wip: rename to authentik (#361)
* root: initial rename * web: rename custom element prefix * root: rename external functions with pb_ prefix * root: fix formatting * root: replace domain with goauthentik.io * proxy: update path * root: rename remaining prefixes * flows: rename file extension * root: pbadmin -> akadmin * docs: fix image filenames * lifecycle: ignore migration files * ci: copy default config from current source before loading last tagged * *: new sentry dsn * tests: fix missing python3.9-dev package * root: add additional migrations for service accounts created by outposts * core: mark system-created service accounts with attribute * policies/expression: fix pb_ replacement not working * web: fix last linting errors, add lit-analyse * policies/expressions: fix lint errors * web: fix sidebar display on screens where not all items fit * proxy: attempt to fix proxy pipeline * proxy: use go env GOPATH to get gopath * lib: fix user_default naming inconsistency * docs: add upgrade docs * docs: update screenshots to use authentik * admin: fix create button on empty-state of outpost * web: fix modal submit not refreshing SiteShell and Table * web: fix height of app-card and height of generic icon * web: fix rendering of subtext * admin: fix version check error not being caught * web: fix worker count not being shown * docs: update screenshots * root: new icon * web: fix lint error * admin: fix linting error * root: migrate coverage config to pyproject
| Before Width: | Height: | Size: 284 B After Width: | Height: | Size: 284 B | 
| Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB | 
| Before Width: | Height: | Size: 351 B After Width: | Height: | Size: 351 B | 
| Before Width: | Height: | Size: 402 B After Width: | Height: | Size: 402 B | 
| Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB | 
| Before Width: | Height: | Size: 543 B After Width: | Height: | Size: 543 B | 
| Before Width: | Height: | Size: 368 B After Width: | Height: | Size: 368 B | 
| Before Width: | Height: | Size: 878 B After Width: | Height: | Size: 878 B | 
| Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB | 
| @ -10,7 +10,7 @@ variables: | ||||
| stages: | ||||
|   - stage: lint | ||||
|     jobs: | ||||
|       - job: lint | ||||
|       - job: eslint | ||||
|         pool: | ||||
|           vmImage: 'ubuntu-latest' | ||||
|         steps: | ||||
| @ -27,6 +27,23 @@ stages: | ||||
|               command: 'custom' | ||||
|               workingDir: 'web/' | ||||
|               customCommand: 'run lint' | ||||
|       - job: lit_analyse | ||||
|         pool: | ||||
|           vmImage: 'ubuntu-latest' | ||||
|         steps: | ||||
|           - task: NodeTool@0 | ||||
|             inputs: | ||||
|               versionSpec: '12.x' | ||||
|             displayName: 'Install Node.js' | ||||
|           - task: Npm@1 | ||||
|             inputs: | ||||
|               command: 'install' | ||||
|               workingDir: 'web/' | ||||
|           - task: Npm@1 | ||||
|             inputs: | ||||
|               command: 'custom' | ||||
|               workingDir: 'web/' | ||||
|               customCommand: 'run lit-analyse' | ||||
|   - stage: build_local | ||||
|     jobs: | ||||
|       - job: build | ||||
| @ -55,7 +72,7 @@ stages: | ||||
|         - task: Docker@2 | ||||
|           inputs: | ||||
|             containerRegistry: 'dockerhub' | ||||
|             repository: 'beryju/passbook-static' | ||||
|             repository: 'beryju/authentik-static' | ||||
|             command: 'buildAndPush' | ||||
|             Dockerfile: 'web/Dockerfile' | ||||
|             tags: "gh-${{ variables.branchName }}" | ||||
|  | ||||
| @ -14,8 +14,9 @@ const resources = [ | ||||
|     { src: "node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css", dest: "dist/" }, | ||||
|     { src: "node_modules/@patternfly/patternfly/assets/*", dest: "dist/assets/" }, | ||||
|     { src: "src/index.html", dest: "dist" }, | ||||
|     { src: "src/passbook.css", dest: "dist" }, | ||||
|     { src: "src/authentik.css", dest: "dist" }, | ||||
|     { src: "src/assets/*", dest: "dist/assets" }, | ||||
|     { src: "../icons/*", dest: "dist/assets/icons" }, | ||||
| ]; | ||||
|  | ||||
| export default [ | ||||
|  | ||||
| @ -19,13 +19,13 @@ export class Config { | ||||
|         return DefaultClient.fetch<Config>(["root", "config"]).then((config) => { | ||||
|             if (config.error_reporting_enabled) { | ||||
|                 Sentry.init({ | ||||
|                     dsn: "https://33cdbcb23f8b436dbe0ee06847410b67@sentry.beryju.org/3", | ||||
|                     release: `passbook@${VERSION}`, | ||||
|                     dsn: "https://a579bb09306d4f8b8d8847c052d3a1d3@sentry.beryju.org/8", | ||||
|                     release: `authentik@${VERSION}`, | ||||
|                     integrations: [new Integrations.BrowserTracing()], | ||||
|                     tracesSampleRate: 1.0, | ||||
|                     environment: config.error_reporting_environment, | ||||
|                 }); | ||||
|                 console.debug("passbook/config: Sentry enabled."); | ||||
|                 console.debug("authentik/config: Sentry enabled."); | ||||
|             } | ||||
|             return config; | ||||
|         }); | ||||
|  | ||||
| Before Width: | Height: | Size: 11 KiB | 
| @ -1,55 +0,0 @@ | ||||
| <?xml version="1.0" encoding="iso-8859-1"?> | ||||
| <!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve"> | ||||
| <path style="fill:#57565C;" d="M407,512H105C47.103,512,0,464.897,0,407V105C0,47.103,47.103,0,105,0h302 | ||||
| 	c57.897,0,105,47.103,105,105v302C512,464.897,464.897,512,407,512z"/> | ||||
| <path style="fill:#3E3D42;" d="M407,0H256v512h151c57.897,0,105-47.103,105-105V105C512,47.103,464.897,0,407,0z"/> | ||||
| <rect x="91" y="141" style="fill:#00C3FF;" width="330" height="44"/> | ||||
| <rect x="256" y="141" style="fill:#00AAF0;" width="165" height="44"/> | ||||
| <rect x="91" y="176" style="fill:#FFDC40;" width="330" height="44"/> | ||||
| <rect x="256" y="176" style="fill:#FFAB15;" width="165" height="44"/> | ||||
| <rect x="91" y="206" style="fill:#87E694;" width="330" height="44"/> | ||||
| <rect x="256" y="206" style="fill:#66CC70;" width="165" height="44"/> | ||||
| <path style="fill:#F2F2F2;" d="M421,381c0,8.284-6.716,15-15,15H106c-8.284,0-15-6.716-15-15v-85h89.997 | ||||
| 	c9.31,0,17.688,4.938,21.868,12.888C213.277,328.695,233.638,341,256,341s42.723-12.305,53.135-32.111 | ||||
| 	c4.18-7.95,12.559-12.889,21.868-12.889H421V381z"/> | ||||
| <path style="fill:#FF6849;" d="M421,266h-89.997c-20.487,0-39.041,11.085-48.423,28.929C277.369,304.842,267.185,311,256,311 | ||||
| 	s-21.369-6.158-26.58-16.071C220.038,277.085,201.484,266,180.997,266H91v-30h330V266z"/> | ||||
| <path style="fill:#F2F2F2;" d="M421,146H91v-15c0-8.284,6.716-15,15-15h300c8.284,0,15,6.716,15,15V146z"/> | ||||
| <path style="fill:#E5E5E5;" d="M331.003,296c-9.31,0-17.688,4.938-21.868,12.889C298.723,328.695,278.362,341,256,341v55h150 | ||||
| 	c8.284,0,15-6.716,15-15v-85H331.003z"/> | ||||
| <path style="fill:#FD4B2D;" d="M256,236v75c11.185,0,21.369-6.158,26.58-16.071C291.962,277.085,310.516,266,331.003,266H421v-30 | ||||
| 	H256z"/> | ||||
| <path style="fill:#E5E5E5;" d="M406,116H256v30h165v-15C421,122.716,414.284,116,406,116z"/> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| </svg> | ||||
| Before Width: | Height: | Size: 2.2 KiB | 
| Before Width: | Height: | Size: 68 B After Width: | Height: | Size: 68 B | 
| @ -1,12 +1,3 @@ | ||||
| @font-face { | ||||
|     font-family: "DIN 1451 Std"; | ||||
|     src: url("assets/fonts/DINEngschriftStd.woff2") format("woff2"), | ||||
|         url("assets/fonts/DINEngschriftStd.woff") format("woff"); | ||||
|     font-weight: normal; | ||||
|     font-style: normal; | ||||
|     font-display: swap; | ||||
| } | ||||
| 
 | ||||
| html { | ||||
|     --pf-c-nav__link--PaddingTop: 0.5rem; | ||||
|     --pf-c-nav__link--PaddingRight: 0.5rem; | ||||
| @ -14,25 +5,6 @@ html { | ||||
|     --pf-c-nav__link--PaddingLeft: 0.5rem; | ||||
| } | ||||
| 
 | ||||
| .pb-brand { | ||||
|     font-family: "DIN 1451 Std"; | ||||
|     font-size: 4em; | ||||
|     display: flex; | ||||
|     flex-direction: row; | ||||
|     align-items: center; | ||||
|     margin-right: 0.5em; | ||||
|     color: var(--pf-global--Color--light-200); | ||||
| } | ||||
| 
 | ||||
| .pb-brand > a:hover { | ||||
|     text-decoration: none; | ||||
| } | ||||
| 
 | ||||
| .pb-brand > img { | ||||
|     max-height: 68px; | ||||
|     margin-right: 0.5em; | ||||
| } | ||||
| 
 | ||||
| /* Fix patternfly sidebar and header with open Modal */ | ||||
| .pf-c-page__sidebar { | ||||
|     z-index: 0; | ||||
| @ -81,15 +53,15 @@ select[multiple] { | ||||
|     line-height: var(--pf-global--spacer--xl); | ||||
| } | ||||
| 
 | ||||
| /* Static OTP Tokens, passbook.stages.otp_static */ | ||||
| .pb-otp-tokens { | ||||
| /* Static OTP Tokens, authentik.stages.otp_static */ | ||||
| .ak-otp-tokens { | ||||
|     list-style: circle; | ||||
|     columns: 2; | ||||
|     -webkit-columns: 2; | ||||
|     -moz-columns: 2; | ||||
|     margin-left: var(--pf-global--spacer--xs); | ||||
| } | ||||
| .pb-otp-tokens li { | ||||
| .ak-otp-tokens li { | ||||
|     font-size: var(--pf-global--FontSize--2xl); | ||||
|     font-family: monospace; | ||||
| } | ||||
| @ -109,3 +81,7 @@ select[multiple] { | ||||
| .pf-c-content h1 :first-child { | ||||
|     margin-right: var(--pf-global--spacer--sm); | ||||
| } | ||||
| 
 | ||||
| .subtext { | ||||
|     font-size: var(--pf-global--FontSize--sm); | ||||
| } | ||||
| @ -5,7 +5,7 @@ import PFAddons from "@patternfly/patternfly/patternfly-addons.css"; | ||||
| // @ts-ignore | ||||
| import FA from "@fortawesome/fontawesome-free/css/fontawesome.css"; | ||||
| // @ts-ignore | ||||
| import PBGlobal from "../passbook.css"; | ||||
| import PBGlobal from "../authentik.css"; | ||||
| import { CSSResult } from "lit-element"; | ||||
|  | ||||
| export const COMMON_STYLES: CSSResult[] = [PF, PFAddons, FA, PBGlobal]; | ||||
|  | ||||
| @ -6,7 +6,7 @@ interface TickValue { | ||||
|     major: boolean; | ||||
| } | ||||
|  | ||||
| @customElement("pb-admin-logins-chart") | ||||
| @customElement("ak-admin-logins-chart") | ||||
| export class AdminLoginsChart extends LitElement { | ||||
|     @property() | ||||
|     url = ""; | ||||
|  | ||||
| @ -7,7 +7,7 @@ import "codemirror/mode/xml/xml.js"; | ||||
| import "codemirror/mode/yaml/yaml.js"; | ||||
| import "codemirror/mode/python/python.js"; | ||||
|  | ||||
| @customElement("pb-codemirror") | ||||
| @customElement("ak-codemirror") | ||||
| export class CodeMirrorTextarea extends LitElement { | ||||
|     @property({type: Boolean}) | ||||
|     readOnly = false; | ||||
|  | ||||
| @ -18,7 +18,7 @@ interface Message { | ||||
|     message: string; | ||||
| } | ||||
|  | ||||
| @customElement("pb-messages") | ||||
| @customElement("ak-messages") | ||||
| export class Messages extends LitElement { | ||||
|     url = DefaultClient.makeUrl(["root", "messages"]); | ||||
|  | ||||
| @ -34,7 +34,7 @@ export class Messages extends LitElement { | ||||
|         try { | ||||
|             this.connect(); | ||||
|         } catch (error) { | ||||
|             console.warn(`passbook/messages: failed to connect to ws ${error}`); | ||||
|             console.warn(`authentik/messages: failed to connect to ws ${error}`); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -48,12 +48,12 @@ export class Messages extends LitElement { | ||||
|         }/ws/client/`; | ||||
|         this.messageSocket = new WebSocket(wsUrl); | ||||
|         this.messageSocket.addEventListener("open", () => { | ||||
|             console.debug(`passbook/messages: connected to ${wsUrl}`); | ||||
|             console.debug(`authentik/messages: connected to ${wsUrl}`); | ||||
|         }); | ||||
|         this.messageSocket.addEventListener("close", (e) => { | ||||
|             console.debug(`passbook/messages: closed ws connection: ${e}`); | ||||
|             console.debug(`authentik/messages: closed ws connection: ${e}`); | ||||
|             setTimeout(() => { | ||||
|                 console.debug(`passbook/messages: reconnecting ws in ${this.retryDelay}ms`); | ||||
|                 console.debug(`authentik/messages: reconnecting ws in ${this.retryDelay}ms`); | ||||
|                 this.connect(); | ||||
|             }, this.retryDelay); | ||||
|             this.retryDelay = this.retryDelay * 2; | ||||
| @ -63,7 +63,7 @@ export class Messages extends LitElement { | ||||
|             this.renderMessage(data); | ||||
|         }); | ||||
|         this.messageSocket.addEventListener("error", (e) => { | ||||
|             console.warn(`passbook/messages: error ${e}`); | ||||
|             console.warn(`authentik/messages: error ${e}`); | ||||
|             this.retryDelay = this.retryDelay * 2; | ||||
|         }); | ||||
|     } | ||||
| @ -72,7 +72,7 @@ export class Messages extends LitElement { | ||||
|      * This mostly gets messages which were created when the user arrives/leaves the site | ||||
|      * and especially the login flow */ | ||||
|     fetchMessages(): Promise<void> { | ||||
|         console.debug("passbook/messages: fetching messages over direct api"); | ||||
|         console.debug("authentik/messages: fetching messages over direct api"); | ||||
|         return fetch(this.url) | ||||
|             .then((r) => r.json()) | ||||
|             .then((r: Message[]) => { | ||||
| @ -85,10 +85,10 @@ export class Messages extends LitElement { | ||||
|     renderMessage(message: Message): void { | ||||
|         const container = <HTMLElement>this.querySelector(".pf-c-alert-group"); | ||||
|         if (!container) { | ||||
|             console.warn("passbook/messages: failed to find container"); | ||||
|             console.warn("authentik/messages: failed to find container"); | ||||
|             return; | ||||
|         } | ||||
|         const id = ID("pb-message"); | ||||
|         const id = ID("ak-message"); | ||||
|         const el = document.createElement("template"); | ||||
|         el.innerHTML = `<li id=${id} class="pf-c-alert-group__item"> | ||||
|             <div class="pf-c-alert pf-m-${message.level_tag} ${message.level_tag === "error" ? "pf-m-danger" : ""}"> | ||||
|  | ||||
| @ -10,7 +10,7 @@ export enum SpinnerSize { | ||||
|     XLarge = "pf-m-xl", | ||||
| } | ||||
|  | ||||
| @customElement("pb-spinner") | ||||
| @customElement("ak-spinner") | ||||
| export class Spinner extends LitElement { | ||||
|     @property() | ||||
|     size: SpinnerSize = SpinnerSize.Medium; | ||||
|  | ||||
| @ -5,8 +5,9 @@ import TabsStyle from "@patternfly/patternfly/components/Tabs/tabs.css"; | ||||
| // @ts-ignore | ||||
| import GlobalsStyle from "@patternfly/patternfly/base/patternfly-globals.css"; | ||||
| import { CURRENT_CLASS } from "../constants"; | ||||
| import { gettext } from "django"; | ||||
|  | ||||
| @customElement("pb-tabs") | ||||
| @customElement("ak-tabs") | ||||
| export class Tabs extends LitElement { | ||||
|     @property() | ||||
|     currentPage?: string; | ||||
| @ -20,7 +21,7 @@ export class Tabs extends LitElement { | ||||
|         return html` <li class="pf-c-tabs__item ${slot === this.currentPage ? CURRENT_CLASS : ""}"> | ||||
|             <button class="pf-c-tabs__link" @click=${() => { this.currentPage = slot; }}> | ||||
|                 <span class="pf-c-tabs__item-text"> | ||||
|                     ${page.attributes.getNamedItem("tab-title")?.value} | ||||
|                     ${page.getAttribute("data-tab-title")} | ||||
|                 </span> | ||||
|             </button> | ||||
|         </li>`; | ||||
| @ -30,7 +31,7 @@ export class Tabs extends LitElement { | ||||
|         const pages = Array.from(this.querySelectorAll("[slot]")); | ||||
|         if (!this.currentPage) { | ||||
|             if (pages.length < 1) { | ||||
|                 return html`<h1>no tabs defined</h1>`; | ||||
|                 return html`<h1>${gettext("no tabs defined")}</h1>`; | ||||
|             } | ||||
|             this.currentPage = pages[0].attributes.getNamedItem("slot")?.value; | ||||
|         } | ||||
|  | ||||
| @ -3,7 +3,7 @@ import { customElement, property } from "lit-element"; | ||||
| import { ERROR_CLASS, SUCCESS_CLASS } from "../../constants"; | ||||
| import { SpinnerButton } from "./SpinnerButton"; | ||||
|  | ||||
| @customElement("pb-action-button") | ||||
| @customElement("ak-action-button") | ||||
| export class ActionButton extends SpinnerButton { | ||||
|     @property() | ||||
|     url = ""; | ||||
| @ -13,7 +13,7 @@ export class ActionButton extends SpinnerButton { | ||||
|             return; | ||||
|         } | ||||
|         this.setLoading(); | ||||
|         const csrftoken = getCookie("passbook_csrf"); | ||||
|         const csrftoken = getCookie("authentik_csrf"); | ||||
|         if (!csrftoken) { | ||||
|             console.debug("No csrf token in cookie"); | ||||
|             this.setDone(ERROR_CLASS); | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| import { customElement, html, LitElement, TemplateResult } from "lit-element"; | ||||
|  | ||||
| @customElement("pb-dropdown") | ||||
| @customElement("ak-dropdown") | ||||
| export class DropdownButton extends LitElement { | ||||
|     constructor() { | ||||
|         super(); | ||||
|  | ||||
| @ -14,7 +14,7 @@ import { convertToSlug } from "../../utils"; | ||||
| import { SpinnerButton } from "./SpinnerButton"; | ||||
| import { PRIMARY_CLASS } from "../../constants"; | ||||
|  | ||||
| @customElement("pb-modal-button") | ||||
| @customElement("ak-modal-button") | ||||
| export class ModalButton extends LitElement { | ||||
|     @property() | ||||
|     href?: string; | ||||
| @ -92,17 +92,17 @@ export class ModalButton extends LitElement { | ||||
|                         if (data.indexOf("csrfmiddlewaretoken") !== -1) { | ||||
|                             const modalSlot = this.querySelector("[slot=modal]"); | ||||
|                             if (!modalSlot) { | ||||
|                                 console.debug("passbook/modalbutton: modal slot not found?"); | ||||
|                                 console.debug("authentik/modalbutton: modal slot not found?"); | ||||
|                                 return; | ||||
|                             } | ||||
|                             modalSlot.innerHTML = data; | ||||
|                             console.debug("passbook/modalbutton: re-showing form"); | ||||
|                             console.debug("authentik/modalbutton: re-showing form"); | ||||
|                             this.updateHandlers(); | ||||
|                         } else { | ||||
|                             this.open = false; | ||||
|                             console.debug("passbook/modalbutton: successful submit"); | ||||
|                             console.debug("authentik/modalbutton: successful submit"); | ||||
|                             this.dispatchEvent( | ||||
|                                 new CustomEvent("hashchange", { | ||||
|                                 new CustomEvent("ak-refresh", { | ||||
|                                     bubbles: true, | ||||
|                                 }) | ||||
|                             ); | ||||
| @ -133,7 +133,7 @@ export class ModalButton extends LitElement { | ||||
|                     modalSlot.innerHTML = t; | ||||
|                     this.updateHandlers(); | ||||
|                     this.open = true; | ||||
|                     this.querySelectorAll<SpinnerButton>("pb-spinner-button").forEach((sb) => { | ||||
|                     this.querySelectorAll<SpinnerButton>("ak-spinner-button").forEach((sb) => { | ||||
|                         sb.setDone(PRIMARY_CLASS); | ||||
|                     }); | ||||
|                 }) | ||||
|  | ||||
| @ -7,7 +7,7 @@ import ButtonStyle from "@patternfly/patternfly/components/Button/button.css"; | ||||
| import SpinnerStyle from "@patternfly/patternfly/components/Spinner/spinner.css"; | ||||
| import { ColorStyles, PRIMARY_CLASS, PROGRESS_CLASS } from "../../constants"; | ||||
|  | ||||
| @customElement("pb-spinner-button") | ||||
| @customElement("ak-spinner-button") | ||||
| export class SpinnerButton extends LitElement { | ||||
|     @property({type: Boolean}) | ||||
|     isRunning = false; | ||||
|  | ||||
| @ -6,7 +6,7 @@ import ButtonStyle from "@patternfly/patternfly/components/Button/button.css"; | ||||
| import { tokenByIdentifier } from "../../api/token"; | ||||
| import { ColorStyles, ERROR_CLASS, PRIMARY_CLASS, SUCCESS_CLASS } from "../../constants"; | ||||
|  | ||||
| @customElement("pb-token-copy-button") | ||||
| @customElement("ak-token-copy-button") | ||||
| export class TokenCopyButton extends LitElement { | ||||
|     @property() | ||||
|     identifier?: string; | ||||
|  | ||||
| @ -3,7 +3,7 @@ import { css, CSSResult, customElement, html, LitElement, property, TemplateResu | ||||
| import { ifDefined } from "lit-html/directives/if-defined"; | ||||
| import { COMMON_STYLES } from "../../common/styles"; | ||||
|  | ||||
| @customElement("pb-aggregate-card") | ||||
| @customElement("ak-aggregate-card") | ||||
| export class AggregateCard extends LitElement { | ||||
|     @property() | ||||
|     icon?: string; | ||||
| @ -20,9 +20,6 @@ export class AggregateCard extends LitElement { | ||||
|                 font-size: var(--pf-global--icon--FontSize--lg); | ||||
|                 text-align: center; | ||||
|             } | ||||
|             .subtext { | ||||
|                 font-size: var(--pf-global--FontSize--sm); | ||||
|             } | ||||
|         `]); | ||||
|     } | ||||
|  | ||||
|  | ||||
| @ -4,7 +4,7 @@ import { AggregateCard } from "./AggregateCard"; | ||||
| import "../Spinner"; | ||||
| import { SpinnerSize } from "../Spinner"; | ||||
|  | ||||
| @customElement("pb-aggregate-card-promise") | ||||
| @customElement("ak-aggregate-card-promise") | ||||
| export class AggregatePromiseCard extends AggregateCard { | ||||
|     @property({attribute: false}) | ||||
|     promise?: Promise<Record<string, unknown>>; | ||||
| @ -20,7 +20,7 @@ export class AggregatePromiseCard extends AggregateCard { | ||||
|  | ||||
|     renderInner(): TemplateResult { | ||||
|         return html`<p class="center-value"> | ||||
|             ${until(this.promiseProxy(), html`<pb-spinner size="${SpinnerSize.Large}"></pb-spinner>`)} | ||||
|             ${until(this.promiseProxy(), html`<ak-spinner size="${SpinnerSize.Large}"></ak-spinner>`)} | ||||
|         </p>`; | ||||
|     } | ||||
|  | ||||
|  | ||||
| @ -18,7 +18,7 @@ export interface SidebarItem { | ||||
|     condition?: () => Promise<boolean>; | ||||
| } | ||||
|  | ||||
| @customElement("pb-sidebar") | ||||
| @customElement("ak-sidebar") | ||||
| export class Sidebar extends LitElement { | ||||
|     @property({attribute: false}) | ||||
|     items: SidebarItem[] = []; | ||||
| @ -36,6 +36,18 @@ export class Sidebar extends LitElement { | ||||
|                     max-height: 82px; | ||||
|                     margin-bottom: -0.5rem; | ||||
|                 } | ||||
|                 nav { | ||||
|                     display: flex; | ||||
|                     flex-direction: column; | ||||
|                     max-height: 100vh; | ||||
|                     height: 100%; | ||||
|                     overflow-y: hidden; | ||||
|                 } | ||||
|                 .pf-c-nav__list { | ||||
|                     flex-grow: 1; | ||||
|                     overflow-y: auto; | ||||
|                 } | ||||
|  | ||||
|                 .pf-c-nav__link { | ||||
|                     --pf-c-nav__link--PaddingTop: 0.5rem; | ||||
|                     --pf-c-nav__link--PaddingRight: 0.5rem; | ||||
| @ -44,12 +56,6 @@ export class Sidebar extends LitElement { | ||||
|                 .pf-c-nav__subnav { | ||||
|                     --pf-c-nav__subnav--PaddingBottom: 0px; | ||||
|                 } | ||||
|  | ||||
|                 .pf-c-nav__item-bottom { | ||||
|                     position: absolute; | ||||
|                     bottom: 0; | ||||
|                     width: 100%; | ||||
|                 } | ||||
|             `, | ||||
|         ]; | ||||
|     } | ||||
| @ -89,18 +95,12 @@ export class Sidebar extends LitElement { | ||||
|     } | ||||
|  | ||||
|     render(): TemplateResult { | ||||
|         return html`<div class="pf-c-page__sidebar-body"> | ||||
|             <nav class="pf-c-nav" aria-label="Global"> | ||||
|                 <ul class="pf-c-nav__list"> | ||||
|                     <li class="pf-c-nav__item sidebar-brand"> | ||||
|                         <pb-sidebar-brand></pb-sidebar-brand> | ||||
|                     </li> | ||||
|                     ${this.items.map((i) => until(this.renderItem(i), html``))} | ||||
|                     <li class="pf-c-nav__item pf-c-nav__item-bottom"> | ||||
|                         <pb-sidebar-user></pb-sidebar-user> | ||||
|                     </li> | ||||
|                 </ul> | ||||
|             </nav> | ||||
|         </div>`; | ||||
|         return html`<nav class="pf-c-nav" aria-label="Global"> | ||||
|             <ak-sidebar-brand></ak-sidebar-brand> | ||||
|             <ul class="pf-c-nav__list"> | ||||
|                 ${this.items.map((i) => until(this.renderItem(i), html``))} | ||||
|             </ul> | ||||
|             <ak-sidebar-user></ak-sidebar-user> | ||||
|         </nav>`; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -6,15 +6,15 @@ import GlobalsStyle from "@patternfly/patternfly/base/patternfly-globals.css"; | ||||
| import { Config } from "../../api/config"; | ||||
|  | ||||
| export const DefaultConfig: Config = { | ||||
|     branding_logo: " /static/dist/assets/images/logo.svg", | ||||
|     branding_title: "passbook", | ||||
|     branding_logo: " /static/dist/assets/icons/icon_left_brand.svg", | ||||
|     branding_title: "authentik", | ||||
|  | ||||
|     error_reporting_enabled: false, | ||||
|     error_reporting_environment: "", | ||||
|     error_reporting_send_pii: false, | ||||
| }; | ||||
|  | ||||
| @customElement("pb-sidebar-brand") | ||||
| @customElement("ak-sidebar-brand") | ||||
| export class SidebarBrand extends LitElement { | ||||
|     @property({attribute: false}) | ||||
|     config: Config = DefaultConfig; | ||||
| @ -24,41 +24,28 @@ export class SidebarBrand extends LitElement { | ||||
|             GlobalsStyle, | ||||
|             PageStyle, | ||||
|             css` | ||||
|                 .pf-c-brand { | ||||
|                     font-family: "DIN 1451 Std"; | ||||
|                     line-height: 60px; | ||||
|                     font-size: 3rem; | ||||
|                     color: var(--pf-c-nav__link--m-current--Color); | ||||
|                 :host { | ||||
|                     display: flex; | ||||
|                     flex-direction: row; | ||||
|                     justify-content: center; | ||||
|                     width: 100%; | ||||
|                     margin: 0 1rem; | ||||
|                     margin-bottom: 1.5rem; | ||||
|                     flex-direction: column; | ||||
|                     align-items: center; | ||||
|                     height: 82px; | ||||
|                 } | ||||
|                 .pf-c-brand img { | ||||
|                     max-height: 60px; | ||||
|                     margin-right: 8px; | ||||
|                     width: 100%; | ||||
|                     padding: 0 .5rem; | ||||
|                 } | ||||
|             `, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     constructor() { | ||||
|         super(); | ||||
|     firstUpdated(): void { | ||||
|         Config.get().then((c) => (this.config = c)); | ||||
|     } | ||||
|  | ||||
|     render(): TemplateResult { | ||||
|         if (!this.config) { | ||||
|             return html``; | ||||
|         } | ||||
|         return html` <a href="#/" class="pf-c-page__header-brand-link"> | ||||
|             <div class="pf-c-brand pb-brand"> | ||||
|                 <img src="${this.config.branding_logo}" alt="passbook icon" loading="lazy" /> | ||||
|                 ${this.config.branding_title | ||||
|         ? html`<span>${this.config.branding_title}</span>` | ||||
|         : ""} | ||||
|             <div class="pf-c-brand ak-brand"> | ||||
|                 <img src="${this.config.branding_logo}" alt="authentik icon" loading="lazy" /> | ||||
|             </div> | ||||
|         </a>`; | ||||
|     } | ||||
|  | ||||
| @ -8,7 +8,7 @@ import AvatarStyle from "@patternfly/patternfly/components/Avatar/avatar.css"; | ||||
| import { User } from "../../api/user"; | ||||
| import { until } from "lit-html/directives/until"; | ||||
|  | ||||
| @customElement("pb-sidebar-user") | ||||
| @customElement("ak-sidebar-user") | ||||
| export class SidebarUser extends LitElement { | ||||
|     static get styles(): CSSResult[] { | ||||
|         return [ | ||||
|  | ||||
| @ -21,6 +21,13 @@ export abstract class Table<T> extends LitElement { | ||||
|         return COMMON_STYLES; | ||||
|     } | ||||
|  | ||||
|     constructor() { | ||||
|         super(); | ||||
|         this.addEventListener("ak-refresh", () => { | ||||
|             this.fetch(); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     public fetch(): void { | ||||
|         this.apiEndpoint(this.page).then((r) => { | ||||
|             this.data = r; | ||||
| @ -74,15 +81,15 @@ export abstract class Table<T> extends LitElement { | ||||
|                         <slot name="create-button"></slot> | ||||
|                         <button | ||||
|                             @click=${() => {this.fetch();}} | ||||
|                             class="pf-c-button pf-m-primary" | ||||
|                         > | ||||
|                             class="pf-c-button pf-m-primary"> | ||||
|                             ${gettext("Refresh")} | ||||
|                         </button> | ||||
|                     </div> | ||||
|                     <pb-table-pagination | ||||
|                     <ak-table-pagination | ||||
|                         class="pf-c-toolbar__item pf-m-pagination" | ||||
|                         .table=${this} | ||||
|                     ></pb-table-pagination> | ||||
|                         .pages=${this.data?.pagination} | ||||
|                         .pageChangeHandler=${(page: number) => {this.page = page; }}> | ||||
|                     </ak-table-pagination> | ||||
|                 </div> | ||||
|             </div> | ||||
|             <table class="pf-c-table pf-m-compact pf-m-grid-md"> | ||||
| @ -96,10 +103,11 @@ export abstract class Table<T> extends LitElement { | ||||
|                 </tbody> | ||||
|             </table> | ||||
|             <div class="pf-c-pagination pf-m-bottom"> | ||||
|                 <pb-table-pagination | ||||
|                 <ak-table-pagination | ||||
|                     class="pf-c-toolbar__item pf-m-pagination" | ||||
|                     .table=${this} | ||||
|                 ></pb-table-pagination> | ||||
|                     .pages=${this.data?.pagination} | ||||
|                     .pageChangeHandler=${(page: number) => { this.page = page; }}> | ||||
|                 </ak-table-pagination> | ||||
|             </div>`; | ||||
|     } | ||||
|  | ||||
|  | ||||
| @ -1,41 +1,29 @@ | ||||
| import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; | ||||
| import { Table } from "./Table"; | ||||
| import { COMMON_STYLES } from "../../common/styles"; | ||||
| import { PBPagination } from "../../api/client"; | ||||
|  | ||||
| @customElement("pb-table-pagination") | ||||
| @customElement("ak-table-pagination") | ||||
| export class TablePagination extends LitElement { | ||||
|     @property({attribute: false}) | ||||
|     table?: Table<unknown>; | ||||
|     pages?: PBPagination; | ||||
|  | ||||
|     @property({attribute: false}) | ||||
|     // eslint-disable-next-line | ||||
|     pageChangeHandler: (page: number) => void = (page: number) => {} | ||||
|  | ||||
|     static get styles(): CSSResult[] { | ||||
|         return COMMON_STYLES; | ||||
|     } | ||||
|  | ||||
|     previousHandler(): void { | ||||
|         if (!this.table?.data?.pagination.previous) { | ||||
|             console.debug("passbook/tables: no previous"); | ||||
|             return; | ||||
|         } | ||||
|         this.table.page = this.table?.data?.pagination.previous; | ||||
|     } | ||||
|  | ||||
|     nextHandler(): void { | ||||
|         if (!this.table?.data?.pagination.next) { | ||||
|             console.debug("passbook/tables: no next"); | ||||
|             return; | ||||
|         } | ||||
|         this.table.page = this.table?.data?.pagination.next; | ||||
|     } | ||||
|  | ||||
|     render(): TemplateResult { | ||||
|         return html` <div class="pf-c-pagination pf-m-compact pf-m-hidden pf-m-visible-on-md"> | ||||
|             <div class="pf-c-pagination pf-m-compact pf-m-compact pf-m-hidden pf-m-visible-on-md"> | ||||
|                 <div class="pf-c-options-menu"> | ||||
|                     <div class="pf-c-options-menu__toggle pf-m-text pf-m-plain"> | ||||
|                         <span class="pf-c-options-menu__toggle-text"> | ||||
|                             ${this.table?.data?.pagination.start_index} - | ||||
|                             ${this.table?.data?.pagination.end_index} of | ||||
|                             ${this.table?.data?.pagination.count} | ||||
|                             ${this.pages?.start_index} - | ||||
|                             ${this.pages?.end_index} of | ||||
|                             ${this.pages?.count} | ||||
|                         </span> | ||||
|                     </div> | ||||
|                 </div> | ||||
| @ -43,8 +31,8 @@ export class TablePagination extends LitElement { | ||||
|                     <div class="pf-c-pagination__nav-control pf-m-prev"> | ||||
|                         <button | ||||
|                             class="pf-c-button pf-m-plain" | ||||
|                             @click=${() => {this.previousHandler();}} | ||||
|                             ?disabled="${(this.table?.data?.pagination.previous || 0) > 0}" | ||||
|                             @click=${() => { this.pageChangeHandler(this.pages?.previous || 0); }} | ||||
|                             ?disabled="${(this.pages?.previous || 0) > 0}" | ||||
|                             aria-label="{% trans 'Go to previous page' %}" | ||||
|                         > | ||||
|                             <i class="fas fa-angle-left" aria-hidden="true"></i> | ||||
| @ -53,8 +41,8 @@ export class TablePagination extends LitElement { | ||||
|                     <div class="pf-c-pagination__nav-control pf-m-next"> | ||||
|                         <button | ||||
|                             class="pf-c-button pf-m-plain" | ||||
|                             @click=${() => {this.nextHandler();}} | ||||
|                             ?disabled="${(this.table?.data?.pagination.next || 0) > 0}" | ||||
|                             @click=${() => { this.pageChangeHandler(this.pages?.next || 0); }} | ||||
|                             ?disabled="${(this.pages?.next || 0) > 0}" | ||||
|                             aria-label="{% trans 'Go to next page' %}" | ||||
|                         > | ||||
|                             <i class="fas fa-angle-right" aria-hidden="true"></i> | ||||
|  | ||||
| @ -3,23 +3,23 @@ | ||||
|     <head> | ||||
|         <link | ||||
|             rel="preload" | ||||
|             href="/static/passbook/fonts/DINEngschriftStd.woff2" | ||||
|             href="/static/authentik/fonts/DINEngschriftStd.woff2" | ||||
|             as="font" | ||||
|             type="font/woff2" | ||||
|             crossorigin | ||||
|         /> | ||||
|         <link | ||||
|             rel="preload" | ||||
|             href="/static/passbook/fonts/DINEngschriftStd.woff" | ||||
|             href="/static/authentik/fonts/DINEngschriftStd.woff" | ||||
|             as="font" | ||||
|             type="font/woff" | ||||
|             crossorigin | ||||
|         /> | ||||
|         <meta charset="UTF-8" /> | ||||
|         <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> | ||||
|         <title>passbook</title> | ||||
|         <link rel="icon" type="image/png" href="/static/dist/assets/images/logo.png" /> | ||||
|         <link rel="shortcut icon" type="image/png" href="/static/dist/assets/images/logo.png" /> | ||||
|         <title>authentik</title> | ||||
|         <link rel="icon" type="image/png" href="/static/dist/assets/icons/icon.png" /> | ||||
|         <link rel="shortcut icon" type="image/png" href="/static/dist/assets/icons/icon.png" /> | ||||
|         <link | ||||
|             rel="stylesheet" | ||||
|             type="text/css" | ||||
| @ -35,24 +35,24 @@ | ||||
|             type="text/css" | ||||
|             href="/static/node_modules/%40fortawesome/fontawesome-free/css/fontawesome.min.css" | ||||
|         /> | ||||
|         <link rel="stylesheet" type="text/css" href="/static/passbook/passbook.css" /> | ||||
|         <link rel="stylesheet" type="text/css" href="/static/authentik/authentik.css" /> | ||||
|         <script src="/static/dist/main.js" type="module"></script> | ||||
|     </head> | ||||
|     <body> | ||||
|         <pb-messages url="/api/v2beta/root/messages/"></pb-messages> | ||||
|         <ak-messages url="/api/v2beta/root/messages/"></ak-messages> | ||||
|         <div class="pf-c-page"> | ||||
|             <a class="pf-c-skip-to-content pf-c-button pf-m-primary" href="#main-content" | ||||
|                 >Skip to content</a | ||||
|             > | ||||
|             <pb-sidebar class="pf-c-page__sidebar"> </pb-sidebar> | ||||
|             <pb-router-outlet | ||||
|             <ak-sidebar class="pf-c-page__sidebar"> </ak-sidebar> | ||||
|             <ak-router-outlet | ||||
|                 role="main" | ||||
|                 class="pf-c-page__main" | ||||
|                 tabindex="-1" | ||||
|                 id="main-content" | ||||
|                 defaultUrl="/library/" | ||||
|             > | ||||
|             </pb-router-outlet> | ||||
|             </ak-router-outlet> | ||||
|         </div> | ||||
|     </body> | ||||
| </html> | ||||
|  | ||||
| @ -117,7 +117,7 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [ | ||||
|     }, | ||||
| ]; | ||||
|  | ||||
| @customElement("pb-interface-admin") | ||||
| @customElement("ak-interface-admin") | ||||
| export class AdminInterface extends Interface { | ||||
|  | ||||
|     get sidebar(): SidebarItem[] { | ||||
|  | ||||
| @ -14,14 +14,14 @@ export abstract class Interface extends LitElement { | ||||
|     } | ||||
|  | ||||
|     render(): TemplateResult { | ||||
|         return html`<pb-messages></pb-messages> | ||||
|         return html`<ak-messages></ak-messages> | ||||
|             <div class="pf-c-page"> | ||||
|                 <a class="pf-c-skip-to-content pf-c-button pf-m-primary" href="#main-content">${gettext("Skip to content")}</a> | ||||
|                 <pb-sidebar class="pf-c-page__sidebar" .items=${this.sidebar}> | ||||
|                 </pb-sidebar> | ||||
|                 <ak-sidebar class="pf-c-page__sidebar" .items=${this.sidebar}> | ||||
|                 </ak-sidebar> | ||||
|                 <main class="pf-c-page__main"> | ||||
|                     <pb-router-outlet role="main" class="pf-c-page__main" tabindex="-1" id="main-content" defaultUrl="/library/"> | ||||
|                     </pb-router-outlet> | ||||
|                     <ak-router-outlet role="main" class="pf-c-page__main" tabindex="-1" id="main-content" defaultUrl="/library/"> | ||||
|                     </ak-router-outlet> | ||||
|                 </main> | ||||
|             </div>`; | ||||
|     } | ||||
|  | ||||
| @ -6,6 +6,7 @@ import { PBResponse } from "../api/client"; | ||||
| import { COMMON_STYLES } from "../common/styles"; | ||||
| import { loading, truncate } from "../utils"; | ||||
|  | ||||
| @customElement("ak-library-app") | ||||
| export class LibraryApplication extends LitElement { | ||||
|     @property({attribute: false}) | ||||
|     application?: Application; | ||||
| @ -13,8 +14,11 @@ export class LibraryApplication extends LitElement { | ||||
|     static get styles(): CSSResult[] { | ||||
|         return COMMON_STYLES.concat( | ||||
|             css` | ||||
|                 img.pf-icon { | ||||
|                     max-height: 24px; | ||||
|                 a { | ||||
|                     height: 100%; | ||||
|                 } | ||||
|                 i.pf-icon { | ||||
|                     height: 36px; | ||||
|                 } | ||||
|                 .pf-c-avatar { | ||||
|                     --pf-c-avatar--BorderRadius: 0; | ||||
| @ -25,7 +29,7 @@ export class LibraryApplication extends LitElement { | ||||
|  | ||||
|     render(): TemplateResult { | ||||
|         if (!this.application) { | ||||
|             return html`<pb-spinner></pb-spinner>`; | ||||
|             return html`<ak-spinner></ak-spinner>`; | ||||
|         } | ||||
|         return html` <a href="${this.application.launch_url}" class="pf-c-card pf-m-hoverable pf-m-compact"> | ||||
|             <div class="pf-c-card__header"> | ||||
| @ -45,7 +49,7 @@ export class LibraryApplication extends LitElement { | ||||
|  | ||||
| } | ||||
|  | ||||
| @customElement("pb-library") | ||||
| @customElement("ak-library") | ||||
| export class LibraryPage extends LitElement { | ||||
|     @property({attribute: false}) | ||||
|     apps?: PBResponse<Application>; | ||||
| @ -72,7 +76,7 @@ export class LibraryPage extends LitElement { | ||||
|  | ||||
|     renderApps(): TemplateResult { | ||||
|         return html`<div class="pf-l-gallery pf-m-gutter"> | ||||
|             ${this.apps?.results.map((app) => html`<pb-library-app application=${app}></pb-library-app>`)} | ||||
|             ${this.apps?.results.map((app) => html`<ak-library-app .application=${app}></ak-library-app>`)} | ||||
|         </div>`; | ||||
|     } | ||||
|  | ||||
|  | ||||
| @ -10,7 +10,7 @@ import { SpinnerSize } from "../../elements/Spinner"; | ||||
| import "../../elements/AdminLoginsChart"; | ||||
| import "./TopApplicationsTable"; | ||||
|  | ||||
| @customElement("pb-admin-status-card") | ||||
| @customElement("ak-admin-status-card") | ||||
| export class AdminStatusCard extends AggregatePromiseCard { | ||||
|  | ||||
|     @property({type: Number}) | ||||
| @ -23,17 +23,17 @@ export class AdminStatusCard extends AggregatePromiseCard { | ||||
|     lessThanThreshold?: number; | ||||
|  | ||||
|     renderNone(): TemplateResult { | ||||
|         return html`<pb-spinner size=${SpinnerSize.Large}></pb-spinner>`; | ||||
|         return html`<ak-spinner size=${SpinnerSize.Large}></ak-spinner>`; | ||||
|     } | ||||
|  | ||||
|     renderGood(): TemplateResult { | ||||
|         return html`<p class="pb-aggregate-card"> | ||||
|         return html`<p class="ak-aggregate-card"> | ||||
|             <i class="fa fa-check-circle"></i> ${this.value} | ||||
|         </p>`; | ||||
|     } | ||||
|  | ||||
|     renderBad(): TemplateResult { | ||||
|         return html`<p class="pb-aggregate-card"> | ||||
|         return html`<p class="ak-aggregate-card"> | ||||
|             <i class="fa fa-exclamation-triangle"></i> ${this.value} | ||||
|         </p> | ||||
|         <p class="subtext">${this.warningText ? gettext(this.warningText) : ""}</p>`; | ||||
| @ -49,7 +49,7 @@ export class AdminStatusCard extends AggregatePromiseCard { | ||||
|  | ||||
| } | ||||
|  | ||||
| @customElement("pb-admin-overview") | ||||
| @customElement("ak-admin-overview") | ||||
| export class AdminOverviewPage extends LitElement { | ||||
|     @property({attribute: false}) | ||||
|     data?: AdminOverview; | ||||
| @ -74,45 +74,54 @@ export class AdminOverviewPage extends LitElement { | ||||
|         </section> | ||||
|         <section class="pf-c-page__main-section"> | ||||
|             <div class="pf-l-gallery pf-m-gutter"> | ||||
|                 <pb-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Logins over the last 24 hours" style="grid-column-end: span 3;grid-row-end: span 2;"> | ||||
|                     <pb-admin-logins-chart url="${DefaultClient.makeUrl(["admin", "metrics"])}"></pb-admin-logins-chart> | ||||
|                 </pb-aggregate-card> | ||||
|                 <pb-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Apps with most usage" style="grid-column-end: span 2;grid-row-end: span 3;"> | ||||
|                     <pb-top-applications-table></pb-top-applications-table> | ||||
|                 </pb-aggregate-card> | ||||
|                 <pb-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Workers"> | ||||
|  | ||||
|                 </pb-aggregate-card> | ||||
|                 <pb-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-plugged" header="Providers" headerLink="#/administration/providers/"> | ||||
|                 <ak-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Logins over the last 24 hours" style="grid-column-end: span 3;grid-row-end: span 2;"> | ||||
|                     <ak-admin-logins-chart url="${DefaultClient.makeUrl(["admin", "metrics"])}"></ak-admin-logins-chart> | ||||
|                 </ak-aggregate-card> | ||||
|                 <ak-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Apps with most usage" style="grid-column-end: span 2;grid-row-end: span 3;"> | ||||
|                     <ak-top-applications-table></ak-top-applications-table> | ||||
|                 </ak-aggregate-card> | ||||
|                 <ak-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Workers"> | ||||
|                     ${this.data ? | ||||
|         this.data?.worker_count < 1 ? | ||||
|             html`<p class="ak-aggregate-card"> | ||||
|                                     <i class="fa fa-exclamation-triangle"></i> ${this.data?.worker_count} | ||||
|                                 </p> | ||||
|                                 <p class="subtext">${gettext("No workers connected.")}</p>` : | ||||
|             html`<p class="ak-aggregate-card"> | ||||
|                                     <i class="fa fa-check-circle"></i> ${this.data?.worker_count} | ||||
|                                 </p>` | ||||
|         : html`<ak-spinner size=${SpinnerSize.Large}></ak-spinner>`} | ||||
|                 </ak-aggregate-card> | ||||
|                 <ak-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-plugged" header="Providers" headerLink="#/administration/providers/"> | ||||
|                     ${this.data ? | ||||
|         this.data?.providers_without_application > 1 ? | ||||
|             html`<p class="pb-aggregate-card"> | ||||
|             html`<p class="ak-aggregate-card"> | ||||
|                                     <i class="fa fa-exclamation-triangle"></i> 0 | ||||
|                                 </p> | ||||
|                                 <p class="subtext">${gettext("At least one Provider has no application assigned.")}</p>` : | ||||
|             html`<p class="pb-aggregate-card"> | ||||
|             html`<p class="ak-aggregate-card"> | ||||
|                                     <i class="fa fa-check-circle"></i> 0 | ||||
|                                 </p>` | ||||
|         : html`<pb-spinner size=${SpinnerSize.Large}></pb-spinner>`} | ||||
|                 </pb-aggregate-card> | ||||
|                 <pb-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-plugged" header="Policies" headerLink="#/administration/policies/"> | ||||
|         : html`<ak-spinner size=${SpinnerSize.Large}></ak-spinner>`} | ||||
|                 </ak-aggregate-card> | ||||
|                 <ak-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-plugged" header="Policies" headerLink="#/administration/policies/"> | ||||
|                     ${this.data ? | ||||
|         this.data?.policies_without_binding > 1 ? | ||||
|             html`<p class="pb-aggregate-card"> | ||||
|             html`<p class="ak-aggregate-card"> | ||||
|                                     <i class="fa fa-exclamation-triangle"></i> 0 | ||||
|                                 </p> | ||||
|                                 <p class="subtext">${gettext("Policies without binding exist.")}</p>` : | ||||
|             html`<p class="pb-aggregate-card"> | ||||
|             html`<p class="ak-aggregate-card"> | ||||
|                                     <i class="fa fa-check-circle"></i> 0 | ||||
|                                 </p>` | ||||
|         : html`<pb-spinner size=${SpinnerSize.Large}></pb-spinner>`} | ||||
|                 </pb-aggregate-card> | ||||
|                 <pb-aggregate-card-promise | ||||
|         : html`<ak-spinner size=${SpinnerSize.Large}></ak-spinner>`} | ||||
|                 </ak-aggregate-card> | ||||
|                 <ak-aggregate-card-promise | ||||
|                     icon="pf-icon pf-icon-user" | ||||
|                     header="Users" | ||||
|                     headerLink="#/administration/users/" | ||||
|                     .promise=${this.users}> | ||||
|                 </pb-aggregate-card-promise> | ||||
|                 </ak-aggregate-card-promise> | ||||
|             </div> | ||||
|         </section>`; | ||||
|     } | ||||
|  | ||||
| @ -5,7 +5,7 @@ import { COMMON_STYLES } from "../../common/styles"; | ||||
|  | ||||
| import "../../elements/Spinner"; | ||||
|  | ||||
| @customElement("pb-top-applications-table") | ||||
| @customElement("ak-top-applications-table") | ||||
| export class TopApplicationsTable extends LitElement { | ||||
|  | ||||
|     @property({attribute: false}) | ||||
| @ -43,7 +43,7 @@ export class TopApplicationsTable extends LitElement { | ||||
|                     </tr> | ||||
|                 </thead> | ||||
|                 <tbody role="rowgroup"> | ||||
|                     ${this.topN ? this.topN.map((e) => this.renderRow(e)) : html`<pb-spinner></pb-spinner>`} | ||||
|                     ${this.topN ? this.topN.map((e) => this.renderRow(e)) : html`<ak-spinner></ak-spinner>`} | ||||
|                 </tbody> | ||||
|             </table>`; | ||||
|     } | ||||
|  | ||||
| @ -4,13 +4,13 @@ import { Application } from "../../api/application"; | ||||
| import { PBResponse } from "../../api/client"; | ||||
| import { TablePage } from "../../elements/table/TablePage"; | ||||
|  | ||||
| @customElement("pb-application-list") | ||||
| @customElement("ak-application-list") | ||||
| export class ApplicationList extends TablePage<Application> { | ||||
|     pageTitle(): string { | ||||
|         return gettext("Applications"); | ||||
|     } | ||||
|     pageDescription(): string { | ||||
|         return gettext("External Applications which use passbook as Identity-Provider, utilizing protocols like OAuth2 and SAML."); | ||||
|         return gettext("External Applications which use authentik as Identity-Provider, utilizing protocols like OAuth2 and SAML."); | ||||
|     } | ||||
|     pageIcon(): string { | ||||
|         return gettext("pf-icon pf-icon-applications"); | ||||
| @ -34,18 +34,18 @@ export class ApplicationList extends TablePage<Application> { | ||||
|             item.provider.toString(), | ||||
|             item.provider.toString(), | ||||
|             ` | ||||
|             <pb-modal-button href="administration/policies/bindings/${item.pk}/update/"> | ||||
|                 <pb-spinner-button slot="trigger" class="pf-m-secondary"> | ||||
|             <ak-modal-button href="administration/policies/bindings/${item.pk}/update/"> | ||||
|                 <ak-spinner-button slot="trigger" class="pf-m-secondary"> | ||||
|                     Edit | ||||
|                 </pb-spinner-button> | ||||
|                 </ak-spinner-button> | ||||
|                 <div slot="modal"></div> | ||||
|             </pb-modal-button> | ||||
|             <pb-modal-button href="administration/policies/bindings/${item.pk}/delete/"> | ||||
|                 <pb-spinner-button slot="trigger" class="pf-m-danger"> | ||||
|             </ak-modal-button> | ||||
|             <ak-modal-button href="administration/policies/bindings/${item.pk}/delete/"> | ||||
|                 <ak-spinner-button slot="trigger" class="pf-m-danger"> | ||||
|                     Delete | ||||
|                 </pb-spinner-button> | ||||
|                 </ak-spinner-button> | ||||
|                 <div slot="modal"></div> | ||||
|             </pb-modal-button> | ||||
|             </ak-modal-button> | ||||
|             `, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
| @ -9,7 +9,7 @@ import { Table } from "../../elements/table/Table"; | ||||
| import "../../elements/Tabs"; | ||||
| import "../../elements/AdminLoginsChart"; | ||||
|  | ||||
| @customElement("pb-bound-policies-list") | ||||
| @customElement("ak-bound-policies-list") | ||||
| export class BoundPoliciesList extends Table<PolicyBinding> { | ||||
|     @property() | ||||
|     target?: string; | ||||
| @ -33,24 +33,24 @@ export class BoundPoliciesList extends Table<PolicyBinding> { | ||||
|             item.order.toString(), | ||||
|             item.timeout.toString(), | ||||
|             ` | ||||
|             <pb-modal-button href="administration/policies/bindings/${item.pk}/update/"> | ||||
|                 <pb-spinner-button slot="trigger" class="pf-m-secondary"> | ||||
|             <ak-modal-button href="administration/policies/bindings/${item.pk}/update/"> | ||||
|                 <ak-spinner-button slot="trigger" class="pf-m-secondary"> | ||||
|                     Edit | ||||
|                 </pb-spinner-button> | ||||
|                 </ak-spinner-button> | ||||
|                 <div slot="modal"></div> | ||||
|             </pb-modal-button> | ||||
|             <pb-modal-button href="administration/policies/bindings/${item.pk}/delete/"> | ||||
|                 <pb-spinner-button slot="trigger" class="pf-m-danger"> | ||||
|             </ak-modal-button> | ||||
|             <ak-modal-button href="administration/policies/bindings/${item.pk}/delete/"> | ||||
|                 <ak-spinner-button slot="trigger" class="pf-m-danger"> | ||||
|                     Delete | ||||
|                 </pb-spinner-button> | ||||
|                 </ak-spinner-button> | ||||
|                 <div slot="modal"></div> | ||||
|             </pb-modal-button> | ||||
|             </ak-modal-button> | ||||
|             `, | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @customElement("pb-application-view") | ||||
| @customElement("ak-application-view") | ||||
| export class ApplicationViewPage extends LitElement { | ||||
|     @property() | ||||
|     set args(value: { [key: string]: string }) { | ||||
| @ -88,8 +88,8 @@ export class ApplicationViewPage extends LitElement { | ||||
|                     <p>${this.application?.meta_publisher}</p> | ||||
|                 </div> | ||||
|             </section> | ||||
|             <pb-tabs> | ||||
|                 <section slot="page-1" tab-title="Users" class="pf-c-page__main-section pf-m-no-padding-mobile"> | ||||
|             <ak-tabs> | ||||
|                 <section slot="page-1" data-tab-title="Users" class="pf-c-page__main-section pf-m-no-padding-mobile"> | ||||
|                     <div class="pf-l-gallery pf-m-gutter"> | ||||
|                         <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-4-col" style="grid-column-end: span 3;grid-row-end: span 2;"> | ||||
|                             <div class="pf-c-card__header"> | ||||
| @ -99,18 +99,18 @@ export class ApplicationViewPage extends LitElement { | ||||
|                             </div> | ||||
|                             <div class="pf-c-card__body"> | ||||
|                                 ${this.application ? html` | ||||
|                                     <pb-admin-logins-chart | ||||
|                                     <ak-admin-logins-chart | ||||
|                                         url="${DefaultClient.makeUrl(["core", "applications", this.application?.slug, "metrics"])}"> | ||||
|                                     </pb-admin-logins-chart>`: ""} | ||||
|                                     </ak-admin-logins-chart>`: ""} | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </section> | ||||
|                 <div slot="page-2" tab-title="Policy Bindings" class="pf-c-page__main-section pf-m-no-padding-mobile"> | ||||
|                 <div slot="page-2" data-tab-title="Policy Bindings" class="pf-c-page__main-section pf-m-no-padding-mobile"> | ||||
|                     <div class="pf-c-card"> | ||||
|                         <pb-bound-policies-list .target=${this.application.pk}></pb-bound-policies-list> | ||||
|                         <ak-bound-policies-list .target=${this.application.pk}></ak-bound-policies-list> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </pb-tabs>`; | ||||
|             </ak-tabs>`; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -11,7 +11,7 @@ interface Response { | ||||
|     body?: string; | ||||
| } | ||||
|  | ||||
| @customElement("pb-flow-shell-card") | ||||
| @customElement("ak-flow-shell-card") | ||||
| export class FlowShellCard extends LitElement { | ||||
|     @property() | ||||
|     flowBodyUrl = ""; | ||||
| @ -59,7 +59,7 @@ export class FlowShellCard extends LitElement { | ||||
|             this.setFormSubmitHandlers(); | ||||
|             break; | ||||
|         default: | ||||
|             console.debug(`passbook/flows: unexpected data type ${data.type}`); | ||||
|             console.debug(`authentik/flows: unexpected data type ${data.type}`); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| @ -84,13 +84,13 @@ export class FlowShellCard extends LitElement { | ||||
|             const element = <HTMLInputElement>form.elements[index]; | ||||
|             if (element.value === form.action) { | ||||
|                 console.debug( | ||||
|                     "passbook/flows: Found Form action URL in form elements, not changing form action." | ||||
|                     "authentik/flows: Found Form action URL in form elements, not changing form action." | ||||
|                 ); | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         form.action = this.flowBodyUrl; | ||||
|         console.debug(`passbook/flows: updated form.action ${this.flowBodyUrl}`); | ||||
|         console.debug(`authentik/flows: updated form.action ${this.flowBodyUrl}`); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
| @ -102,11 +102,11 @@ export class FlowShellCard extends LitElement { | ||||
|  | ||||
|     setFormSubmitHandlers(): void { | ||||
|         this.querySelectorAll("form").forEach((form) => { | ||||
|             console.debug(`passbook/flows: Checking for autosubmit attribute ${form}`); | ||||
|             console.debug(`authentik/flows: Checking for autosubmit attribute ${form}`); | ||||
|             this.checkAutosubmit(form); | ||||
|             console.debug(`passbook/flows: Setting action for form ${form}`); | ||||
|             console.debug(`authentik/flows: Setting action for form ${form}`); | ||||
|             this.updateFormAction(form); | ||||
|             console.debug(`passbook/flows: Adding handler for form ${form}`); | ||||
|             console.debug(`authentik/flows: Adding handler for form ${form}`); | ||||
|             form.addEventListener("submit", (e) => { | ||||
|                 e.preventDefault(); | ||||
|                 const formData = new FormData(form); | ||||
| @ -125,14 +125,14 @@ export class FlowShellCard extends LitElement { | ||||
|                         this.errorMessage(e); | ||||
|                     }); | ||||
|             }); | ||||
|             form.classList.add("pb-flow-wrapped"); | ||||
|             form.classList.add("ak-flow-wrapped"); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     errorMessage(error: string): void { | ||||
|         this.flowBody = ` | ||||
|             <style> | ||||
|                 .pb-exception { | ||||
|                 .ak-exception { | ||||
|                     font-family: monospace; | ||||
|                     overflow-x: scroll; | ||||
|                 } | ||||
| @ -146,12 +146,12 @@ export class FlowShellCard extends LitElement { | ||||
|                 <h3> | ||||
|                     Something went wrong! Please try again later. | ||||
|                 </h3> | ||||
|                 <pre class="pb-exception">${error}</pre> | ||||
|                 <pre class="ak-exception">${error}</pre> | ||||
|             </div>`; | ||||
|     } | ||||
|  | ||||
|     loading(): TemplateResult { | ||||
|         return html` <div class="pf-c-login__main-body pb-loading"> | ||||
|         return html` <div class="pf-c-login__main-body ak-loading"> | ||||
|             <span class="pf-c-spinner" role="progressbar" aria-valuetext="Loading..."> | ||||
|                 <span class="pf-c-spinner__clipper"></span> | ||||
|                 <span class="pf-c-spinner__lead-ball"></span> | ||||
|  | ||||
| @ -7,7 +7,7 @@ import SpinnerStyle from "@patternfly/patternfly/components/Spinner/spinner.css" | ||||
| import BackdropStyle from "@patternfly/patternfly/components/Backdrop/backdrop.css"; | ||||
| import { SpinnerSize } from "../../elements/Spinner"; | ||||
|  | ||||
| @customElement("pb-site-shell") | ||||
| @customElement("ak-site-shell") | ||||
| export class SiteShell extends LitElement { | ||||
|     @property() | ||||
|     set url(value: string) { | ||||
| @ -45,6 +45,13 @@ export class SiteShell extends LitElement { | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     constructor() { | ||||
|         super(); | ||||
|         this.addEventListener("ak-refresh", () => { | ||||
|             this.loadContent(); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     loadContent(): void { | ||||
|         if (!this._url) { | ||||
|             return; | ||||
| @ -55,7 +62,7 @@ export class SiteShell extends LitElement { | ||||
|                 if (r.ok) { | ||||
|                     return r; | ||||
|                 } | ||||
|                 console.debug(`passbook/site-shell: Request failed ${this._url}`); | ||||
|                 console.debug(`authentik/site-shell: Request failed ${this._url}`); | ||||
|                 window.location.hash = "#/"; | ||||
|                 throw new Error("Request failed"); | ||||
|             }) | ||||
| @ -69,7 +76,7 @@ export class SiteShell extends LitElement { | ||||
|             }) | ||||
|             .then(() => { | ||||
|                 // Ensure anchors only change the hash | ||||
|                 this.querySelectorAll<HTMLAnchorElement>("a:not(.pb-root-link)").forEach((a) => { | ||||
|                 this.querySelectorAll<HTMLAnchorElement>("a:not(.ak-root-link)").forEach((a) => { | ||||
|                     if (a.href === "") { | ||||
|                         return; | ||||
|                     } | ||||
| @ -78,12 +85,12 @@ export class SiteShell extends LitElement { | ||||
|                         const qs = url.search || ""; | ||||
|                         a.href = `#${url.pathname}${qs}`; | ||||
|                     } catch (e) { | ||||
|                         console.debug(`passbook/site-shell: error ${e}`); | ||||
|                         console.debug(`authentik/site-shell: error ${e}`); | ||||
|                         a.href = `#${a.href}`; | ||||
|                     } | ||||
|                 }); | ||||
|                 // Create refresh buttons | ||||
|                 this.querySelectorAll("[role=pb-refresh]").forEach((rt) => { | ||||
|                 this.querySelectorAll("[role=ak-refresh]").forEach((rt) => { | ||||
|                     rt.addEventListener("click", () => { | ||||
|                         this.loadContent(); | ||||
|                     }); | ||||
| @ -108,7 +115,7 @@ export class SiteShell extends LitElement { | ||||
|             html`<div class="pf-c-backdrop"> | ||||
|                     <div class="pf-l-bullseye"> | ||||
|                         <div class="pf-l-bullseye__item"> | ||||
|                             <pb-spinner size=${SpinnerSize.Large}></pb-spinner> | ||||
|                             <ak-spinner size=${SpinnerSize.Large}></ak-spinner> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div>` | ||||
|  | ||||
| @ -15,7 +15,7 @@ export class Route { | ||||
|  | ||||
|     redirect(to: string): Route { | ||||
|         this.callback = () => { | ||||
|             console.debug(`passbook/router: redirecting ${to}`); | ||||
|             console.debug(`authentik/router: redirecting ${to}`); | ||||
|             window.location.hash = `#${to}`; | ||||
|             return html``; | ||||
|         }; | ||||
|  | ||||
| @ -11,7 +11,7 @@ import { RouteMatch } from "./RouteMatch"; | ||||
|  | ||||
| import "../generic/SiteShell"; | ||||
|  | ||||
| @customElement("pb-router-outlet") | ||||
| @customElement("ak-router-outlet") | ||||
| export class RouterOutlet extends LitElement { | ||||
|     @property({attribute: false}) | ||||
|     current?: RouteMatch; | ||||
| @ -46,28 +46,28 @@ export class RouterOutlet extends LitElement { | ||||
|         if (activeUrl === "") { | ||||
|             activeUrl = this.defaultUrl || "/"; | ||||
|             window.location.hash = `#${activeUrl}`; | ||||
|             console.debug(`passbook/router: set to ${window.location.hash}`); | ||||
|             console.debug(`authentik/router: set to ${window.location.hash}`); | ||||
|             return; | ||||
|         } | ||||
|         let matchedRoute: RouteMatch | null = null; | ||||
|         ROUTES.some((route) => { | ||||
|             console.debug(`passbook/router: matching ${activeUrl} against ${route.url}`); | ||||
|             console.debug(`authentik/router: matching ${activeUrl} against ${route.url}`); | ||||
|             const match = route.url.exec(activeUrl); | ||||
|             if (match != null) { | ||||
|                 matchedRoute = new RouteMatch(route); | ||||
|                 matchedRoute.arguments = match.groups || {}; | ||||
|                 matchedRoute.fullUrl = activeUrl; | ||||
|                 console.debug(`passbook/router: found match ${matchedRoute}`); | ||||
|                 console.debug(`authentik/router: found match ${matchedRoute}`); | ||||
|                 return true; | ||||
|             } | ||||
|         }); | ||||
|         if (!matchedRoute) { | ||||
|             console.debug(`passbook/router: route "${activeUrl}" not defined, defaulting to shell`); | ||||
|             console.debug(`authentik/router: route "${activeUrl}" not defined, defaulting to shell`); | ||||
|             const route = new Route( | ||||
|                 RegExp(""), | ||||
|                 html`<pb-site-shell url=${activeUrl}> | ||||
|                 html`<ak-site-shell url=${activeUrl}> | ||||
|                     <div slot="body"></div> | ||||
|                 </pb-site-shell>` | ||||
|                 </ak-site-shell>` | ||||
|             ); | ||||
|             matchedRoute = new RouteMatch(route); | ||||
|             matchedRoute.arguments = route.url.exec(activeUrl)?.groups || {}; | ||||
|  | ||||
| @ -10,10 +10,10 @@ 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`<pb-library></pb-library>`), | ||||
|     new Route(new RegExp("^/administration/overview-ng/$"), html`<pb-admin-overview></pb-admin-overview>`), | ||||
|     new Route(new RegExp("^/applications/$"), html`<pb-application-list></pb-application-list>`), | ||||
|     new Route(new RegExp("^/library/$"), html`<ak-library></ak-library>`), | ||||
|     new Route(new RegExp("^/administration/overview-ng/$"), html`<ak-admin-overview></ak-admin-overview>`), | ||||
|     new Route(new RegExp("^/applications/$"), html`<ak-application-list></ak-application-list>`), | ||||
|     new Route(new RegExp(`^/applications/(?<slug>${SLUG_REGEX})/$`)).then((args) => { | ||||
|         return html`<pb-application-view .args=${args}></pb-application-view>`; | ||||
|         return html`<ak-application-view .args=${args}></ak-application-view>`; | ||||
|     }), | ||||
| ]; | ||||
|  | ||||
| @ -42,7 +42,7 @@ export function loading<T>(v: T, actual: TemplateResult): TemplateResult { | ||||
|             <div class="pf-c-empty-state__content"> | ||||
|                 <div class="pf-l-bullseye"> | ||||
|                     <div class="pf-l-bullseye__item"> | ||||
|                         <pb-spinner size="${SpinnerSize.Large}"></pb-spinner> | ||||
|                         <ak-spinner size="${SpinnerSize.Large}"></ak-spinner> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|  | ||||
 Jens L
					Jens L