mirror of
https://github.com/goauthentik/authentik.git
synced 2026-06-17 19:09:11 +03:00
web: Fix server-side message race condition, type mismatch.
This commit is contained in:
@@ -16,18 +16,14 @@
|
||||
relBase: "{{ base_url_rel }}",
|
||||
},
|
||||
};
|
||||
window.addEventListener("DOMContentLoaded", function () {
|
||||
{% for message in messages %}
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("ak-message", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: {
|
||||
level: "{{ message.tags|escapejs }}",
|
||||
message: "{{ message.message|escapejs }}",
|
||||
},
|
||||
}),
|
||||
);
|
||||
{% endfor %}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script data-id="authentik-messages" type="application/json">
|
||||
[{% for message in messages %}
|
||||
{
|
||||
"level": "{{ message.tags|escapejs }}",
|
||||
"message": "{{ message.message|escapejs }}"
|
||||
}{% if not forloop.last %},{% endif %}
|
||||
{% endfor %}]
|
||||
</script>
|
||||
|
||||
|
||||
@@ -57,3 +57,23 @@ export function trimMany<T extends object, K extends keyof T>(target: T, ...keys
|
||||
|
||||
return output as Pick<T, K>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to parse a JSON string, returning a fallback value if parsing fails or if the input is not a string.
|
||||
*
|
||||
* @param input The input to parse.
|
||||
* @param fallback The fallback value to return if parsing fails or if the input is not a string. Defaults to `null`.
|
||||
*
|
||||
* @returns The parsed value, or the fallback value if parsing fails or if the input is not a string.
|
||||
*/
|
||||
export function tryParsingJSON<T = unknown>(input: unknown, fallback?: undefined): T | undefined;
|
||||
export function tryParsingJSON<T = unknown>(input: unknown, fallback: null): T | null;
|
||||
export function tryParsingJSON<T = unknown, F = null>(input: unknown, fallback?: F): T | F {
|
||||
if (typeof input !== "string") return (fallback ?? null) as F;
|
||||
|
||||
try {
|
||||
return JSON.parse(input);
|
||||
} catch {
|
||||
return (fallback ?? null) as F;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import "#elements/messages/Message";
|
||||
|
||||
import { parseAPIResponseError, pluckErrorDetail } from "#common/errors/network";
|
||||
import { APIMessage, MessageLevel } from "#common/messages";
|
||||
import { tryParsingJSON } from "#common/objects";
|
||||
|
||||
import { AKElement } from "#elements/Base";
|
||||
import Styles from "#elements/messages/styles.css";
|
||||
@@ -106,6 +107,8 @@ export type MessageContainerAlignment = "top-left" | "top-right" | "bottom-left"
|
||||
|
||||
@customElement("ak-message-container")
|
||||
export class MessageContainer extends AKElement {
|
||||
public static readonly serializedSelector = "script[data-id=authentik-messages]";
|
||||
|
||||
@property({ attribute: false })
|
||||
public messages: APIMessage[] = [];
|
||||
|
||||
@@ -129,8 +132,30 @@ export class MessageContainer extends AKElement {
|
||||
super.connectedCallback();
|
||||
|
||||
this.popover = "manual";
|
||||
|
||||
requestAnimationFrame(this.drainMessages);
|
||||
}
|
||||
|
||||
protected drainMessages = (): void => {
|
||||
const selector = (this.constructor as typeof MessageContainer).serializedSelector;
|
||||
const container = this.ownerDocument.querySelector<HTMLScriptElement>(selector);
|
||||
|
||||
if (!container) {
|
||||
logger.warn(`Expected to find a script tag with ${selector}, but none was found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const messages = tryParsingJSON<APIMessage[]>(container.textContent);
|
||||
|
||||
if (!messages?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const message of messages) {
|
||||
this.addMessage(message);
|
||||
}
|
||||
};
|
||||
|
||||
public updated(changedProperties: PropertyValues<this>) {
|
||||
super.updated(changedProperties);
|
||||
|
||||
|
||||
@@ -36,6 +36,24 @@ body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ak-c-safe-mode {
|
||||
position: fixed;
|
||||
z-index: 9999999;
|
||||
inset-block-end: 0;
|
||||
inset-inline-end: 0;
|
||||
pointer-events: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: var(--pf-global--FontSize--sm, 0.75rem);
|
||||
font-weight: bold;
|
||||
color: var(--pf-global--Color--100, CanvasText);
|
||||
background-color: var(--pf-global--BackgroundColor--200, Canvas);
|
||||
opacity: 0.75;
|
||||
padding: var(--pf-global--spacer--sm, 0.5rem);
|
||||
border-start-start-radius: 8px;
|
||||
}
|
||||
|
||||
/* #endregion */
|
||||
|
||||
html > form > input {
|
||||
|
||||
Reference in New Issue
Block a user