mirror of
https://github.com/goauthentik/authentik
synced 2026-05-12 01:47:06 +02:00
* Added tests and refinements as tests indicate. * Building out the test suite. * web: test the simple things. Fix what the tests revealed. - Move `EmptyState.test.ts` into the `./tests` folder. - Provide unit tests for: - Alert - Divider - Expand - Label - LoadingOverlay - Give all tested items an Interface and a functional variant for rendering - Give Label an alternative syntax for declaring alert levels - Remove the slot name in LoadingOverlay - Change the slot call in `./enterprise/rac/index.ts` to not need the slot name as well - Change the attribute names `topMost`, `textOpen`, and `textClosed` to `topmost`, `text-open`, and `text-closed`, respectively. - Change locations in the code where those are used to correspond ** Why interfaces: ** Provides another check on the input/output boundaries of our elements, gives Storybook and WebdriverIO another validation to check, and guarantees any rendering functions cannot be passed invalid property names. ** Why functions for rendering: ** Providing functions for rendering gets us one step closer to dynamically defining our forms-in-code at runtime without losing any type safety. ** Why rename the attributes: ** A *very* subtle bug: [Element:setAttribute()](https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute) automatically "converts an attribute name to all lower-case when called on an HTML element in an HTML document." The three attributes renamed are all treated *as* attributes, either classic boolean or stringly-typed attributes, and attempting to manipulate them with `setAttribute()` will fail. All of these attributes are presentational; none of them end up in a transaction with the back-end, so kebab-to-camel conversions are not a concern. Also, ["topmost" is one word](https://www.merriam-webster.com/dictionary/topmost). ** Why remove the slot name: ** Because there was only one slot. A name is not needed. * Fix minor spelling error.
87 lines
2.8 KiB
TypeScript
87 lines
2.8 KiB
TypeScript
import { PFSize } from "@goauthentik/common/enums.js";
|
|
import { AKElement } from "@goauthentik/elements/Base";
|
|
import "@goauthentik/elements/Spinner";
|
|
import { type SlottedTemplateResult, type Spread } from "@goauthentik/elements/types";
|
|
import { spread } from "@open-wc/lit-helpers";
|
|
|
|
import { msg } from "@lit/localize";
|
|
import { css, html, nothing } from "lit";
|
|
import { customElement, property } from "lit/decorators.js";
|
|
|
|
import PFEmptyState from "@patternfly/patternfly/components/EmptyState/empty-state.css";
|
|
import PFTitle from "@patternfly/patternfly/components/Title/title.css";
|
|
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
|
|
|
export interface IEmptyState {
|
|
icon?: string;
|
|
loading?: boolean;
|
|
fullHeight?: boolean;
|
|
header?: string;
|
|
}
|
|
|
|
@customElement("ak-empty-state")
|
|
export class EmptyState extends AKElement implements IEmptyState {
|
|
@property({ type: String })
|
|
icon = "";
|
|
|
|
@property({ type: Boolean })
|
|
loading = false;
|
|
|
|
@property({ type: Boolean })
|
|
fullHeight = false;
|
|
|
|
@property()
|
|
header?: string;
|
|
|
|
static get styles() {
|
|
return [
|
|
PFBase,
|
|
PFEmptyState,
|
|
PFTitle,
|
|
css`
|
|
i.pf-c-empty-state__icon {
|
|
height: var(--pf-global--icon--FontSize--2xl);
|
|
line-height: var(--pf-global--icon--FontSize--2xl);
|
|
}
|
|
`,
|
|
];
|
|
}
|
|
|
|
render() {
|
|
return html`<div class="pf-c-empty-state ${this.fullHeight && "pf-m-full-height"}">
|
|
<div class="pf-c-empty-state__content">
|
|
${this.loading
|
|
? html`<div class="pf-c-empty-state__icon">
|
|
<ak-spinner size=${PFSize.XLarge}></ak-spinner>
|
|
</div>`
|
|
: html`<i
|
|
class="pf-icon fa ${this.icon ||
|
|
"fa-question-circle"} pf-c-empty-state__icon"
|
|
aria-hidden="true"
|
|
></i>`}
|
|
<h1 class="pf-c-title pf-m-lg">
|
|
${this.loading && this.header === undefined ? msg("Loading") : this.header}
|
|
</h1>
|
|
<div class="pf-c-empty-state__body">
|
|
<slot name="body"></slot>
|
|
</div>
|
|
<div class="pf-c-empty-state__primary">
|
|
<slot name="primary"></slot>
|
|
</div>
|
|
</div>
|
|
</div>`;
|
|
}
|
|
}
|
|
|
|
export function akEmptyState(properties: IEmptyState, content: SlottedTemplateResult = nothing) {
|
|
const message =
|
|
typeof content === "string" ? html`<span slot="body">${content}</span>` : content;
|
|
return html`<ak-empty-state ${spread(properties as Spread)}>${message}</ak-empty-state>`;
|
|
}
|
|
|
|
declare global {
|
|
interface HTMLElementTagNameMap {
|
|
"ak-empty-state": EmptyState;
|
|
}
|
|
}
|