web: Gracefully handle missing element construction.

This commit is contained in:
Teffen Ellis
2026-04-23 02:38:54 +02:00
parent 805ff9f1ab
commit ef73bf6319
2 changed files with 45 additions and 1 deletions

View File

@@ -3,6 +3,7 @@ import { checkObjectShallowEquality } from "#common/collections";
import { AKElement } from "#elements/Base";
import { asInvoker, type ModalTemplate } from "#elements/dialogs/invokers";
import type { DialogInit, TransclusionElementConstructor } from "#elements/dialogs/shared";
import { ElementConstructorBoundary } from "#elements/errors/boundaries";
import type { LitPropertyRecord } from "#elements/types";
import { isAKElementConstructor, StrictUnsafe } from "#elements/utils/unsafe";
@@ -159,10 +160,22 @@ export function lookupElementConstructor<T extends CustomElementConstructor>(
tagName: string,
registry: CustomElementRegistry = window.customElements,
): T {
if (!tagName) {
// eslint-disable-next-line no-console
console.trace(
"No tag name provided for lookup. Did this value come from a different version of authentik?",
);
return ElementConstructorBoundary as unknown as T;
}
const ElementConstructor = registry.get(tagName);
if (!ElementConstructor) {
throw new TypeError(`No custom element defined for tag name: ${tagName}`);
// eslint-disable-next-line no-console
console.trace(`No custom element defined for tag name: ${tagName}`);
return ElementConstructorBoundary as unknown as T;
}
return ElementConstructor as unknown as T;

View File

@@ -0,0 +1,31 @@
import { AKElement } from "#elements/Base";
import { SlottedTemplateResult } from "#elements/types";
import { msg } from "@lit/localize";
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
import { html } from "lit-html";
import PFAlert from "@patternfly/patternfly/components/Alert/alert.css";
/**
* A fallback element to render when a custom element fails to load, either due to a missing import,
* or a version mismatch between the element's definition and its usage.
*/
@customElement("ak-element-missing")
export class ElementConstructorBoundary extends AKElement {
public styles = [PFAlert];
protected override render(): SlottedTemplateResult {
return html`<div class="pf-c-alert pf-m-danger" role="alert">
<div class="pf-c-alert__icon">
<i class="fas fa-exclamation-triangle" aria-hidden="true"></i>
</div>
<h4 class="pf-c-alert__title">${msg("Failed to load element")}</h4>
<div class="pf-c-alert__description">
${msg(
"The element could not be loaded. This may be due to a missing import or a version mismatch.",
)}
</div>
</div>`;
}
}