From be06adcb599a4a2b773462bfb7e7660760eb3ece Mon Sep 17 00:00:00 2001 From: Jens L Date: Sat, 14 May 2022 17:07:37 +0200 Subject: [PATCH] web: lazy load parts of interfaces (#2864) --- web/rollup.config.js | 68 ++++---- web/src/authentik.css | 5 + web/src/elements/router/Route.ts | 35 +++-- web/src/flows/FlowExecutor.ts | 236 +++++++++++++++------------- web/src/interfaces/locale.ts | 136 ++++++++++------ web/src/locales/de.po | 1 + web/src/locales/en.po | 1 + web/src/locales/es.po | 1 + web/src/locales/fr_FR.po | 1 + web/src/locales/pl.po | 1 + web/src/locales/pseudo-LOCALE.po | 1 + web/src/locales/tr.po | 1 + web/src/locales/zh-Hans.po | 1 + web/src/locales/zh-Hant.po | 1 + web/src/locales/zh_TW.po | 1 + web/src/pages/flows/FlowViewPage.ts | 5 + web/src/routesAdmin.ts | 200 ++++++++++++----------- web/src/routesUser.ts | 8 +- 18 files changed, 389 insertions(+), 314 deletions(-) diff --git a/web/rollup.config.js b/web/rollup.config.js index 388b54a6a..3124e5099 100644 --- a/web/rollup.config.js +++ b/web/rollup.config.js @@ -70,24 +70,32 @@ export function manualChunks(id) { } } -export const PLUGINS = [ - cssimport(), - markdown(), - nodeResolve({ extensions, browser: true }), - commonjs(), - babel({ - extensions, - babelHelpers: "runtime", - include: ["src/**/*"], - }), - replace({ - "process.env.NODE_ENV": JSON.stringify(isProdBuild ? "production" : "development"), - "process.env.AK_API_BASE_PATH": JSON.stringify(apiBasePath), - "preventAssignment": true, - }), - sourcemaps(), - isProdBuild && terser(), -].filter((p) => p); +export const defaultOptions = { + plugins: [ + cssimport(), + markdown(), + nodeResolve({ extensions, browser: true }), + commonjs(), + babel({ + extensions, + babelHelpers: "runtime", + include: ["src/**/*"], + }), + replace({ + "process.env.NODE_ENV": JSON.stringify(isProdBuild ? "production" : "development"), + "process.env.AK_API_BASE_PATH": JSON.stringify(apiBasePath), + "preventAssignment": true, + }), + sourcemaps(), + isProdBuild && terser(), + ].filter((p) => p), + watch: { + clearScreen: false, + }, + preserveEntrySignatures: false, + cache: true, + context: "window", +}; // Polyfills (imported first) export const POLY = { @@ -110,9 +118,6 @@ export const POLY = { copyOnce: false, }), ].filter((p) => p), - watch: { - clearScreen: false, - }, }; export default [ @@ -120,8 +125,6 @@ export default [ // Flow interface { input: "./src/interfaces/FlowInterface.ts", - context: "window", - cache: true, output: [ { format: "es", @@ -130,16 +133,11 @@ export default [ manualChunks: manualChunks, }, ], - plugins: PLUGINS, - watch: { - clearScreen: false, - }, + ...defaultOptions, }, // Admin interface { input: "./src/interfaces/AdminInterface.ts", - context: "window", - cache: true, output: [ { format: "es", @@ -148,16 +146,11 @@ export default [ manualChunks: manualChunks, }, ], - plugins: PLUGINS, - watch: { - clearScreen: false, - }, + ...defaultOptions, }, // User interface { input: "./src/interfaces/UserInterface.ts", - context: "window", - cache: true, output: [ { format: "es", @@ -166,9 +159,6 @@ export default [ manualChunks: manualChunks, }, ], - plugins: PLUGINS, - watch: { - clearScreen: false, - }, + ...defaultOptions, }, ]; diff --git a/web/src/authentik.css b/web/src/authentik.css index 2e9d7ffc2..e98426cbb 100644 --- a/web/src/authentik.css +++ b/web/src/authentik.css @@ -95,6 +95,11 @@ html > form > input { vertical-align: middle; } +.pf-c-description-list__description .pf-c-button { + margin-right: 6px; + margin-bottom: 6px; +} + @media (prefers-color-scheme: dark) { .ak-static-page h1 { color: var(--ak-dark-foreground); diff --git a/web/src/elements/router/Route.ts b/web/src/elements/router/Route.ts index b6c186de1..7aab1c69f 100644 --- a/web/src/elements/router/Route.ts +++ b/web/src/elements/router/Route.ts @@ -1,4 +1,5 @@ import { TemplateResult, html } from "lit"; +import { until } from "lit/directives/until.js"; export const SLUG_REGEX = "[-a-zA-Z0-9_]+"; export const ID_REGEX = "\\d+"; @@ -12,39 +13,41 @@ export class Route { url: RegExp; private element?: TemplateResult; - private callback?: (args: RouteArgs) => TemplateResult; + private callback?: (args: RouteArgs) => Promise; - constructor(url: RegExp, element?: TemplateResult) { + constructor(url: RegExp, callback?: (args: RouteArgs) => Promise) { this.url = url; - this.element = element; + this.callback = callback; } - redirect(to: string): Route { - this.callback = () => { + redirect(to: string, raw = false): Route { + this.callback = async () => { console.debug(`authentik/router: redirecting ${to}`); - window.location.hash = `#${to}`; - return html``; - }; - return this; - } - - redirectRaw(to: string): Route { - this.callback = () => { - console.debug(`authentik/router: redirecting ${to}`); - window.location.hash = `${to}`; + if (!raw) { + window.location.hash = `#${to}`; + } else { + window.location.hash = to; + } return html``; }; return this; } then(render: (args: RouteArgs) => TemplateResult): Route { + this.callback = async (args) => { + return render(args); + }; + return this; + } + + thenAsync(render: (args: RouteArgs) => Promise): Route { this.callback = render; return this; } render(args: RouteArgs): TemplateResult { if (this.callback) { - return this.callback(args); + return html`${until(this.callback(args))}`; } if (this.element) { return this.element; diff --git a/web/src/flows/FlowExecutor.ts b/web/src/flows/FlowExecutor.ts index e5739b93b..9bca2303c 100644 --- a/web/src/flows/FlowExecutor.ts +++ b/web/src/flows/FlowExecutor.ts @@ -30,26 +30,13 @@ import { WebsocketClient } from "../common/ws"; import { EVENT_FLOW_ADVANCE, TITLE_DEFAULT } from "../constants"; import "../elements/LoadingOverlay"; import { first } from "../utils"; -import "./FlowInspector"; -import "./sources/apple/AppleLoginInit"; -import "./sources/plex/PlexLoginInit"; import "./stages/RedirectStage"; import "./stages/access_denied/AccessDeniedStage"; -import "./stages/authenticator_duo/AuthenticatorDuoStage"; -import "./stages/authenticator_sms/AuthenticatorSMSStage"; -import "./stages/authenticator_static/AuthenticatorStaticStage"; -import "./stages/authenticator_totp/AuthenticatorTOTPStage"; -import "./stages/authenticator_validate/AuthenticatorValidateStage"; -import "./stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage"; import "./stages/autosubmit/AutosubmitStage"; import { StageHost } from "./stages/base"; import "./stages/captcha/CaptchaStage"; -import "./stages/consent/ConsentStage"; -import "./stages/dummy/DummyStage"; -import "./stages/email/EmailStage"; import "./stages/identification/IdentificationStage"; import "./stages/password/PasswordStage"; -import "./stages/prompt/PromptStage"; @customElement("ak-flow-executor") export class FlowExecutor extends LitElement implements StageHost { @@ -229,7 +216,117 @@ export class FlowExecutor extends LitElement implements StageHost { } as ChallengeTypes; } - renderChallenge(): TemplateResult { + async renderChallengeNativeElement(): Promise { + switch (this.challenge?.component) { + case "ak-stage-access-denied": + // Statically imported for performance reasons + return html``; + case "ak-stage-identification": + // Statically imported for performance reasons + return html``; + case "ak-stage-password": + // Statically imported for performance reasons + return html``; + case "ak-stage-captcha": + // Statically imported to prevent browsers blocking urls + return html``; + case "ak-stage-consent": + await import("./stages/consent/ConsentStage"); + return html``; + case "ak-stage-dummy": + await import("./stages/dummy/DummyStage"); + return html``; + case "ak-stage-email": + await import("./stages/email/EmailStage"); + return html``; + case "ak-stage-autosubmit": + // Statically imported for performance reasons + return html``; + case "ak-stage-prompt": + await import("./stages/prompt/PromptStage"); + return html``; + case "ak-stage-authenticator-totp": + await import("./stages/authenticator_totp/AuthenticatorTOTPStage"); + return html``; + case "ak-stage-authenticator-duo": + await import("./stages/authenticator_duo/AuthenticatorDuoStage"); + return html``; + case "ak-stage-authenticator-static": + await import("./stages/authenticator_static/AuthenticatorStaticStage"); + return html``; + case "ak-stage-authenticator-webauthn": + await import("./stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage"); + return html``; + case "ak-stage-authenticator-sms": + await import("./stages/authenticator_sms/AuthenticatorSMSStage"); + return html``; + case "ak-stage-authenticator-validate": + await import("./stages/authenticator_validate/AuthenticatorValidateStage"); + return html``; + case "ak-flow-sources-plex": + await import("./sources/plex/PlexLoginInit"); + return html``; + case "ak-flow-sources-oauth-apple": + await import("./sources/apple/AppleLoginInit"); + return html``; + default: + break; + } + return html`Invalid native challenge element`; + } + + async renderChallenge(): Promise { if (!this.challenge) { return html``; } @@ -247,96 +344,7 @@ export class FlowExecutor extends LitElement implements StageHost { case ChallengeChoices.Shell: return html`${unsafeHTML((this.challenge as ShellChallenge).body)}`; case ChallengeChoices.Native: - switch (this.challenge.component) { - case "ak-stage-access-denied": - return html``; - case "ak-stage-identification": - return html``; - case "ak-stage-password": - return html``; - case "ak-stage-captcha": - return html``; - case "ak-stage-consent": - return html``; - case "ak-stage-dummy": - return html``; - case "ak-stage-email": - return html``; - case "ak-stage-autosubmit": - return html``; - case "ak-stage-prompt": - return html``; - case "ak-stage-authenticator-totp": - return html``; - case "ak-stage-authenticator-duo": - return html``; - case "ak-stage-authenticator-static": - return html``; - case "ak-stage-authenticator-webauthn": - return html``; - case "ak-stage-authenticator-validate": - return html``; - case "ak-stage-authenticator-sms": - return html``; - case "ak-flow-sources-plex": - return html``; - case "ak-flow-sources-oauth-apple": - return html``; - default: - break; - } - break; + return await this.renderChallengeNativeElement(); default: console.debug(`authentik/flows: unexpected data type ${this.challenge.type}`); break; @@ -350,10 +358,20 @@ export class FlowExecutor extends LitElement implements StageHost { } return html` ${this.loading ? html`` : html``} - ${this.renderChallenge()} + ${until(this.renderChallenge())} `; } + async renderInspector(): Promise { + if (!this.inspectorOpen) { + return html``; + } + await import("./FlowInspector"); + return html``; + } + render(): TemplateResult { return html`
- - + ${until(this.renderInspector())} `; diff --git a/web/src/interfaces/locale.ts b/web/src/interfaces/locale.ts index a12527dc3..8a486e02d 100644 --- a/web/src/interfaces/locale.ts +++ b/web/src/interfaces/locale.ts @@ -1,96 +1,122 @@ -import { de, en, es, fr, pl, tr, zh } from "make-plural/plurals"; - import { Messages, i18n } from "@lingui/core"; import { detect, fromNavigator, fromUrl } from "@lingui/detect-locale"; import { t } from "@lingui/macro"; import { LitElement } from "lit"; -import { messages as localeDE } from "../locales/de"; -import { messages as localeEN } from "../locales/en"; -import { messages as localeES } from "../locales/es"; -import { messages as localeFR_FR } from "../locales/fr_FR"; -import { messages as localePL } from "../locales/pl"; -import { messages as localeDEBUG } from "../locales/pseudo-LOCALE"; -import { messages as localeTR } from "../locales/tr"; -import { messages as localeZH_Hans } from "../locales/zh-Hans"; -import { messages as localeZH_Hant } from "../locales/zh-Hant"; -import { messages as localeZH_TW } from "../locales/zh_TW"; +interface Locale { + locale: Messages; + // eslint-disable-next-line @typescript-eslint/ban-types + plurals: Function; +} export const LOCALES: { code: string; label: string; - // eslint-disable-next-line @typescript-eslint/ban-types - plurals: Function; - locale: Messages; + locale: () => Promise; }[] = [ { code: "en", - plurals: en, label: t`English`, - locale: localeEN, + locale: async () => { + return { + locale: (await import("../locales/en")).messages, + plurals: (await import("make-plural/plurals")).en, + }; + }, }, { code: "debug", - plurals: en, label: t`Debug`, - locale: localeDEBUG, + locale: async () => { + return { + locale: (await import("../locales/pseudo-LOCALE")).messages, + plurals: (await import("make-plural/plurals")).en, + }; + }, }, { code: "fr", - plurals: fr, label: t`French`, - locale: localeFR_FR, + locale: async () => { + return { + locale: (await import("../locales/fr_FR")).messages, + plurals: (await import("make-plural/plurals")).fr, + }; + }, }, { code: "tr", - plurals: tr, label: t`Turkish`, - locale: localeTR, + locale: async () => { + return { + locale: (await import("../locales/tr")).messages, + plurals: (await import("make-plural/plurals")).tr, + }; + }, }, { code: "es", - plurals: es, label: t`Spanish`, - locale: localeES, + locale: async () => { + return { + locale: (await import("../locales/es")).messages, + plurals: (await import("make-plural/plurals")).es, + }; + }, }, { code: "pl", - plurals: pl, label: t`Polish`, - locale: localePL, + locale: async () => { + return { + locale: (await import("../locales/pl")).messages, + plurals: (await import("make-plural/plurals")).pl, + }; + }, }, { code: "zh_TW", - plurals: zh, label: t`Taiwanese Mandarin`, - locale: localeZH_TW, + locale: async () => { + return { + locale: (await import("../locales/zh_TW")).messages, + plurals: (await import("make-plural/plurals")).zh, + }; + }, }, { code: "zh-CN", - plurals: zh, label: t`Chinese (simplified)`, - locale: localeZH_Hans, + locale: async () => { + return { + locale: (await import("../locales/zh-Hans")).messages, + plurals: (await import("make-plural/plurals")).zh, + }; + }, }, { code: "zh-HK", - plurals: zh, label: t`Chinese (traditional)`, - locale: localeZH_Hant, + locale: async () => { + return { + locale: (await import("../locales/zh-Hant")).messages, + plurals: (await import("make-plural/plurals")).zh, + }; + }, }, { code: "de", - plurals: de, label: t`German`, - locale: localeDE, + locale: async () => { + return { + locale: (await import("../locales/de")).messages, + plurals: (await import("make-plural/plurals")).de, + }; + }, }, ]; -LOCALES.forEach((locale) => { - i18n.loadLocaleData(locale.code, { plurals: locale.plurals }); - i18n.load(locale.code, locale.locale); -}); - const DEFAULT_FALLBACK = () => "en"; export function autoDetectLanguage() { @@ -102,25 +128,33 @@ export function autoDetectLanguage() { } if (detected in i18n._messages) { console.debug(`authentik/locale: Activating detected locale '${detected}'`); - i18n.activate(detected); + activateLocale(detected); } else { console.debug(`authentik/locale: No locale for '${detected}', falling back to en`); - i18n.activate(DEFAULT_FALLBACK()); + activateLocale(DEFAULT_FALLBACK()); } } export function activateLocale(code: string) { const urlLocale = fromUrl("locale"); if (urlLocale !== null && urlLocale !== "") { - i18n.activate(urlLocale); - } else { - i18n.activate(code); + code = urlLocale; } - document.querySelectorAll("[data-refresh-on-locale=true]").forEach((el) => { - try { - (el as LitElement).requestUpdate(); - } catch { - console.debug(`authentik/locale: failed to update element ${el}`); - } + const locale = LOCALES.find((locale) => locale.code == code); + if (!locale) { + console.warn(`authentik/locale: failed to find locale for code ${code}`); + return; + } + locale.locale().then((localeData) => { + i18n.loadLocaleData(locale.code, { plurals: localeData.plurals }); + i18n.load(locale.code, localeData.locale); + i18n.activate(locale.code); + document.querySelectorAll("[data-refresh-on-locale=true]").forEach((el) => { + try { + (el as LitElement).requestUpdate(); + } catch { + console.debug(`authentik/locale: failed to update element ${el}`); + } + }); }); } autoDetectLanguage(); diff --git a/web/src/locales/de.po b/web/src/locales/de.po index 5ef2eff17..9b596eca3 100644 --- a/web/src/locales/de.po +++ b/web/src/locales/de.po @@ -2824,6 +2824,7 @@ msgstr "Server laden" #: src/elements/table/Table.ts #: src/flows/FlowExecutor.ts #: src/flows/FlowExecutor.ts +#: src/flows/FlowExecutor.ts #: src/flows/FlowInspector.ts #: src/flows/stages/access_denied/AccessDeniedStage.ts #: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts diff --git a/web/src/locales/en.po b/web/src/locales/en.po index 67f93d0e8..9631fcbd5 100644 --- a/web/src/locales/en.po +++ b/web/src/locales/en.po @@ -2876,6 +2876,7 @@ msgstr "Load servers" #: src/elements/table/Table.ts #: src/flows/FlowExecutor.ts #: src/flows/FlowExecutor.ts +#: src/flows/FlowExecutor.ts #: src/flows/FlowInspector.ts #: src/flows/stages/access_denied/AccessDeniedStage.ts #: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts diff --git a/web/src/locales/es.po b/web/src/locales/es.po index bad12d73e..9716f603a 100644 --- a/web/src/locales/es.po +++ b/web/src/locales/es.po @@ -2817,6 +2817,7 @@ msgstr "Servidores de carga" #: src/elements/table/Table.ts #: src/flows/FlowExecutor.ts #: src/flows/FlowExecutor.ts +#: src/flows/FlowExecutor.ts #: src/flows/FlowInspector.ts #: src/flows/stages/access_denied/AccessDeniedStage.ts #: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts diff --git a/web/src/locales/fr_FR.po b/web/src/locales/fr_FR.po index 86a7dc933..10a15dd49 100644 --- a/web/src/locales/fr_FR.po +++ b/web/src/locales/fr_FR.po @@ -2848,6 +2848,7 @@ msgstr "Charger les serveurs" #: src/elements/table/Table.ts #: src/flows/FlowExecutor.ts #: src/flows/FlowExecutor.ts +#: src/flows/FlowExecutor.ts #: src/flows/FlowInspector.ts #: src/flows/stages/access_denied/AccessDeniedStage.ts #: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts diff --git a/web/src/locales/pl.po b/web/src/locales/pl.po index c93d8721a..1cb94ff7a 100644 --- a/web/src/locales/pl.po +++ b/web/src/locales/pl.po @@ -2814,6 +2814,7 @@ msgstr "Załaduj serwery" #: src/elements/table/Table.ts #: src/flows/FlowExecutor.ts #: src/flows/FlowExecutor.ts +#: src/flows/FlowExecutor.ts #: src/flows/FlowInspector.ts #: src/flows/stages/access_denied/AccessDeniedStage.ts #: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts diff --git a/web/src/locales/pseudo-LOCALE.po b/web/src/locales/pseudo-LOCALE.po index 06383bd5f..1747905fd 100644 --- a/web/src/locales/pseudo-LOCALE.po +++ b/web/src/locales/pseudo-LOCALE.po @@ -2858,6 +2858,7 @@ msgstr "" #: src/elements/table/Table.ts #: src/flows/FlowExecutor.ts #: src/flows/FlowExecutor.ts +#: src/flows/FlowExecutor.ts #: src/flows/FlowInspector.ts #: src/flows/stages/access_denied/AccessDeniedStage.ts #: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts diff --git a/web/src/locales/tr.po b/web/src/locales/tr.po index 217c0b9b4..cfd4d3c02 100644 --- a/web/src/locales/tr.po +++ b/web/src/locales/tr.po @@ -2818,6 +2818,7 @@ msgstr "Sunucuları yükle" #: src/elements/table/Table.ts #: src/flows/FlowExecutor.ts #: src/flows/FlowExecutor.ts +#: src/flows/FlowExecutor.ts #: src/flows/FlowInspector.ts #: src/flows/stages/access_denied/AccessDeniedStage.ts #: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts diff --git a/web/src/locales/zh-Hans.po b/web/src/locales/zh-Hans.po index ab677b992..a4d4e4f5d 100644 --- a/web/src/locales/zh-Hans.po +++ b/web/src/locales/zh-Hans.po @@ -2802,6 +2802,7 @@ msgstr "加载服务器" #: src/elements/table/Table.ts #: src/flows/FlowExecutor.ts #: src/flows/FlowExecutor.ts +#: src/flows/FlowExecutor.ts #: src/flows/FlowInspector.ts #: src/flows/stages/access_denied/AccessDeniedStage.ts #: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts diff --git a/web/src/locales/zh-Hant.po b/web/src/locales/zh-Hant.po index 63db418c7..e9b203701 100644 --- a/web/src/locales/zh-Hant.po +++ b/web/src/locales/zh-Hant.po @@ -2804,6 +2804,7 @@ msgstr "加载服务器" #: src/elements/table/Table.ts #: src/flows/FlowExecutor.ts #: src/flows/FlowExecutor.ts +#: src/flows/FlowExecutor.ts #: src/flows/FlowInspector.ts #: src/flows/stages/access_denied/AccessDeniedStage.ts #: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts diff --git a/web/src/locales/zh_TW.po b/web/src/locales/zh_TW.po index 8803f38a6..5d488c1b9 100644 --- a/web/src/locales/zh_TW.po +++ b/web/src/locales/zh_TW.po @@ -2804,6 +2804,7 @@ msgstr "加载服务器" #: src/elements/table/Table.ts #: src/flows/FlowExecutor.ts #: src/flows/FlowExecutor.ts +#: src/flows/FlowExecutor.ts #: src/flows/FlowInspector.ts #: src/flows/stages/access_denied/AccessDeniedStage.ts #: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts diff --git a/web/src/pages/flows/FlowViewPage.ts b/web/src/pages/flows/FlowViewPage.ts index 55af16d40..1ca6d0cdb 100644 --- a/web/src/pages/flows/FlowViewPage.ts +++ b/web/src/pages/flows/FlowViewPage.ts @@ -163,6 +163,11 @@ export class FlowViewPage extends LitElement { `inspector&next=/#${window.location.hash}`, )}`; window.open(finalURL, "_blank"); + }) + .catch((exc: Response) => { + // This request can return a HTTP 400 when a flow + // is not applicable. + window.open(exc.url, "_blank"); }); }} > diff --git a/web/src/routesAdmin.ts b/web/src/routesAdmin.ts index f9ea6d374..6461a952e 100644 --- a/web/src/routesAdmin.ts +++ b/web/src/routesAdmin.ts @@ -2,116 +2,130 @@ import { html } from "lit"; import { ID_REGEX, Route, SLUG_REGEX, UUID_REGEX } from "./elements/router/Route"; import "./pages/admin-overview/AdminOverviewPage"; -import "./pages/admin-overview/DashboardUserPage"; -import "./pages/applications/ApplicationListPage"; -import "./pages/applications/ApplicationViewPage"; -import "./pages/crypto/CertificateKeyPairListPage"; -import "./pages/events/EventInfoPage"; -import "./pages/events/EventListPage"; -import "./pages/events/RuleListPage"; -import "./pages/events/TransportListPage"; -import "./pages/flows/FlowListPage"; -import "./pages/flows/FlowViewPage"; -import "./pages/groups/GroupListPage"; -import "./pages/groups/GroupViewPage"; -import "./pages/outposts/OutpostListPage"; -import "./pages/outposts/ServiceConnectionListPage"; -import "./pages/policies/PolicyListPage"; -import "./pages/policies/reputation/ReputationListPage"; -import "./pages/property-mappings/PropertyMappingListPage"; -import "./pages/providers/ProviderListPage"; -import "./pages/providers/ProviderViewPage"; -import "./pages/sources/SourceListPage"; -import "./pages/sources/SourceViewPage"; -import "./pages/stages/StageListPage"; -import "./pages/stages/invitation/InvitationListPage"; -import "./pages/stages/prompt/PromptListPage"; -import "./pages/system-tasks/SystemTaskListPage"; -import "./pages/tenants/TenantListPage"; -import "./pages/tokens/TokenListPage"; -import "./pages/users/UserListPage"; -import "./pages/users/UserViewPage"; export const ROUTES: Route[] = [ // Prevent infinite Shell loops new Route(new RegExp("^/$")).redirect("/administration/overview"), new Route(new RegExp("^#.*")).redirect("/administration/overview"), - new Route(new RegExp("^/library$")).redirectRaw("/if/user/"), - new Route( - new RegExp("^/administration/overview$"), - html``, - ), - new Route( - new RegExp("^/administration/dashboard/users$"), - html``, - ), - new Route( - new RegExp("^/administration/system-tasks$"), - html``, - ), - new Route(new RegExp("^/core/providers$"), html``), - new Route(new RegExp(`^/core/providers/(?${ID_REGEX})$`)).then((args) => { + new Route(new RegExp("^/library$")).redirect("/if/user/", true), + // statically imported since this is the default route + new Route(new RegExp("^/administration/overview$"), async () => { + return html``; + }), + new Route(new RegExp("^/administration/dashboard/users$"), async () => { + await import("./pages/admin-overview/DashboardUserPage"); + return html``; + }), + new Route(new RegExp("^/administration/system-tasks$"), async () => { + await import("./pages/system-tasks/SystemTaskListPage"); + return html``; + }), + new Route(new RegExp("^/core/providers$"), async () => { + await import("./pages/providers/ProviderListPage"); + return html``; + }), + new Route(new RegExp(`^/core/providers/(?${ID_REGEX})$`), async (args) => { + await import("./pages/providers/ProviderViewPage"); return html``; }), - new Route( - new RegExp("^/core/applications$"), - html``, - ), - new Route(new RegExp(`^/core/applications/(?${SLUG_REGEX})$`)).then((args) => { + new Route(new RegExp("^/core/applications$"), async () => { + await import("./pages/applications/ApplicationListPage"); + return html``; + }), + new Route(new RegExp(`^/core/applications/(?${SLUG_REGEX})$`), async (args) => { + await import("./pages/applications/ApplicationViewPage"); return html``; }), - new Route(new RegExp("^/core/sources$"), html``), - new Route(new RegExp(`^/core/sources/(?${SLUG_REGEX})$`)).then((args) => { + new Route(new RegExp("^/core/sources$"), async () => { + await import("./pages/sources/SourceListPage"); + return html``; + }), + new Route(new RegExp(`^/core/sources/(?${SLUG_REGEX})$`), async (args) => { + await import("./pages/sources/SourceViewPage"); return html``; }), - new Route( - new RegExp("^/core/property-mappings$"), - html``, - ), - new Route(new RegExp("^/core/tokens$"), html``), - new Route(new RegExp("^/core/tenants$"), html``), - new Route(new RegExp("^/policy/policies$"), html``), - new Route( - new RegExp("^/policy/reputation$"), - html``, - ), - new Route(new RegExp("^/identity/groups$"), html``), - new Route(new RegExp(`^/identity/groups/(?${UUID_REGEX})$`)).then((args) => { + new Route(new RegExp("^/core/property-mappings$"), async () => { + await import("./pages/property-mappings/PropertyMappingListPage"); + return html``; + }), + new Route(new RegExp("^/core/tokens$"), async () => { + await import("./pages/tokens/TokenListPage"); + return html``; + }), + new Route(new RegExp("^/core/tenants$"), async () => { + await import("./pages/tenants/TenantListPage"); + return html``; + }), + new Route(new RegExp("^/policy/policies$"), async () => { + await import("./pages/policies/PolicyListPage"); + return html``; + }), + new Route(new RegExp("^/policy/reputation$"), async () => { + await import("./pages/policies/reputation/ReputationListPage"); + return html``; + }), + new Route(new RegExp("^/identity/groups$"), async () => { + await import("./pages/groups/GroupListPage"); + return html``; + }), + new Route(new RegExp(`^/identity/groups/(?${UUID_REGEX})$`), async (args) => { + await import("./pages/groups/GroupViewPage"); return html``; }), - new Route(new RegExp("^/identity/users$"), html``), - new Route(new RegExp(`^/identity/users/(?${ID_REGEX})$`)).then((args) => { + new Route(new RegExp("^/identity/users$"), async () => { + await import("./pages/users/UserListPage"); + return html``; + }), + new Route(new RegExp(`^/identity/users/(?${ID_REGEX})$`), async (args) => { + await import("./pages/users/UserViewPage"); return html``; }), - new Route( - new RegExp("^/flow/stages/invitations$"), - html``, - ), - new Route( - new RegExp("^/flow/stages/prompts$"), - html``, - ), - new Route(new RegExp("^/flow/stages$"), html``), - new Route(new RegExp("^/flow/flows$"), html``), - new Route(new RegExp(`^/flow/flows/(?${SLUG_REGEX})$`)).then((args) => { + new Route(new RegExp("^/flow/stages/invitations$"), async () => { + await import("./pages/stages/invitation/InvitationListPage"); + return html``; + }), + new Route(new RegExp("^/flow/stages/prompts$"), async () => { + await import("./pages/stages/prompt/PromptListPage"); + return html``; + }), + new Route(new RegExp("^/flow/stages$"), async () => { + await import("./pages/stages/StageListPage"); + return html``; + }), + new Route(new RegExp("^/flow/flows$"), async () => { + await import("./pages/flows/FlowListPage"); + return html``; + }), + new Route(new RegExp(`^/flow/flows/(?${SLUG_REGEX})$`), async (args) => { + await import("./pages/flows/FlowViewPage"); return html``; }), - new Route(new RegExp("^/events/log$"), html``), - new Route(new RegExp(`^/events/log/(?${UUID_REGEX})$`)).then((args) => { + new Route(new RegExp("^/events/log$"), async () => { + await import("./pages/events/EventListPage"); + return html``; + }), + new Route(new RegExp(`^/events/log/(?${UUID_REGEX})$`), async (args) => { + await import("./pages/events/EventInfoPage"); return html``; }), - new Route( - new RegExp("^/events/transports$"), - html``, - ), - new Route(new RegExp("^/events/rules$"), html``), - new Route(new RegExp("^/outpost/outposts$"), html``), - new Route( - new RegExp("^/outpost/integrations$"), - html``, - ), - new Route( - new RegExp("^/crypto/certificates$"), - html``, - ), + new Route(new RegExp("^/events/transports$"), async () => { + await import("./pages/events/TransportListPage"); + return html``; + }), + new Route(new RegExp("^/events/rules$"), async () => { + await import("./pages/events/RuleListPage"); + return html``; + }), + new Route(new RegExp("^/outpost/outposts$"), async () => { + await import("./pages/outposts/OutpostListPage"); + return html``; + }), + new Route(new RegExp("^/outpost/integrations$"), async () => { + await import("./pages/outposts/ServiceConnectionListPage"); + return html``; + }), + new Route(new RegExp("^/crypto/certificates$"), async () => { + await import("./pages/crypto/CertificateKeyPairListPage"); + return html``; + }), ]; diff --git a/web/src/routesUser.ts b/web/src/routesUser.ts index 273588861..9e92f46dc 100644 --- a/web/src/routesUser.ts +++ b/web/src/routesUser.ts @@ -2,12 +2,14 @@ import { html } from "lit"; import { Route } from "./elements/router/Route"; import "./user/LibraryPage"; -import "./user/user-settings/UserSettingsPage"; export const ROUTES: Route[] = [ // Prevent infinite Shell loops new Route(new RegExp("^/$")).redirect("/library"), new Route(new RegExp("^#.*")).redirect("/library"), - new Route(new RegExp("^/library$"), html``), - new Route(new RegExp("^/settings$"), html``), + new Route(new RegExp("^/library$"), async () => html``), + new Route(new RegExp("^/settings$"), async () => { + await import("./user/user-settings/UserSettingsPage"); + return html``; + }), ];