From 16b3ca3715a48f3226a8e9f51e28de75ce7f6734 Mon Sep 17 00:00:00 2001 From: Ken Sternberg Date: Fri, 15 Mar 2024 15:21:51 -0700 Subject: [PATCH] web: add command palette Adds [Ninja Keys](https://github.com/ssleptsov/ninja-keys) (MIT License) to the Admin Interface. This is a trivial demo. Start the UI and begin by pressing CMD-K or CTRL-K in the Admin Interface. - Because a lot of the Create and Update operations are accessible as activations-on-modals rather than navigable components in their own right, we don't have a way to encode commands like "Start the Application Wizard" or "Add a new Policy." - Our search isn't very quick, so "Edit Application Foo" would have intolerable delays while we looked up a list of applications that could be edited. - The `icon` feature is relatively difficult to exploit because it's a web component and its inner styles are inacessible. - There seem to be cases where the modal-popup and charts conflict. If we want to move forward with this, we have the challenge of finding activation means for the various Create and Edit features, and whether or not Search can be meaningfully integrated into the results. It would also be nifty if the User and Admin palettes treated each other as peers; you could just go "CMD-K My User Page" and it would just *take* you there, and "CMD-K Admin Applications" to go back, creating an illusion of seamlessness. --- web/package-lock.json | 61 +++++++ web/package.json | 13 +- web/src/admin/AdminInterface/AdminCommands.ts | 172 ++++++++++++++++++ .../admin/AdminInterface/AdminInterface.ts | 3 + 4 files changed, 243 insertions(+), 6 deletions(-) create mode 100644 web/src/admin/AdminInterface/AdminCommands.ts diff --git a/web/package-lock.json b/web/package-lock.json index 124f325095..aaf85d6933 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -39,6 +39,7 @@ "lit": "^3.1.2", "md-front-matter": "^1.0.4", "mermaid": "^10.9.0", + "ninja-keys": "^1.2.2", "rapidoc": "^9.3.4", "showdown": "^2.1.0", "style-mod": "^4.1.2", @@ -3326,6 +3327,33 @@ "@lit/reactive-element": "^1.0.0 || ^2.0.0" } }, + "node_modules/@material/mwc-icon": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@material/mwc-icon/-/mwc-icon-0.25.3.tgz", + "integrity": "sha512-36076AWZIRSr8qYOLjuDDkxej/HA0XAosrj7TS1ZeLlUBnLUtbDtvc1S7KSa0hqez7ouzOqGaWK24yoNnTa2OA==", + "dependencies": { + "lit": "^2.0.0", + "tslib": "^2.0.1" + } + }, + "node_modules/@material/mwc-icon/node_modules/@lit/reactive-element": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.6.3.tgz", + "integrity": "sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ==", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.0.0" + } + }, + "node_modules/@material/mwc-icon/node_modules/lit": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/lit/-/lit-2.8.0.tgz", + "integrity": "sha512-4Sc3OFX9QHOJaHbmTMk28SYgVxLN3ePDjg7hofEft2zWlehFL3LiAuapWc4U/kYwMYJSh2hTCPZ6/LIC7ii0MA==", + "dependencies": { + "@lit/reactive-element": "^1.6.0", + "lit-element": "^3.3.0", + "lit-html": "^2.8.0" + } + }, "node_modules/@mdx-js/react": { "version": "2.3.0", "dev": true, @@ -11381,6 +11409,11 @@ "dev": true, "license": "ISC" }, + "node_modules/hotkeys-js": { + "version": "3.8.7", + "resolved": "https://registry.npmjs.org/hotkeys-js/-/hotkeys-js-3.8.7.tgz", + "integrity": "sha512-ckAx3EkUr5XjDwjEHDorHxRO2Kb7z6Z2Sxul4MbBkN8Nho7XDslQsgMJT+CiJ5Z4TgRxxvKHEpuLE3imzqy4Lg==" + }, "node_modules/http-errors": { "version": "2.0.0", "dev": true, @@ -13640,6 +13673,34 @@ "dev": true, "license": "MIT" }, + "node_modules/ninja-keys": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/ninja-keys/-/ninja-keys-1.2.2.tgz", + "integrity": "sha512-ylo8jzKowi3XBHkgHRjBJaKQkl32WRLr7kRiA0ajiku11vHRDJ2xANtTScR5C7XlDwKEOYvUPesCKacUeeLAYw==", + "dependencies": { + "@material/mwc-icon": "0.25.3", + "hotkeys-js": "3.8.7", + "lit": "2.2.6" + } + }, + "node_modules/ninja-keys/node_modules/@lit/reactive-element": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.6.3.tgz", + "integrity": "sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ==", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.0.0" + } + }, + "node_modules/ninja-keys/node_modules/lit": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/lit/-/lit-2.2.6.tgz", + "integrity": "sha512-K2vkeGABfSJSfkhqHy86ujchJs3NR9nW1bEEiV+bXDkbiQ60Tv5GUausYN2mXigZn8lC1qXuc46ArQRKYmumZw==", + "dependencies": { + "@lit/reactive-element": "^1.3.0", + "lit-element": "^3.2.0", + "lit-html": "^2.2.0" + } + }, "node_modules/node-abi": { "version": "3.56.0", "license": "MIT", diff --git a/web/package.json b/web/package.json index ed109e88d0..f4237f15c5 100644 --- a/web/package.json +++ b/web/package.json @@ -14,8 +14,8 @@ "build": "run-s build-locales esbuild:build", "build-proxy": "run-s build-locales esbuild:build-proxy", "watch": "run-s build-locales esbuild:watch", - "lint": "eslint . --max-warnings 0 --fix", - "lint:precommit": "node scripts/eslint-precommit.mjs", + "lint": "cross-env NODE_OPTIONS='--max_old_space_size=8192' eslint . --max-warnings 0 --fix", + "lint:precommit": "cross-env NODE_OPTIONS='--max_old_space_size=8192' node scripts/eslint-precommit.mjs", "lint:spelling": "node scripts/check-spelling.mjs", "lit-analyse": "lit-analyzer src", "precommit": "npm-run-all --parallel tsc lit-analyse lint:spelling --sequential lint:precommit prettier", @@ -40,9 +40,9 @@ "@fortawesome/fontawesome-free": "^6.5.1", "@goauthentik/api": "^2024.2.2-1709583949", "@lit-labs/task": "^3.1.0", - "@lit/reactive-element": "^2.0.4", "@lit/context": "^1.1.0", "@lit/localize": "^0.12.1", + "@lit/reactive-element": "^2.0.4", "@open-wc/lit-helpers": "^0.7.0", "@patternfly/elements": "^2.4.0", "@patternfly/patternfly": "^4.224.2", @@ -60,6 +60,7 @@ "lit": "^3.1.2", "md-front-matter": "^1.0.4", "mermaid": "^10.9.0", + "ninja-keys": "^1.2.2", "rapidoc": "^9.3.4", "showdown": "^2.1.0", "style-mod": "^4.1.2", @@ -79,6 +80,7 @@ "@hcaptcha/types": "^1.0.3", "@jeysal/storybook-addon-css-user-preferences": "^0.2.0", "@lit/localize-tools": "^0.7.2", + "@rollup/plugin-replace": "^5.0.5", "@spotlightjs/spotlight": "^1.2.12", "@storybook/addon-essentials": "^7.6.17", "@storybook/addon-links": "^7.6.17", @@ -95,9 +97,6 @@ "@types/showdown": "^2.0.6", "@typescript-eslint/eslint-plugin": "^7.2.0", "@typescript-eslint/parser": "^7.2.0", - "@rollup/plugin-replace": "^5.0.5", - "rollup-plugin-modify": "^3.0.0", - "rollup-plugin-postcss-lit": "^2.1.0", "babel-plugin-macros": "^3.1.0", "babel-plugin-tsconfig-paths": "^1.0.3", "chokidar": "^3.6.0", @@ -117,6 +116,8 @@ "pseudolocale": "^2.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "rollup-plugin-modify": "^3.0.0", + "rollup-plugin-postcss-lit": "^2.1.0", "storybook": "^7.6.17", "storybook-addon-mock": "^4.3.0", "ts-lit-plugin": "^2.0.2", diff --git a/web/src/admin/AdminInterface/AdminCommands.ts b/web/src/admin/AdminInterface/AdminCommands.ts new file mode 100644 index 0000000000..733117fd5a --- /dev/null +++ b/web/src/admin/AdminInterface/AdminCommands.ts @@ -0,0 +1,172 @@ +import { navigate } from "@goauthentik/elements/router/RouterOutlet"; +import { INinjaAction } from "ninja-keys/dist/interfaces/ininja-action.js"; + +import { msg } from "@lit/localize"; + +export const adminCommands: INinjaAction[] = [ + { + id: msg("Overview"), + title: msg("Dashboard"), + handler: () => navigate("/administration/overview"), + section: msg("Dashboards"), + }, + { + handler: () => navigate("/administration/dashboard/users"), + id: msg("User Statistics"), + title: msg("User Statistics"), + icon: '', + section: msg("Dashboards"), + }, + { + handler: () => navigate("/administration/system-tasks"), + id: msg("System Tasks"), + title: msg("System Tasks"), + section: msg("Dashboards"), + }, + { + handler: () => navigate("/core/applications"), + id: msg("Applications"), + title: msg("Applications"), + section: msg("Applications"), + }, + { + handler: () => navigate("/core/providers"), + id: msg("Providers"), + title: msg("Providers"), + section: msg("Applications"), + }, + { + handler: () => navigate("/outpost/outposts"), + id: msg("Outposts"), + title: msg("Outposts"), + section: msg("Applications"), + }, + { + handler: () => navigate("/events/log"), + id: msg("Logs"), + title: msg("Logs"), + section: msg("Events"), + }, + { + handler: () => navigate("/events/rules"), + id: msg("Notification Rules"), + title: msg("Notification Rules"), + section: msg("Events"), + }, + { + handler: () => navigate("/events/transports"), + id: msg("Notification Transports"), + title: msg("Notification Transports"), + section: msg("Events"), + }, + + { + handler: () => navigate("/policy/policies"), + id: msg("Policies"), + title: msg("Policies"), + section: msg("Customization"), + }, + { + handler: () => navigate("/core/property-mappings"), + id: msg("Property Mappings"), + title: msg("Property Mappings"), + section: msg("Customization"), + }, + { + handler: () => navigate("/blueprints/instances"), + id: msg("Blueprints"), + title: msg("Blueprints"), + section: msg("Customization"), + }, + { + handler: () => navigate("/policy/reputation"), + id: msg("Reputation scores"), + title: msg("Reputation scores"), + section: msg("Customization"), + }, + { + handler: () => navigate("/flow/flows"), + id: msg("Flows"), + title: msg("Flows"), + section: msg("Flows"), + }, + { + handler: () => navigate("/flow/stages"), + id: msg("Stages"), + title: msg("Stages"), + section: msg("Flows"), + }, + { + handler: () => navigate("/flow/stages/prompts"), + id: msg("Prompts"), + title: msg("Prompts"), + section: msg("Flows"), + }, + + { + handler: () => navigate("/identity/users"), + id: msg("Users"), + title: msg("Users"), + section: msg("Directory"), + }, + { + handler: () => navigate("/identity/groups"), + id: msg("Groups"), + title: msg("Groups"), + section: msg("Directory"), + }, + { + handler: () => navigate("/identity/roles"), + id: msg("Roles"), + title: msg("Roles"), + section: msg("Directory"), + }, + { + handler: () => navigate("/core/sources"), + id: msg("Federation and Social login"), + title: msg("Federation and Social login"), + section: msg("Directory"), + }, + { + handler: () => navigate("/core/tokens"), + id: msg("Tokens and App passwords"), + title: msg("Tokens and App passwords"), + section: msg("Directory"), + }, + { + handler: () => navigate("/flow/stages/invitations"), + id: msg("Invitations"), + title: msg("Invitations"), + section: msg("Directory"), + }, + + { + handler: () => navigate("/core/brands"), + id: msg("Brands"), + title: msg("Brands"), + section: msg("System"), + }, + { + handler: () => navigate("/crypto/certificates"), + id: msg("Certificates"), + title: msg("Certificates"), + section: msg("System"), + }, + { + handler: () => navigate("/outpost/integrations"), + id: msg("Outpost Integrations"), + title: msg("Outpost Integrations"), + section: msg("System"), + }, + { + handler: () => navigate("/admin/settings"), + id: msg("Settings"), + title: msg("Settings"), + section: msg("System"), + }, + { + handler: () => window.location.assign("/if/user/"), + id: msg("User interface"), + title: msg("Go to my User page"), + }, +]; diff --git a/web/src/admin/AdminInterface/AdminInterface.ts b/web/src/admin/AdminInterface/AdminInterface.ts index dab187f8d9..a25fdfa71f 100644 --- a/web/src/admin/AdminInterface/AdminInterface.ts +++ b/web/src/admin/AdminInterface/AdminInterface.ts @@ -18,6 +18,7 @@ import { getURLParam, updateURLParams } from "@goauthentik/elements/router/Route import "@goauthentik/elements/router/RouterOutlet"; import "@goauthentik/elements/sidebar/Sidebar"; import "@goauthentik/elements/sidebar/SidebarItem"; +import "ninja-keys"; import { CSSResult, TemplateResult, css, html } from "lit"; import { customElement, property, state } from "lit/decorators.js"; @@ -30,6 +31,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { AdminApi, SessionUser, UiThemeEnum, Version } from "@goauthentik/api"; +import { adminCommands } from "./AdminCommands"; import "./AdminSidebar"; @customElement("ak-interface-admin") @@ -117,6 +119,7 @@ export class AdminInterface extends EnterpriseAwareInterface { }; return html` +