diff --git a/src/components/settings/Users/AddUser.vue b/src/components/settings/Users/AddUser.vue new file mode 100644 index 00000000000..5f38420b888 --- /dev/null +++ b/src/components/settings/Users/AddUser.vue @@ -0,0 +1,94 @@ + + + diff --git a/src/components/settings/Users/EditUser.vue b/src/components/settings/Users/EditUser.vue new file mode 100644 index 00000000000..bb6307664b3 --- /dev/null +++ b/src/components/settings/Users/EditUser.vue @@ -0,0 +1,205 @@ + + + diff --git a/src/components/settings/Users/Users.vue b/src/components/settings/Users/Users.vue new file mode 100644 index 00000000000..1be9e84085b --- /dev/null +++ b/src/components/settings/Users/Users.vue @@ -0,0 +1,153 @@ + + + + + diff --git a/src/components/settings/Users/routes.js b/src/components/settings/Users/routes.js new file mode 100644 index 00000000000..6d35174558a --- /dev/null +++ b/src/components/settings/Users/routes.js @@ -0,0 +1,29 @@ +import { h } from "vue"; +import { RouterView } from "vue-router"; + +// Needed for settings enter/leave CSS animation +const AnimatedRouterView = () => h("div", [ h(RouterView) ]); +AnimatedRouterView.displayName = "AnimatedRouterView"; + +export default { + path: "users", + component: AnimatedRouterView, + children: [ + { + path: "", + name: "settings.users", + component: () => import("./Users.vue") + }, + { + path: "add", + name: "settings.users.add", + component: () => import("./AddUser.vue") + }, + { + path: "edit/:id", + name: "settings.users.edit", + props: true, + component: () => import("./EditUser.vue") + }, + ] +}; diff --git a/src/icon.js b/src/icon.js index 7bdfe1ca02f..b404827832a 100644 --- a/src/icon.js +++ b/src/icon.js @@ -50,6 +50,8 @@ import { faInfoCircle, faClone, faCertificate, + faUserSlash, + faUserCheck, } from "@fortawesome/free-solid-svg-icons"; library.add( @@ -97,6 +99,8 @@ library.add( faInfoCircle, faClone, faCertificate, + faUserSlash, + faUserCheck, ); export { FontAwesomeIcon }; diff --git a/src/lang/en.json b/src/lang/en.json index 772e572997d..56e4ed70f95 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -796,8 +796,8 @@ "noGroupMonitorMsg": "Not Available. Create a Group Monitor First.", "Close": "Close", "Request Body": "Request Body", - "wayToGetFlashDutyKey":"You can go to Channel -> (Select a Channel) -> Integrations -> Add a new integration' page, add a 'Custom Event' to get a push address, copy the Integration Key in the address. For more information, please visit", - "FlashDuty Severity":"Severity", + "wayToGetFlashDutyKey": "You can go to Channel -> (Select a Channel) -> Integrations -> Add a new integration' page, add a 'Custom Event' to get a push address, copy the Integration Key in the address. For more information, please visit", + "FlashDuty Severity": "Severity", "nostrRelays": "Nostr relays", "nostrRelaysHelp": "One relay URL per line", "nostrSender": "Sender Private Key (nsec)", @@ -806,5 +806,12 @@ "showCertificateExpiry": "Show Certificate Expiry", "noOrBadCertificate": "No/Bad Certificate", "gamedigGuessPort": "Gamedig: Guess Port", - "gamedigGuessPortDescription": "The port used by Valve Server Query Protocol may be different from the client port. Try this if the monitor cannot connect to your server." -} + "gamedigGuessPortDescription": "The port used by Valve Server Query Protocol may be different from the client port. Try this if the monitor cannot connect to your server.", + "Users": "Users", + "Add New User": "Add New User", + "confirmDisableUserMsg": "Are you sure you want to disable this user? The user will not be able to login anymore.", + "Create an admin account": "Create an admin account", + "Identity": "Identity", + "Update Username": "Update Username", + "Permissions": "Permissions" +} \ No newline at end of file diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index d6549a3cb86..1f533aab18e 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -126,6 +126,13 @@ export default { security: { title: this.$t("Security"), }, + users: { + title: this.$t("Users"), + children: { + add: { title: this.$t("Add") }, + edit: { title: this.$t("Edit") } + }, + }, "api-keys": { title: this.$t("API Keys") }, diff --git a/src/router.js b/src/router.js index a8644805e86..f52ecaad8f2 100644 --- a/src/router.js +++ b/src/router.js @@ -26,6 +26,7 @@ import General from "./components/settings/General.vue"; const Notifications = () => import("./components/settings/Notifications.vue"); import ReverseProxy from "./components/settings/ReverseProxy.vue"; import Tags from "./components/settings/Tags.vue"; +import usersSettingsRoutes from "./components/settings/Users/routes.js"; import MonitorHistory from "./components/settings/MonitorHistory.vue"; const Security = () => import("./components/settings/Security.vue"); import Proxies from "./components/settings/Proxies.vue"; @@ -117,6 +118,7 @@ const routes = [ path: "security", component: Security, }, + usersSettingsRoutes, { path: "api-keys", component: APIKeys, diff --git a/src/util-frontend.js b/src/util-frontend.js index 4b85fa34683..ea003a0ae8c 100644 --- a/src/util-frontend.js +++ b/src/util-frontend.js @@ -139,3 +139,22 @@ export function colorOptions(self) { color: "#DB2777" }, ]; } + +/** + * Get debounced function + * @returns {function} debounced function + */ +export function Debounce() { + let timeout = null; + + /** + * exec callback function after delay if no new call to function happens + * @param {function} callback function to execute after delay + * @param {number} [delay=100] delay before execute the callback if no new call to function happens + * @returns {void} + */ + return function (callback, delay = 100) { + clearTimeout(timeout); + timeout = setTimeout(() => callback(), delay); + }; +}