web/admin: rework markdown, correctly render Admonitions, fix links
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
		@ -3,6 +3,7 @@ import babel from "@rollup/plugin-babel";
 | 
			
		||||
import commonjs from "@rollup/plugin-commonjs";
 | 
			
		||||
import { nodeResolve } from "@rollup/plugin-node-resolve";
 | 
			
		||||
import replace from "@rollup/plugin-replace";
 | 
			
		||||
import { cwd } from "process";
 | 
			
		||||
import copy from "rollup-plugin-copy";
 | 
			
		||||
import cssimport from "rollup-plugin-cssimport";
 | 
			
		||||
import { terser } from "rollup-plugin-terser";
 | 
			
		||||
@ -82,6 +83,7 @@ export const defaultOptions = {
 | 
			
		||||
        }),
 | 
			
		||||
        replace({
 | 
			
		||||
            "process.env.NODE_ENV": JSON.stringify(isProdBuild ? "production" : "development"),
 | 
			
		||||
            "process.env.CWD": JSON.stringify(cwd()),
 | 
			
		||||
            "process.env.AK_API_BASE_PATH": JSON.stringify(apiBasePath),
 | 
			
		||||
            "preventAssignment": true,
 | 
			
		||||
        }),
 | 
			
		||||
 | 
			
		||||
