tests/e2e: add test for authentication flow in compatibility mode (#14392)

* tests/e2e: add test for authentication flow in compatibility mode

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* web: Add prefix class to CSS for easier debugging of constructed stylesheets.

- Use CSS variables for highlighter.

* web: Fix issue where MDX components apply styles out of order.

* web: Fix hover color.

* web: Fix CSS module types. Clean up globals.

* web: Fix issues surrounding availability of shadow root in compatibility mode.

* web: Fix typo.

* web: Partial fixes for storybook dark theme.

* web: Fix overflow.

* web: Fix issues surrounding competing interfaces attempting to apply styles.

* fix padding in ak-alert in. markdown

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* web: Minimize use of sub-module exports.

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Teffen Ellis <teffen@sister.software>
This commit is contained in:
Jens L.
2025-05-15 16:51:11 +02:00
committed by GitHub
parent 814e438422
commit 0cf6bff93c
39 changed files with 1731 additions and 2435 deletions

View File

@ -1,10 +1,47 @@
/**
* @file Theme utilities.
*/
import { UIConfig } from "@goauthentik/common/ui/config";
import {
type StyleRoot,
createStyleSheetUnsafe,
setAdoptedStyleSheets,
} from "@goauthentik/common/stylesheets.js";
import { UIConfig } from "@goauthentik/common/ui/config.js";
import AKBase from "@goauthentik/common/styles/authentik.css";
import AKBaseDark from "@goauthentik/common/styles/theme-dark.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { Config, CurrentBrand, UiThemeEnum } from "@goauthentik/api";
//#region Stylesheet Exports
/**
* A global style sheet for the Patternfly base styles.
*
* @remarks
*
* While a component *may* import its own instance of the PFBase style sheet,
* this instance ensures referential identity.
*/
export const $PFBase = createStyleSheetUnsafe(PFBase);
/**
* A global style sheet for the authentik base styles.
*
* @see {@linkcode $PFBase} for details.
*/
export const $AKBase = createStyleSheetUnsafe(AKBase);
/**
* A global style sheet for the authentik dark theme.
*
* @see {@linkcode $PFBase} for details.
*/
export const $AKBaseDark = createStyleSheetUnsafe(AKBaseDark);
//#endregion
//#region Scheme Types
/**
@ -134,15 +171,21 @@ export function resolveUITheme(
* Effect listener invoked when the color scheme changes.
*/
export type UIThemeListener = (currentUITheme: ResolvedUITheme) => void;
/**
* Create an effect that runs
* Effect destructor invoked when cleanup is required.
*/
export type UIThemeDestructor = () => void;
/**
* Create an effect that runs UI theme changes.
*
* @returns A cleanup function that removes the effect.
*/
export function createUIThemeEffect(
effect: UIThemeListener,
listenerOptions?: AddEventListenerOptions,
): () => void {
): UIThemeDestructor {
const colorSchemeTarget = resolveUITheme();
const invertedColorSchemeTarget = UIThemeInversion[colorSchemeTarget];
@ -174,6 +217,8 @@ export function createUIThemeEffect(
mediaQueryList.removeEventListener("change", changeListener);
};
listenerOptions?.signal?.addEventListener("abort", cleanup);
return cleanup;
}
@ -181,16 +226,96 @@ export function createUIThemeEffect(
//#region Theme Element
/**
* Applies the current UI theme to the given style root.
*
* @param styleRoot The style root to apply the theme to.
* @param currentUITheme The current UI theme to apply.
* @param additionalStyleSheets Additional style sheets to apply, in addition to the theme's base sheets.
* @category CSS
*
* @see {@linkcode setAdoptedStyleSheets} for caveats.
*/
export function applyUITheme(
styleRoot: StyleRoot,
currentUITheme: ResolvedUITheme = resolveUITheme(),
...additionalStyleSheets: Array<CSSStyleSheet | undefined | null>
): void {
setAdoptedStyleSheets(styleRoot, (currentStyleSheets) => {
const appendedSheets = additionalStyleSheets.filter(Boolean) as CSSStyleSheet[];
if (currentUITheme === UiThemeEnum.Dark) {
return [...currentStyleSheets, $AKBaseDark, ...appendedSheets];
}
return [
...currentStyleSheets.filter((styleSheet) => styleSheet !== $AKBaseDark),
...appendedSheets,
];
});
}
/**
* Applies the given theme to the document, i.e. the `<html>` element.
*
* @param hint The color scheme hint to use.
*/
export function applyDocumentTheme(hint: CSSColorSchemeValue | UIThemeHint = "auto"): void {
const preferredColorScheme = formatColorScheme(hint);
const applyStyleSheets: UIThemeListener = (currentUITheme) => {
console.debug(`authentik/theme (document): switching to ${currentUITheme} theme`);
setAdoptedStyleSheets(document, (currentStyleSheets) => {
if (currentUITheme === "dark") {
return [...currentStyleSheets, $PFBase, $AKBase, $AKBaseDark];
}
return [
...currentStyleSheets.filter((styleSheet) => styleSheet !== $AKBaseDark),
$PFBase,
$AKBase,
];
});
document.documentElement.dataset.theme = currentUITheme;
};
if (preferredColorScheme === "auto") {
createUIThemeEffect(applyStyleSheets);
return;
}
applyStyleSheets(preferredColorScheme);
}
/**
* An element that can be themed.
*/
export interface ThemedElement extends HTMLElement {
brand?: CurrentBrand;
uiConfig?: UIConfig;
config?: Config;
/**
* The brand information for the current theme.
*/
readonly brand?: CurrentBrand;
/**
* The UI configuration for the current theme,
* typically injected through a Lit Mixin.
*
* @see {@linkcode UIConfig} for details.
*/
readonly uiConfig?: UIConfig;
/**
* An authentik configuration initially provided by the server.
*/
readonly config?: Config;
activeTheme: ResolvedUITheme;
}
/**
* Returns the root interface element of the page.
*
* @todo Can this be handled with a Lit Mixin?
*/
export function rootInterface<T extends ThemedElement = ThemedElement>(): T | null {
const element = document.body.querySelector<T>("[data-ak-interface-root]");