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.
This commit is contained in:
61
web/package-lock.json
generated
61
web/package-lock.json
generated
@ -39,6 +39,7 @@
|
|||||||
"lit": "^3.1.2",
|
"lit": "^3.1.2",
|
||||||
"md-front-matter": "^1.0.4",
|
"md-front-matter": "^1.0.4",
|
||||||
"mermaid": "^10.9.0",
|
"mermaid": "^10.9.0",
|
||||||
|
"ninja-keys": "^1.2.2",
|
||||||
"rapidoc": "^9.3.4",
|
"rapidoc": "^9.3.4",
|
||||||
"showdown": "^2.1.0",
|
"showdown": "^2.1.0",
|
||||||
"style-mod": "^4.1.2",
|
"style-mod": "^4.1.2",
|
||||||
@ -3326,6 +3327,33 @@
|
|||||||
"@lit/reactive-element": "^1.0.0 || ^2.0.0"
|
"@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": {
|
"node_modules/@mdx-js/react": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -11381,6 +11409,11 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"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": {
|
"node_modules/http-errors": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -13640,6 +13673,34 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/node-abi": {
|
||||||
"version": "3.56.0",
|
"version": "3.56.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@ -14,8 +14,8 @@
|
|||||||
"build": "run-s build-locales esbuild:build",
|
"build": "run-s build-locales esbuild:build",
|
||||||
"build-proxy": "run-s build-locales esbuild:build-proxy",
|
"build-proxy": "run-s build-locales esbuild:build-proxy",
|
||||||
"watch": "run-s build-locales esbuild:watch",
|
"watch": "run-s build-locales esbuild:watch",
|
||||||
"lint": "eslint . --max-warnings 0 --fix",
|
"lint": "cross-env NODE_OPTIONS='--max_old_space_size=8192' eslint . --max-warnings 0 --fix",
|
||||||
"lint:precommit": "node scripts/eslint-precommit.mjs",
|
"lint:precommit": "cross-env NODE_OPTIONS='--max_old_space_size=8192' node scripts/eslint-precommit.mjs",
|
||||||
"lint:spelling": "node scripts/check-spelling.mjs",
|
"lint:spelling": "node scripts/check-spelling.mjs",
|
||||||
"lit-analyse": "lit-analyzer src",
|
"lit-analyse": "lit-analyzer src",
|
||||||
"precommit": "npm-run-all --parallel tsc lit-analyse lint:spelling --sequential lint:precommit prettier",
|
"precommit": "npm-run-all --parallel tsc lit-analyse lint:spelling --sequential lint:precommit prettier",
|
||||||
@ -40,9 +40,9 @@
|
|||||||
"@fortawesome/fontawesome-free": "^6.5.1",
|
"@fortawesome/fontawesome-free": "^6.5.1",
|
||||||
"@goauthentik/api": "^2024.2.2-1709583949",
|
"@goauthentik/api": "^2024.2.2-1709583949",
|
||||||
"@lit-labs/task": "^3.1.0",
|
"@lit-labs/task": "^3.1.0",
|
||||||
"@lit/reactive-element": "^2.0.4",
|
|
||||||
"@lit/context": "^1.1.0",
|
"@lit/context": "^1.1.0",
|
||||||
"@lit/localize": "^0.12.1",
|
"@lit/localize": "^0.12.1",
|
||||||
|
"@lit/reactive-element": "^2.0.4",
|
||||||
"@open-wc/lit-helpers": "^0.7.0",
|
"@open-wc/lit-helpers": "^0.7.0",
|
||||||
"@patternfly/elements": "^2.4.0",
|
"@patternfly/elements": "^2.4.0",
|
||||||
"@patternfly/patternfly": "^4.224.2",
|
"@patternfly/patternfly": "^4.224.2",
|
||||||
@ -60,6 +60,7 @@
|
|||||||
"lit": "^3.1.2",
|
"lit": "^3.1.2",
|
||||||
"md-front-matter": "^1.0.4",
|
"md-front-matter": "^1.0.4",
|
||||||
"mermaid": "^10.9.0",
|
"mermaid": "^10.9.0",
|
||||||
|
"ninja-keys": "^1.2.2",
|
||||||
"rapidoc": "^9.3.4",
|
"rapidoc": "^9.3.4",
|
||||||
"showdown": "^2.1.0",
|
"showdown": "^2.1.0",
|
||||||
"style-mod": "^4.1.2",
|
"style-mod": "^4.1.2",
|
||||||
@ -79,6 +80,7 @@
|
|||||||
"@hcaptcha/types": "^1.0.3",
|
"@hcaptcha/types": "^1.0.3",
|
||||||
"@jeysal/storybook-addon-css-user-preferences": "^0.2.0",
|
"@jeysal/storybook-addon-css-user-preferences": "^0.2.0",
|
||||||
"@lit/localize-tools": "^0.7.2",
|
"@lit/localize-tools": "^0.7.2",
|
||||||
|
"@rollup/plugin-replace": "^5.0.5",
|
||||||
"@spotlightjs/spotlight": "^1.2.12",
|
"@spotlightjs/spotlight": "^1.2.12",
|
||||||
"@storybook/addon-essentials": "^7.6.17",
|
"@storybook/addon-essentials": "^7.6.17",
|
||||||
"@storybook/addon-links": "^7.6.17",
|
"@storybook/addon-links": "^7.6.17",
|
||||||
@ -95,9 +97,6 @@
|
|||||||
"@types/showdown": "^2.0.6",
|
"@types/showdown": "^2.0.6",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||||
"@typescript-eslint/parser": "^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-macros": "^3.1.0",
|
||||||
"babel-plugin-tsconfig-paths": "^1.0.3",
|
"babel-plugin-tsconfig-paths": "^1.0.3",
|
||||||
"chokidar": "^3.6.0",
|
"chokidar": "^3.6.0",
|
||||||
@ -117,6 +116,8 @@
|
|||||||
"pseudolocale": "^2.0.0",
|
"pseudolocale": "^2.0.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^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": "^7.6.17",
|
||||||
"storybook-addon-mock": "^4.3.0",
|
"storybook-addon-mock": "^4.3.0",
|
||||||
"ts-lit-plugin": "^2.0.2",
|
"ts-lit-plugin": "^2.0.2",
|
||||||
|
|||||||
172
web/src/admin/AdminInterface/AdminCommands.ts
Normal file
172
web/src/admin/AdminInterface/AdminCommands.ts
Normal file
@ -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: '<i class="pf-icon pf-icon-user"></i>',
|
||||||
|
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"),
|
||||||
|
},
|
||||||
|
];
|
||||||
@ -18,6 +18,7 @@ import { getURLParam, updateURLParams } from "@goauthentik/elements/router/Route
|
|||||||
import "@goauthentik/elements/router/RouterOutlet";
|
import "@goauthentik/elements/router/RouterOutlet";
|
||||||
import "@goauthentik/elements/sidebar/Sidebar";
|
import "@goauthentik/elements/sidebar/Sidebar";
|
||||||
import "@goauthentik/elements/sidebar/SidebarItem";
|
import "@goauthentik/elements/sidebar/SidebarItem";
|
||||||
|
import "ninja-keys";
|
||||||
|
|
||||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators.js";
|
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 { AdminApi, SessionUser, UiThemeEnum, Version } from "@goauthentik/api";
|
||||||
|
|
||||||
|
import { adminCommands } from "./AdminCommands";
|
||||||
import "./AdminSidebar";
|
import "./AdminSidebar";
|
||||||
|
|
||||||
@customElement("ak-interface-admin")
|
@customElement("ak-interface-admin")
|
||||||
@ -117,6 +119,7 @@ export class AdminInterface extends EnterpriseAwareInterface {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return html` <ak-locale-context>
|
return html` <ak-locale-context>
|
||||||
|
<ninja-keys .data=${adminCommands} noAutoLoadMdicons></ninja-keys>
|
||||||
<div class="pf-c-page">
|
<div class="pf-c-page">
|
||||||
<ak-admin-sidebar
|
<ak-admin-sidebar
|
||||||
class="pf-c-page__sidebar ${classMap(sidebarClasses)}"
|
class="pf-c-page__sidebar ${classMap(sidebarClasses)}"
|
||||||
|
|||||||
Reference in New Issue
Block a user