@ -259,7 +259,20 @@ export class OAuth2ProviderViewPage extends AKElement {
 | 
			
		||||
                    class="pf-c-card pf-l-grid__item pf-m-12-col pf-m-12-col-on-xl pf-m-12-col-on-2xl"
 | 
			
		||||
                >
 | 
			
		||||
                    <div class="pf-c-card__body">
 | 
			
		||||
                        <ak-markdown .md=${MDProviderOAuth2}></ak-markdown>
 | 
			
		||||
                        <ak-markdown
 | 
			
		||||
                            .replacers=${[
 | 
			
		||||
                                (input: string) => {
 | 
			
		||||
                                    if (!this.provider) {
 | 
			
		||||
                                        return input;
 | 
			
		||||
                                    }
 | 
			
		||||
                                    return input.replaceAll(
 | 
			
		||||
                                        "<application slug>",
 | 
			
		||||
                                        this.provider.assignedApplicationSlug,
 | 
			
		||||
                                    );
 | 
			
		||||
                                },
 | 
			
		||||
                            ]}
 | 
			
		||||
                            .md=${MDProviderOAuth2}
 | 
			
		||||
                        ></ak-markdown>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>`;
 | 
			
		||||
 | 
			
		||||
@ -13,7 +13,6 @@ import MDTraefikStandalone from "@goauthentik/docs/providers/proxy/_traefik_stan
 | 
			
		||||
import { AKElement } from "@goauthentik/elements/Base";
 | 
			
		||||
import "@goauthentik/elements/CodeMirror";
 | 
			
		||||
import { PFColor } from "@goauthentik/elements/Label";
 | 
			
		||||
import { MarkdownDocument } from "@goauthentik/elements/Markdown";
 | 
			
		||||
import "@goauthentik/elements/Markdown";
 | 
			
		||||
import "@goauthentik/elements/Tabs";
 | 
			
		||||
import "@goauthentik/elements/buttons/ModalButton";
 | 
			
		||||
@ -104,25 +103,6 @@ export class ProxyProviderViewPage extends AKElement {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderConfigTemplate(markdown: MarkdownDocument): MarkdownDocument {
 | 
			
		||||
        const extHost = new URL(this.provider?.externalHost || "http://a");
 | 
			
		||||
        // See website/docs/providers/proxy/forward_auth.mdx
 | 
			
		||||
        if (this.provider?.mode === ProxyMode.ForwardSingle) {
 | 
			
		||||
            markdown.html = markdown.html
 | 
			
		||||
                .replaceAll("authentik.company", window.location.hostname)
 | 
			
		||||
                .replaceAll("outpost.company:9000", window.location.hostname)
 | 
			
		||||
                .replaceAll("https://app.company", extHost.toString())
 | 
			
		||||
                .replaceAll("app.company", extHost.hostname);
 | 
			
		||||
        } else if (this.provider?.mode == ProxyMode.ForwardDomain) {
 | 
			
		||||
            markdown.html = markdown.html
 | 
			
		||||
                .replaceAll("authentik.company", window.location.hostname)
 | 
			
		||||
                .replaceAll("outpost.company:9000", extHost.toString())
 | 
			
		||||
                .replaceAll("https://app.company", extHost.toString())
 | 
			
		||||
                .replaceAll("app.company", extHost.hostname);
 | 
			
		||||
        }
 | 
			
		||||
        return markdown;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderConfig(): TemplateResult {
 | 
			
		||||
        const serves = [
 | 
			
		||||
            {
 | 
			
		||||
@ -154,6 +134,29 @@ export class ProxyProviderViewPage extends AKElement {
 | 
			
		||||
                md: MDCaddyStandalone,
 | 
			
		||||
            },
 | 
			
		||||
        ];
 | 
			
		||||
        const replacers = [
 | 
			
		||||
            (input: string): string => {
 | 
			
		||||
                if (!this.provider) {
 | 
			
		||||
                    return input;
 | 
			
		||||
                }
 | 
			
		||||
                const extHost = new URL(this.provider.externalHost);
 | 
			
		||||
                // See website/docs/providers/proxy/forward_auth.mdx
 | 
			
		||||
                if (this.provider?.mode === ProxyMode.ForwardSingle) {
 | 
			
		||||
                    return input
 | 
			
		||||
                        .replaceAll("authentik.company", window.location.hostname)
 | 
			
		||||
                        .replaceAll("outpost.company:9000", window.location.hostname)
 | 
			
		||||
                        .replaceAll("https://app.company", extHost.toString())
 | 
			
		||||
                        .replaceAll("app.company", extHost.hostname);
 | 
			
		||||
                } else if (this.provider?.mode == ProxyMode.ForwardDomain) {
 | 
			
		||||
                    return input
 | 
			
		||||
                        .replaceAll("authentik.company", window.location.hostname)
 | 
			
		||||
                        .replaceAll("outpost.company:9000", extHost.toString())
 | 
			
		||||
                        .replaceAll("https://app.company", extHost.toString())
 | 
			
		||||
                        .replaceAll("app.company", extHost.hostname);
 | 
			
		||||
                }
 | 
			
		||||
                return input;
 | 
			
		||||
            },
 | 
			
		||||
        ];
 | 
			
		||||
        return html`<ak-tabs pageIdentifier="proxy-setup">
 | 
			
		||||
            ${serves.map((server) => {
 | 
			
		||||
                return html`<section
 | 
			
		||||
@ -161,7 +164,7 @@ export class ProxyProviderViewPage extends AKElement {
 | 
			
		||||
                    data-tab-title="${server.label}"
 | 
			
		||||
                    class="pf-c-page__main-section pf-m-light pf-m-no-padding-mobile"
 | 
			
		||||
                >
 | 
			
		||||
                    <ak-markdown .md=${this.renderConfigTemplate(server.md)}></ak-markdown>
 | 
			
		||||
                    <ak-markdown .replacers=${replacers} .md=${server.md}></ak-markdown>
 | 
			
		||||
                </section>`;
 | 
			
		||||
            })}</ak-tabs
 | 
			
		||||
        >`;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										41
									
								
								web/src/elements/Alert.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								web/src/elements/Alert.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
import { AKElement } from "@goauthentik/elements/Base";
 | 
			
		||||
 | 
			
		||||
import { CSSResult, TemplateResult, html } from "lit";
 | 
			
		||||
import { customElement, property } from "lit/decorators.js";
 | 
			
		||||
 | 
			
		||||
import AKGlobal from "@goauthentik/common/styles/authentik.css";
 | 
			
		||||
import PFAlert from "@patternfly/patternfly/components/Alert/alert.css";
 | 
			
		||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
			
		||||
 | 
			
		||||
export enum Level {
 | 
			
		||||
    Warning = "pf-m-warning",
 | 
			
		||||
    Info = "pf-m-info",
 | 
			
		||||
    Success = "pf-m-success",
 | 
			
		||||
    Danger = "pf-m-danger",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@customElement("ak-alert")
 | 
			
		||||
export class Alert extends AKElement {
 | 
			
		||||
    @property({ type: Boolean })
 | 
			
		||||
    inline = false;
 | 
			
		||||
 | 
			
		||||
    @property()
 | 
			
		||||
    level: Level = Level.Warning;
 | 
			
		||||
 | 
			
		||||
    static get styles(): CSSResult[] {
 | 
			
		||||
        return [PFBase, PFAlert, AKGlobal];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render(): TemplateResult {
 | 
			
		||||
        return html`<div
 | 
			
		||||
            class="pf-c-alert ${this.inline ? html`pf-m-inline` : html``} ${this.level}"
 | 
			
		||||
        >
 | 
			
		||||
            <div class="pf-c-alert__icon">
 | 
			
		||||
                <i class="fas fa-exclamation-circle"></i>
 | 
			
		||||
            </div>
 | 
			
		||||
            <h4 class="pf-c-alert__title">
 | 
			
		||||
                <slot></slot>
 | 
			
		||||
            </h4>
 | 
			
		||||
        </div>`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,3 +1,4 @@
 | 
			
		||||
import "@goauthentik/elements/Alert";
 | 
			
		||||
import { AKElement } from "@goauthentik/elements/Base";
 | 
			
		||||
 | 
			
		||||
import { CSSResult, TemplateResult, html } from "lit";
 | 
			
		||||
@ -12,22 +13,66 @@ export interface MarkdownDocument {
 | 
			
		||||
    html: string;
 | 
			
		||||
    metadata: { [key: string]: string };
 | 
			
		||||
    filename: string;
 | 
			
		||||
    path: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type Replacer = (input: string, md: MarkdownDocument) => string;
 | 
			
		||||
 | 
			
		||||
@customElement("ak-markdown")
 | 
			
		||||
export class Markdown extends AKElement {
 | 
			
		||||
    @property({ attribute: false })
 | 
			
		||||
    md?: MarkdownDocument;
 | 
			
		||||
 | 
			
		||||
    @property({ attribute: false })
 | 
			
		||||
    replacers: Replacer[] = [];
 | 
			
		||||
 | 
			
		||||
    defaultReplacers: Replacer[] = [
 | 
			
		||||
        this.replaceAdmonitions,
 | 
			
		||||
        this.replaceList,
 | 
			
		||||
        this.replaceRelativeLinks,
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    static get styles(): CSSResult[] {
 | 
			
		||||
        return [PFList, PFContent, AKGlobal];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    replaceAdmonitions(input: string): string {
 | 
			
		||||
        const admonitionStart = /:::(\w+)<br\s\/>/gm;
 | 
			
		||||
        const admonitionEnd = /:::/gm;
 | 
			
		||||
        return input
 | 
			
		||||
            .replaceAll(admonitionStart, "<ak-alert level=\"$1\">")
 | 
			
		||||
            .replaceAll(admonitionEnd, "</ak-alert>");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    replaceList(input: string): string {
 | 
			
		||||
        return input.replace("<ul>", "<ul class='pf-c-list'>");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    replaceRelativeLinks(input: string, md: MarkdownDocument): string {
 | 
			
		||||
        const relativeLink = /href=".(.*)"/gm;
 | 
			
		||||
        const cwd = process.env.CWD as string;
 | 
			
		||||
        // cwd will point to $root/web, but the docs are in $root/website/docs
 | 
			
		||||
        let relPath = md.path.replace(cwd + "site", "");
 | 
			
		||||
        if (md.filename === "index.md") {
 | 
			
		||||
            relPath = relPath.replace("index.md", "");
 | 
			
		||||
        }
 | 
			
		||||
        const baseURL = "https://goauthentik.io";
 | 
			
		||||
        const fullURL = `${baseURL}${relPath}.$1`;
 | 
			
		||||
        return input.replace(relativeLink, `href="${fullURL}" target="_blank"`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render(): TemplateResult {
 | 
			
		||||
        if (!this.md) {
 | 
			
		||||
            return html``;
 | 
			
		||||
        }
 | 
			
		||||
        const finalHTML = this.md?.html.replace("<ul>", "<ul class='pf-c-list'>");
 | 
			
		||||
        let finalHTML = this.md.html;
 | 
			
		||||
        const replacers = [...this.defaultReplacers, ...this.replacers];
 | 
			
		||||
        replacers.forEach((r) => {
 | 
			
		||||
            if (!this.md) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            finalHTML = r(finalHTML, this.md);
 | 
			
		||||
        });
 | 
			
		||||
        return html`${this.md?.metadata.title ? html`<h2>${this.md.metadata.title}</h2>` : html``}
 | 
			
		||||
        ${unsafeHTML(finalHTML)}`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user