diff --git a/web/rollup.config.mjs b/web/rollup.config.mjs index 49825a29d..db9caf6ee 100644 --- a/web/rollup.config.mjs +++ b/web/rollup.config.mjs @@ -148,7 +148,7 @@ export default [ }, // Admin interface { - input: "./src/admin/AdminInterface/AdminInterface.ts", + input: "./src/admin/AdminInterface.ts", output: [ { format: "es", diff --git a/web/src/admin/AdminInterface/AdminInterface.ts b/web/src/admin/AdminInterface.ts similarity index 50% rename from web/src/admin/AdminInterface/AdminInterface.ts rename to web/src/admin/AdminInterface.ts index 69e07d84e..e59793706 100644 --- a/web/src/admin/AdminInterface/AdminInterface.ts +++ b/web/src/admin/AdminInterface.ts @@ -26,7 +26,6 @@ import { spread } from "@open-wc/lit-helpers"; import { msg, str } from "@lit/localize"; import { CSSResult, TemplateResult, css, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators.js"; -import { classMap } from "lit/directives/class-map.js"; import { map } from "lit/directives/map.js"; import PFButton from "@patternfly/patternfly/components/Button/button.css"; @@ -34,9 +33,14 @@ import PFDrawer from "@patternfly/patternfly/components/Drawer/drawer.css"; import PFPage from "@patternfly/patternfly/components/Page/page.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css"; -import { AdminApi, CoreApi, SessionUser, UiThemeEnum, Version } from "@goauthentik/api"; - -import "./AdminSidebar"; +import { + AdminApi, + CapabilitiesEnum, + CoreApi, + SessionUser, + UiThemeEnum, + Version, +} from "@goauthentik/api"; @customElement("ak-interface-admin") export class AdminInterface extends Interface { @@ -122,26 +126,23 @@ export class AdminInterface extends Interface { } render(): TemplateResult { - const sidebarClasses = { - "pf-m-expanded": this.sidebarOpen, - "pf-m-collapsed": !this.sidebarOpen, - "pf-m-light": this.activeTheme === UiThemeEnum.Light, - }; - - const drawerOpen = this.notificationDrawerOpen || this.apiDrawerOpen; - const drawerClasses = { - "pf-m-expanded": drawerOpen, - "pf-m-collapsed": !drawerOpen, - }; - return html`
- + + ${this.renderSidebarItems()} +
-
+
@@ -176,4 +177,120 @@ export class AdminInterface extends Interface {
`; } + + renderSidebarItems(): TemplateResult { + // The second attribute type is of string[] to help with the 'activeWhen' control, which was + // commonplace and singular enough to merit its own handler. + type SidebarEntry = [ + path: string | null, + label: string, + attributes?: Record | string[] | null, // eslint-disable-line + children?: SidebarEntry[], + ]; + + // prettier-ignore + const sidebarContent: SidebarEntry[] = [ + ["/if/user/", msg("User interface"), { "?isAbsoluteLink": true, "?highlight": true }], + [null, msg("Dashboards"), { "?expanded": true }, [ + ["/administration/overview", msg("Overview")], + ["/administration/dashboard/users", msg("User Statistics")], + ["/administration/system-tasks", msg("System Tasks")]]], + [null, msg("Applications"), null, [ + ["/core/providers", msg("Providers"), [`^/core/providers/(?${ID_REGEX})$`]], + ["/core/applications", msg("Applications"), [`^/core/applications/(?${SLUG_REGEX})$`]], + ["/outpost/outposts", msg("Outposts")]]], + [null, msg("Events"), null, [ + ["/events/log", msg("Logs"), [`^/events/log/(?${UUID_REGEX})$`]], + ["/events/rules", msg("Notification Rules")], + ["/events/transports", msg("Notification Transports")]]], + [null, msg("Customisation"), null, [ + ["/policy/policies", msg("Policies")], + ["/core/property-mappings", msg("Property Mappings")], + ["/blueprints/instances", msg("Blueprints")], + ["/policy/reputation", msg("Reputation scores")]]], + [null, msg("Flows and Stages"), null, [ + ["/flow/flows", msg("Flows"), [`^/flow/flows/(?${SLUG_REGEX})$`]], + ["/flow/stages", msg("Stages")], + ["/flow/stages/prompts", msg("Prompts")]]], + [null, msg("Directory"), null, [ + ["/identity/users", msg("Users"), [`^/identity/users/(?${ID_REGEX})$`]], + ["/identity/groups", msg("Groups"), [`^/identity/groups/(?${UUID_REGEX})$`]], + ["/identity/roles", msg("Roles"), [`^/identity/roles/(?${UUID_REGEX})$`]], + ["/core/sources", msg("Federation and Social login"), [`^/core/sources/(?${SLUG_REGEX})$`]], + ["/core/tokens", msg("Tokens and App passwords")], + ["/flow/stages/invitations", msg("Invitations")]]], + [null, msg("System"), null, [ + ["/core/tenants", msg("Tenants")], + ["/crypto/certificates", msg("Certificates")], + ["/outpost/integrations", msg("Outpost Integrations")]]] + ]; + + // Typescript requires the type here to correctly type the recursive path + type SidebarRenderer = (_: SidebarEntry) => TemplateResult; + + const renderOneSidebarItem: SidebarRenderer = ([path, label, attributes, children]) => { + const properties = Array.isArray(attributes) + ? { ".activeWhen": attributes } + : attributes ?? {}; + if (path) { + properties["path"] = path; + } + return html` + ${label ? html`${label}` : nothing} + ${map(children, renderOneSidebarItem)} + `; + }; + + // prettier-ignore + return html` + ${this.renderNewVersionMessage()} + ${this.renderImpersonationMessage()} + ${map(sidebarContent, renderOneSidebarItem)} + ${this.renderEnterpriseMessage()} + `; + } + + renderNewVersionMessage() { + return this.version && this.version.versionCurrent !== VERSION + ? html` + + ${msg("A newer version of the frontend is available.")} + + ` + : nothing; + } + + renderImpersonationMessage() { + return this.user?.original + ? html` { + new CoreApi(DEFAULT_CONFIG).coreUsersImpersonateEndRetrieve().then(() => { + window.location.reload(); + }); + }} + > + ${msg( + str`You're currently impersonating ${this.user.user.username}. Click to stop.`, + )} + ` + : nothing; + } + + renderEnterpriseMessage() { + return this.config?.capabilities.includes(CapabilitiesEnum.IsEnterprise) + ? html` + + ${msg("Enterprise")} + + ${msg("Licenses")} + + + ` + : nothing; + } } diff --git a/web/src/admin/AdminInterface/AdminSidebar.ts b/web/src/admin/AdminInterface/AdminSidebar.ts deleted file mode 100644 index f922bbeff..000000000 --- a/web/src/admin/AdminInterface/AdminSidebar.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; -import { VERSION } from "@goauthentik/common/constants"; -import { me } from "@goauthentik/common/users"; -import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts"; -import { AKElement } from "@goauthentik/elements/Base"; -import { ID_REGEX, SLUG_REGEX, UUID_REGEX } from "@goauthentik/elements/router/Route"; -import { spread } from "@open-wc/lit-helpers"; - -import { consume } from "@lit-labs/context"; -import { msg, str } from "@lit/localize"; -import { TemplateResult, html, nothing } from "lit"; -import { customElement, property, state } from "lit/decorators.js"; -import { map } from "lit/directives/map.js"; - -import { - AdminApi, - CapabilitiesEnum, - type Config, - CoreApi, - ProvidersApi, - type SessionUser, - UiThemeEnum, - type UserSelf, - TypeCreate, - Version, -} from "@goauthentik/api"; - -@customElement("ak-admin-sidebar") -export class AkAdminSidebar extends AKElement { - @property({ type: Boolean }) - open = true; - - @state() - version: Version["versionCurrent"] | null = null; - - @state() - impersonation: UserSelf["username"] | null = null; - - @state() - providerTypes: TypeCreate[] = []; - - @consume({ context: authentikConfigContext }) - public config!: Config; - - firstUpdated() { - new AdminApi(DEFAULT_CONFIG).adminVersionRetrieve().then((version) => { - this.version = version.versionCurrent; - }); - me().then((user: SessionUser) => { - this.impersonation = user.original ? user.user.username : null; - }); - new ProvidersApi(DEFAULT_CONFIG).providersAllTypesList().then((types) => { - this.providerTypes = types; - }); - } - - render() { - return html` - - ${this.renderSidebarItems()} - - `; - } - - renderSidebarItems(): TemplateResult { - // The second attribute type is of string[] to help with the 'activeWhen' control, which was - // commonplace and singular enough to merit its own handler. - type SidebarEntry = [ - path: string | null, - label: string, - attributes?: Record | string[] | null, // eslint-disable-line - children?: SidebarEntry[], - ]; - - // prettier-ignore - const sidebarContent: SidebarEntry[] = [ - ["/if/user/", msg("User interface"), { "?isAbsoluteLink": true, "?highlight": true }], - [null, msg("Dashboards"), { "?expanded": true }, [ - ["/administration/overview", msg("Overview")], - ["/administration/dashboard/users", msg("User Statistics")], - ["/administration/system-tasks", msg("System Tasks")]]], - [null, msg("Applications"), null, [ - ["/core/applications", msg("Applications"), [`^/core/applications/(?${SLUG_REGEX})$`]], - ["/core/providers", msg("Providers"), [`^/core/providers/(?${ID_REGEX})$`]], - ["/outpost/outposts", msg("Outposts")]]], - [null, msg("Events"), null, [ - ["/events/log", msg("Logs"), [`^/events/log/(?${UUID_REGEX})$`]], - ["/events/rules", msg("Notification Rules")], - ["/events/transports", msg("Notification Transports")]]], - [null, msg("Customisation"), null, [ - ["/policy/policies", msg("Policies")], - ["/core/property-mappings", msg("Property Mappings")], - ["/blueprints/instances", msg("Blueprints")], - ["/policy/reputation", msg("Reputation scores")]]], - [null, msg("Flows and Stages"), null, [ - ["/flow/flows", msg("Flows"), [`^/flow/flows/(?${SLUG_REGEX})$`]], - ["/flow/stages", msg("Stages")], - ["/flow/stages/prompts", msg("Prompts")]]], - [null, msg("Directory"), null, [ - ["/identity/users", msg("Users"), [`^/identity/users/(?${ID_REGEX})$`]], - ["/identity/groups", msg("Groups"), [`^/identity/groups/(?${UUID_REGEX})$`]], - ["/identity/roles", msg("Roles"), [`^/identity/roles/(?${UUID_REGEX})$`]], - ["/core/sources", msg("Federation and Social login"), [`^/core/sources/(?${SLUG_REGEX})$`]], - ["/core/tokens", msg("Tokens and App passwords")], - ["/flow/stages/invitations", msg("Invitations")]]], - [null, msg("System"), null, [ - ["/core/tenants", msg("Tenants")], - ["/crypto/certificates", msg("Certificates")], - ["/outpost/integrations", msg("Outpost Integrations")]]] - ]; - - // Typescript requires the type here to correctly type the recursive path - type SidebarRenderer = (_: SidebarEntry) => TemplateResult; - - const renderOneSidebarItem: SidebarRenderer = ([path, label, attributes, children]) => { - const properties = Array.isArray(attributes) - ? { ".activeWhen": attributes } - : attributes ?? {}; - if (path) { - properties["path"] = path; - } - return html` - ${label ? html`${label}` : nothing} - ${map(children, renderOneSidebarItem)} - `; - }; - - // prettier-ignore - return html` - ${this.renderNewVersionMessage()} - ${this.renderImpersonationMessage()} - ${map(sidebarContent, renderOneSidebarItem)} - ${this.renderEnterpriseMessage()} - `; - } - - renderNewVersionMessage() { - return this.version && this.version !== VERSION - ? html` - - ${msg("A newer version of the frontend is available.")} - - ` - : nothing; - } - - renderImpersonationMessage() { - const reload = () => - new CoreApi(DEFAULT_CONFIG).coreUsersImpersonateEndRetrieve().then(() => { - window.location.reload(); - }); - - return this.impersonation - ? html` - ${msg( - str`You're currently impersonating ${this.impersonation}. Click to stop.` - )} - ` - : nothing; - } - - renderEnterpriseMessage() { - return this.config?.capabilities.includes(CapabilitiesEnum.IsEnterprise) - ? html` - - ${msg("Enterprise")} - - ${msg("Licenses")} - - - ` - : nothing; - } -} diff --git a/web/src/admin/AdminInterface/index.ts b/web/src/admin/AdminInterface/index.ts deleted file mode 100644 index f8e588a05..000000000 --- a/web/src/admin/AdminInterface/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { AdminInterface } from "./AdminInterface"; -import "./AdminInterface"; -export { AdminInterface }; diff --git a/web/src/elements/AuthentikContexts.ts b/web/src/elements/AuthentikContexts.ts deleted file mode 100644 index a4b7d4f84..000000000 --- a/web/src/elements/AuthentikContexts.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { createContext } from "@lit-labs/context"; -import { type Config } from "@goauthentik/api"; - -export const authentikConfigContext = createContext( - Symbol("authentik-config-context") -); - -export default authentikConfigContext; diff --git a/web/src/elements/Base.ts b/web/src/elements/Base.ts index f9efc1228..7b2420454 100644 --- a/web/src/elements/Base.ts +++ b/web/src/elements/Base.ts @@ -1,7 +1,6 @@ import { config, tenant } from "@goauthentik/common/api/config"; import { EVENT_THEME_CHANGE } from "@goauthentik/common/constants"; import { UIConfig, uiConfig } from "@goauthentik/common/ui/config"; -import { ContextProvider } from "@lit-labs/context"; import { adaptCSS } from "@goauthentik/common/utils"; import { localized } from "@lit/localize"; @@ -13,7 +12,6 @@ import ThemeDark from "@goauthentik/common/styles/theme-dark.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { Config, CurrentTenant, UiThemeEnum } from "@goauthentik/api"; -import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts"; type AkInterface = HTMLElement & { getTheme: () => Promise; @@ -183,25 +181,8 @@ export class Interface extends AKElement implements AkInterface { @state() uiConfig?: UIConfig; - _configContext = new ContextProvider(this, { - context: authentikConfigContext, - initialValue: undefined - }); - - - _config?: Config; - @state() - set config(c: Config) { - this._config = c; - this._configContext.setValue(c); - this.requestUpdate(); - } - - get config(): Config | undefined { - return this._config; - } - + config?: Config; constructor() { super(); diff --git a/web/src/elements/sidebar/SidebarItem.ts b/web/src/elements/sidebar/SidebarItem.ts index 26cdb975e..9d5374736 100644 --- a/web/src/elements/sidebar/SidebarItem.ts +++ b/web/src/elements/sidebar/SidebarItem.ts @@ -144,84 +144,47 @@ export class SidebarItem extends AKElement { return this.renderInner(); } - renderWithChildren() { - return html`
  • - -
    -
      - -
    -
    -
  • `; - } - - renderWithPathAndChildren() { - return html`
  • - - -
    -
      - -
    -
    -
  • `; - } - - renderWithPath() { - return html` - - - - `; - } - - renderWithLabel() { - html` - - - - `; - } - - renderInner() { + renderInner(): TemplateResult { if (this.childItems.length > 0) { - return this.path ? this.renderWithPathAndChildren() : this.renderWithChildren(); + return html`
  • + +
    +
      + +
    +
    +
  • `; } - return html`
  • - ${this.path ? this.renderWithPath() : this.renderWithLabel()} + ${this.path + ? html` + + + + ` + : html` + + + + `}
  • `; } }