Compare commits
3
Commits
b8f9430827
...
abf00ac401
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abf00ac401 | ||
|
|
fcd4d4743b | ||
|
|
fb152bd023 |
@@ -4,5 +4,4 @@
|
||||
session.use_strict_mode=1
|
||||
```
|
||||
|
||||
https://github.com/ldaptools/ldaptools
|
||||
|
||||
https://bulma.io/
|
||||
@@ -6,7 +6,7 @@
|
||||
"name": "portal-vue",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "7.3.1",
|
||||
"bootstrap": "5.3.8",
|
||||
"bulma": "^1.0.4",
|
||||
"vue": "^3.5.40",
|
||||
"vue-i18n": "^11.4.10",
|
||||
"vue-multiselect": "^3.5.0",
|
||||
@@ -150,7 +150,31 @@
|
||||
|
||||
"@oxc-project/types": ["@oxc-project/types@0.148.0", "", {}, "sha512-Nm4s/jB+4FpFsPhWGEC4h7rzksesmtnMXomo6rCMcg/b8zLQuOziRgkCS1fxDCXOlJB/6Q8oABOZ/OP6RIPj9A=="],
|
||||
|
||||
"@popperjs/core": ["@popperjs/core@2.11.8", "", {}, "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="],
|
||||
"@parcel/watcher": ["@parcel/watcher@2.6.0", "", { "dependencies": { "detect-libc": "^2.0.3", "is-glob": "^4.0.3", "node-addon-api": "^7.0.0", "picomatch": "^4.0.4" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.6.0", "@parcel/watcher-darwin-arm64": "2.6.0", "@parcel/watcher-darwin-x64": "2.6.0", "@parcel/watcher-freebsd-x64": "2.6.0", "@parcel/watcher-linux-arm-glibc": "2.6.0", "@parcel/watcher-linux-arm-musl": "2.6.0", "@parcel/watcher-linux-arm64-glibc": "2.6.0", "@parcel/watcher-linux-arm64-musl": "2.6.0", "@parcel/watcher-linux-x64-glibc": "2.6.0", "@parcel/watcher-linux-x64-musl": "2.6.0", "@parcel/watcher-win32-arm64": "2.6.0", "@parcel/watcher-win32-x64": "2.6.0" } }, "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w=="],
|
||||
|
||||
"@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.6.0", "", { "os": "android", "cpu": "arm64" }, "sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA=="],
|
||||
|
||||
"@parcel/watcher-darwin-arm64": ["@parcel/watcher-darwin-arm64@2.6.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw=="],
|
||||
|
||||
"@parcel/watcher-darwin-x64": ["@parcel/watcher-darwin-x64@2.6.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw=="],
|
||||
|
||||
"@parcel/watcher-freebsd-x64": ["@parcel/watcher-freebsd-x64@2.6.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ=="],
|
||||
|
||||
"@parcel/watcher-linux-arm-glibc": ["@parcel/watcher-linux-arm-glibc@2.6.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg=="],
|
||||
|
||||
"@parcel/watcher-linux-arm-musl": ["@parcel/watcher-linux-arm-musl@2.6.0", "", { "os": "linux", "cpu": "arm" }, "sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw=="],
|
||||
|
||||
"@parcel/watcher-linux-arm64-glibc": ["@parcel/watcher-linux-arm64-glibc@2.6.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g=="],
|
||||
|
||||
"@parcel/watcher-linux-arm64-musl": ["@parcel/watcher-linux-arm64-musl@2.6.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA=="],
|
||||
|
||||
"@parcel/watcher-linux-x64-glibc": ["@parcel/watcher-linux-x64-glibc@2.6.0", "", { "os": "linux", "cpu": "x64" }, "sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A=="],
|
||||
|
||||
"@parcel/watcher-linux-x64-musl": ["@parcel/watcher-linux-x64-musl@2.6.0", "", { "os": "linux", "cpu": "x64" }, "sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw=="],
|
||||
|
||||
"@parcel/watcher-win32-arm64": ["@parcel/watcher-win32-arm64@2.6.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ=="],
|
||||
|
||||
"@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.6.0", "", { "os": "win32", "cpu": "x64" }, "sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A=="],
|
||||
|
||||
"@rolldown/binding-android-arm-eabi": ["@rolldown/binding-android-arm-eabi@1.2.7", "", { "os": "android", "cpu": "arm" }, "sha512-EypzgnYCwyVY4NDHKzGmNJT5b+XaQEBniHxsMdeIQLB/tcCzZnhqrzHpZFbX9iaxx+5RiB8caATBtfvZP7zVxQ=="],
|
||||
|
||||
@@ -250,12 +274,12 @@
|
||||
|
||||
"birpc": ["birpc@2.9.0", "", {}, "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw=="],
|
||||
|
||||
"bootstrap": ["bootstrap@5.3.8", "", { "peerDependencies": { "@popperjs/core": "^2.11.8" } }, "sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg=="],
|
||||
|
||||
"brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="],
|
||||
|
||||
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
||||
|
||||
"bulma": ["bulma@1.0.4", "", {}, "sha512-Ffb6YGXDiZYX3cqvSbHWqQ8+LkX6tVoTcZuVB3lm93sbAVXlO0D6QlOTMnV6g18gILpAXqkG2z9hf9z4hCjz2g=="],
|
||||
|
||||
"cacheable": ["cacheable@2.5.0", "", { "dependencies": { "@cacheable/memory": "^2.2.0", "@cacheable/utils": "^2.5.0", "hookified": "^1.15.0", "keyv": "^5.6.0", "qified": "^0.10.1" } }, "sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g=="],
|
||||
|
||||
"chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
||||
@@ -352,6 +376,8 @@
|
||||
|
||||
"ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
|
||||
|
||||
"immutable": ["immutable@5.1.9", "", {}, "sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg=="],
|
||||
|
||||
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
|
||||
|
||||
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
||||
@@ -420,6 +446,8 @@
|
||||
|
||||
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
|
||||
|
||||
"node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="],
|
||||
|
||||
"nostics": ["nostics@1.2.0", "", {}, "sha512-FGqEfhQjrvo1lL8KFifdTQiNwwQHJxC1jtYE1Rc54qF/jxONUNL+kC9gS1krX8Q65PgrQ5fCqH/I4NhWBvdSqg=="],
|
||||
|
||||
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
|
||||
@@ -464,6 +492,8 @@
|
||||
|
||||
"rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="],
|
||||
|
||||
"sass": ["sass@1.104.0", "", { "dependencies": { "chokidar": "^5.0.0", "immutable": "^5.1.5", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-btHMApW2bgolvClhRW8AlQJzgI9lUB3pPSofBQQT+E46GWvf9o0TVQ13SYv5riWZVFyPN+JNz3TKW9XhBlc10w=="],
|
||||
|
||||
"scule": ["scule@1.3.0", "", {}, "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g=="],
|
||||
|
||||
"semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
||||
|
||||
+2
-1
@@ -4,7 +4,8 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>NASLOV</title>
|
||||
<title>CMMS</title>
|
||||
<link rel="icon" type="image/x-icon" href="/vue/favicon.ico">
|
||||
|
||||
<script defer type="module" src="/vue/main.js"></script>
|
||||
</head>
|
||||
|
||||
+3
-2
@@ -4,11 +4,12 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "vite build && cp -R php dist/php && cp -R vendor dist/vendor",
|
||||
"serve": "concurrently \"vite\" \"php -S localhost:8000\" \"mailpit\" \"caddy run --config Caddyfile\""
|
||||
"serve": "concurrently \"vite\" \"php -S localhost:8000\" \"mailpit\" \"caddy run --config Caddyfile\"",
|
||||
"php": "concurrently \"php -t dist -S localhost:8000\" \"mailpit\" \"caddy reverse-proxy -t localhost:8000\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "7.3.1",
|
||||
"bootstrap": "5.3.8",
|
||||
"bulma": "^1.0.4",
|
||||
"vue": "^3.5.40",
|
||||
"vue-i18n": "^11.4.10",
|
||||
"vue-multiselect": "^3.5.0",
|
||||
|
||||
@@ -11,7 +11,8 @@ try {
|
||||
$conn->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
||||
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
|
||||
} catch(PDOException $e) {
|
||||
echo "Connection failed: " . $e->getMessage();
|
||||
echo json_encode(["error" => "error.connect.faild"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+11
-24
@@ -12,7 +12,7 @@ $nimrodLDAP = new Connection([
|
||||
]);
|
||||
|
||||
if (!isset($_POST['uporabnik']) || !isset($_POST['geslo'])) {
|
||||
echo json_encode(["napaka" => "manjkajo podatki"]);
|
||||
echo json_encode(["error" => "error.user.login.missing"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -22,17 +22,22 @@ $geslo = $_POST['geslo'];
|
||||
try {
|
||||
$nimrodLDAP->connect();
|
||||
} catch (Exception $e) {
|
||||
echo 'napaka pri povezavi na LDap';
|
||||
echo $e;
|
||||
echo json_encode(["error" => "error.user.login.connect"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$LUser = $nimrodLDAP->query()->findBy('samaccountname', $username);
|
||||
if (empty($LUser)) {
|
||||
echo json_encode(["napaka" => "uporabnik ni najden"]);
|
||||
echo json_encode(["error" => "error.user.login.notFound"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$emailUserja = $LUser['userprincipalname'][0];
|
||||
$user = $LUser['distinguishedname'][0];
|
||||
if (!$nimrodLDAP->auth()->attempt($user, $geslo, $stayAuthenticated = true)) {
|
||||
echo json_encode(["error" => "error.user.login.wrongPassword"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$vGrupah = $LUser['memberof'];
|
||||
$dGrupe = [
|
||||
@@ -44,14 +49,7 @@ $razlikaGrup = array_intersect(
|
||||
array_map('strtolower', $dGrupe)
|
||||
);
|
||||
if (count($razlikaGrup) <= 0) {
|
||||
echo json_encode(["napaka" => "nimaš pravic skupinskih"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$emailUserja = $LUser['userprincipalname'][0];
|
||||
$user = $LUser['distinguishedname'][0];
|
||||
if (!$nimrodLDAP->auth()->attempt($user, $geslo, $stayAuthenticated = true)) {
|
||||
echo json_encode(["napaka" => "napacno geslo"]);
|
||||
echo json_encode(["error" => "error.user.login.groupRight"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -78,15 +76,4 @@ if ($obstojeciUporabnik) {
|
||||
$_SESSION['displayname'] = $uporabnik;
|
||||
$_SESSION['email'] = $email;
|
||||
|
||||
echo json_encode(["res" => "uspesno"]);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
echo json_encode(["res" => "res.user.login.true"]);
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
<?php
|
||||
session_destroy();
|
||||
echo json_encode(["res" => "res.user.loginout.true"]);
|
||||
Vendored
+53
-5
@@ -38,9 +38,31 @@ declare module 'vue-router/auto-routes' {
|
||||
Record<never, never>,
|
||||
| never
|
||||
>,
|
||||
'/test': RouteRecordInfo<
|
||||
'/test',
|
||||
'/test',
|
||||
'/settings': RouteRecordInfo<
|
||||
'/settings',
|
||||
'/settings',
|
||||
Record<never, never>,
|
||||
Record<never, never>,
|
||||
| '/settings/groups'
|
||||
| '/settings/users'
|
||||
>,
|
||||
'/settings/groups': RouteRecordInfo<
|
||||
'/settings/groups',
|
||||
'/settings/groups',
|
||||
Record<never, never>,
|
||||
Record<never, never>,
|
||||
| never
|
||||
>,
|
||||
'/settings/users': RouteRecordInfo<
|
||||
'/settings/users',
|
||||
'/settings/users',
|
||||
Record<never, never>,
|
||||
Record<never, never>,
|
||||
| never
|
||||
>,
|
||||
'/user_settings': RouteRecordInfo<
|
||||
'/user_settings',
|
||||
'/user_settings',
|
||||
Record<never, never>,
|
||||
Record<never, never>,
|
||||
| never
|
||||
@@ -66,9 +88,35 @@ declare module 'vue-router/auto-routes' {
|
||||
pathParamNames:
|
||||
| never
|
||||
}
|
||||
'vue/routes/test.vue': {
|
||||
'vue/routes/settings.vue': {
|
||||
routes:
|
||||
| '/test'
|
||||
| '/settings'
|
||||
| '/settings/groups'
|
||||
| '/settings/users'
|
||||
views:
|
||||
| 'default'
|
||||
pathParamNames:
|
||||
| never
|
||||
}
|
||||
'vue/routes/settings/groups.vue': {
|
||||
routes:
|
||||
| '/settings/groups'
|
||||
views:
|
||||
| never
|
||||
pathParamNames:
|
||||
| never
|
||||
}
|
||||
'vue/routes/settings/users.vue': {
|
||||
routes:
|
||||
| '/settings/users'
|
||||
views:
|
||||
| never
|
||||
pathParamNames:
|
||||
| never
|
||||
}
|
||||
'vue/routes/user_settings.vue': {
|
||||
routes:
|
||||
| '/user_settings'
|
||||
views:
|
||||
| never
|
||||
pathParamNames:
|
||||
|
||||
@@ -12,6 +12,7 @@ export default defineConfig(() => ({
|
||||
VueRouter({
|
||||
routesFolder: 'vue/routes',
|
||||
importMode: 'sync',
|
||||
exclude: ['vue/routes/**/comp/**'],
|
||||
}),
|
||||
vue(),
|
||||
],
|
||||
|
||||
+9
-6
@@ -1,15 +1,18 @@
|
||||
<template>
|
||||
<LanguageSwitcher />
|
||||
<p>
|
||||
{{ t('app.hello') }}
|
||||
</p>
|
||||
|
||||
<div class="is-flex">
|
||||
<Sidebar />
|
||||
<main class="p-5 is-flex-grow-1">
|
||||
<RouterView />
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import LanguageSwitcher from '@/components/LanguageSwitcher.vue'
|
||||
import { applyTheme } from '@/components/theme';
|
||||
import Sidebar from '@/components/Sidebar.vue';
|
||||
|
||||
applyTheme();
|
||||
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
@@ -1,13 +1,17 @@
|
||||
<template>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown">
|
||||
{{ locale.toUpperCase() }}
|
||||
<div class="dropdown is-hoverable">
|
||||
<div class="dropdown-trigger">
|
||||
<button class="button">
|
||||
<span>{{ locale.toUpperCase() }}</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li v-for="loc in SUPPORT_LOCALES" :key="loc">
|
||||
<a class="dropdown-item" href="#" @click.prevent="setLocale(loc)">{{ loc.toUpperCase() }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="dropdown-menu">
|
||||
<div class="dropdown-content">
|
||||
<button v-for="loc in SUPPORT_LOCALES" :key="loc" @click.prevent="setLocale(loc)" class="dropdown-item">
|
||||
{{ loc.toUpperCase() }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<aside class="menu m-3" :class="{ 'is-collapsed': collapsed }">
|
||||
|
||||
<div class="level">
|
||||
<p class="level-item" v-if="!collapsed">CMMS</p>
|
||||
<div class="level-item">
|
||||
<button class="button" :title="collapsed ? 'Expand menu' : 'Collapse menu'" @click="toggleSidebar">
|
||||
<span class="icon">
|
||||
<i class="fa-solid" :class="collapsed ? 'fa-angles-right' : 'fa-angles-left'"></i>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="menu-list">
|
||||
<li v-for="item in items" :key="item.to">
|
||||
<RouterLink :to="item.to" active-class="is-active" :class="{ 'has-text-centered': collapsed }"
|
||||
:title="collapsed ? item.label : null">
|
||||
<span class="icon">
|
||||
<i class="fa-solid" :class="item.icon"></i>
|
||||
</span>
|
||||
<span v-if="!collapsed"> {{ t(item.label) }}</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
</ul>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { RouterLink } from 'vue-router';
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const collapsed = ref(localStorage.getItem('sidebarCollapsed') === 'true');
|
||||
|
||||
function toggleSidebar() {
|
||||
collapsed.value = !collapsed.value;
|
||||
localStorage.setItem('sidebarCollapsed', collapsed.value);
|
||||
}
|
||||
|
||||
// Example items — replace `to` with real routes as pages are added.
|
||||
const items = [
|
||||
{ label: 'menu.dashboard', icon: 'fa-gauge-high', to: '/' },
|
||||
// { label: 'Assets', icon: 'fa-boxes-stacked', to: '/assets' },
|
||||
// { label: 'Work Orders', icon: 'fa-clipboard-list', to: '/work-orders' },
|
||||
// { label: 'Maintenance', icon: 'fa-screwdriver-wrench', to: '/maintenance' },
|
||||
// { label: 'Reports', icon: 'fa-chart-line', to: '/reports' },
|
||||
{ label: 'menu.userSettings', icon: 'fa-user-gear', to: '/user_settings' },
|
||||
{ label: 'menu.settings', icon: 'fa-gear', to: '/settings' },
|
||||
];
|
||||
</script>
|
||||
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<div class="dropdown is-hoverable">
|
||||
<div class="dropdown-trigger">
|
||||
<button class="button">
|
||||
<span>Barvna tema</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="dropdown-menu">
|
||||
<div class="dropdown-content">
|
||||
<button class="dropdown-item" @click.prevent="setTheme('light')">
|
||||
Svetlo
|
||||
</button>
|
||||
<button class="dropdown-item" @click.prevent="setTheme('dark')">
|
||||
Temno
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { setTheme } from './theme';
|
||||
</script>
|
||||
@@ -0,0 +1,21 @@
|
||||
import { ref } from 'vue';
|
||||
|
||||
|
||||
const theme = ref(localStorage.getItem('theme') || 'auto');
|
||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
|
||||
|
||||
export function applyTheme() {
|
||||
const resolved = theme.value === 'auto' ? (prefersDark.matches ? 'dark' : 'light') : theme.value;
|
||||
document.documentElement.setAttribute('data-theme', resolved);
|
||||
}
|
||||
|
||||
export function setTheme(value) {
|
||||
theme.value = value;
|
||||
localStorage.setItem('theme', value);
|
||||
applyTheme();
|
||||
}
|
||||
|
||||
prefersDark.addEventListener('change', () => {
|
||||
if (theme.value === 'auto') applyTheme();
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
@import 'vue-multiselect/dist/vue-multiselect.css';
|
||||
@import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||
|
||||
@import 'bulma/css/bulma.min.css';
|
||||
|
||||
html {
|
||||
background-color: var(--bulma-scheme-main-ter);
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
--bulma-dropdown-menu-min-width: 4rem;
|
||||
}
|
||||
|
||||
a.dropdown-item,
|
||||
button.dropdown-item {
|
||||
padding-inline-end: 1rem;
|
||||
}
|
||||
|
||||
[data-theme=dark],
|
||||
.theme-dark {
|
||||
--bulma-scheme-main-ter-l: 20%;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 318 B |
@@ -1,4 +1,13 @@
|
||||
{
|
||||
"menu": {
|
||||
"settings": "Settings",
|
||||
"userSettings": "User settings",
|
||||
"dashboard": "Dashboard"
|
||||
},
|
||||
"settings":{
|
||||
"users":"Users",
|
||||
"groups":"Groups"
|
||||
},
|
||||
"common": {
|
||||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
{
|
||||
"menu": {
|
||||
"settings": "Nastavitve",
|
||||
"userSettings": "Uporabniške nastavitve",
|
||||
"dashboard": "Nadzorna plošča"
|
||||
},
|
||||
"common": {
|
||||
"save": "Shrani",
|
||||
"cancel": "Prekliči",
|
||||
|
||||
+1
-5
@@ -3,11 +3,7 @@ import { createRouter, createWebHashHistory } from 'vue-router'
|
||||
import { routes, handleHotUpdate } from 'vue-router/auto-routes'
|
||||
import { i18n, setLocale, initialLocale } from './i18n.js'
|
||||
|
||||
import '@fortawesome/fontawesome-free/css/all.min.css'
|
||||
import 'bootstrap/dist/css/bootstrap.min.css'
|
||||
import 'bootstrap/dist/js/bootstrap.bundle.min.js'
|
||||
import 'vue-multiselect/dist/vue-multiselect.css';
|
||||
|
||||
import './css/all.css'
|
||||
|
||||
import App from './app.vue'
|
||||
|
||||
|
||||
+2
-14
@@ -1,22 +1,10 @@
|
||||
<template>
|
||||
<p>{{ t('app.world') }}</p>
|
||||
<p v-for="value in j">
|
||||
{{ value }}
|
||||
</p>
|
||||
<h1 class="title">{{ t('menu.dashboard') }}</h1>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { useI18n } from 'vue-i18n';
|
||||
const { t } = useI18n();
|
||||
|
||||
const j = ref([]);
|
||||
|
||||
onMounted(async () => {
|
||||
const res = await fetch("/php/notifications.php")
|
||||
j.value = await res.json();
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<h1 class="title">{{ t('menu.settings') }}</h1>
|
||||
<div class="tabs">
|
||||
<ul>
|
||||
<li v-for="i in routes" :class="{ 'is-active': route.path === i.path }">
|
||||
<RouterLink :to="i.path">
|
||||
{{ t(i.title) }}
|
||||
</RouterLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<RouterView />
|
||||
</template>
|
||||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
|
||||
const routes = [
|
||||
{"title": "settings.users", "path": "/settings/users"},
|
||||
{"title": "settings.groups", "path": "/settings/groups"}
|
||||
];
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,8 @@
|
||||
<template>
|
||||
|
||||
</template>
|
||||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
const { t } = useI18n();
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>user</th>
|
||||
<th>email</th>
|
||||
<th>group</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</template>
|
||||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
const { t } = useI18n();
|
||||
|
||||
</script>
|
||||
@@ -1,8 +0,0 @@
|
||||
<template>
|
||||
{{ t('common.save') }}
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const { t } = useI18n()
|
||||
</script>
|
||||
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<h1 class="title">{{ t('menu.userSettings') }}</h1>
|
||||
|
||||
<LanguageSwitcher />
|
||||
<ThemeSwitcher />
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import ThemeSwitcher from '@/components/ThemeSwitcher.vue';
|
||||
import LanguageSwitcher from '@/components/LanguageSwitcher.vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
Reference in New Issue
Block a user