web: provide storybook demos and docs for existing tests (#11651)
* 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. * First pass at a custom, styled input object. * . * web: Demo the simple things. Fix things the Demo says need fixing. - Move the Element's stories into a `./stories` folder - Provide stories for (these are the same ones "provided tests for" in the [previous PR](https://github.com/goauthentik/authentik/pull/11633)) - Alert - Divider - Expand - Label - LoadingOverlay - Provide Storybook documentation for: - AppIcon - ActionButton - AggregateCard - AggregatePromiseCard - QuickActionsCard - Alert - Divider - EmptyState - Expand - Label - LoadingOverlay - ApplicationEmptyState - Fix a bug in LoadingOverlay; naming error in nested slots caused any message attached to the overlay to not sow up correctly. - Revise AppIcon to be independent of authentik; it just cares if the data has a name or an icon reference, it does not need to know about `Application` objects. As such, it's an *element*, not a *component*, and I've moved it into the right location, and updated the few places it is used to match. * Prettier has opinions with which I sometimes diverge. * Found a bug! Although pf-m-xl was defined as a legal size, there was no code to handle drawing something XL! * Found a few typos and incorrect API descriptions.
This commit is contained in:
98
web/src/elements/AppIcon.ts
Normal file
98
web/src/elements/AppIcon.ts
Normal file
@ -0,0 +1,98 @@
|
||||
import { PFSize } from "@goauthentik/common/enums.js";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import { P, match } from "ts-pattern";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
import PFFAIcons from "@patternfly/patternfly/base/patternfly-fa-icons.css";
|
||||
import PFAvatar from "@patternfly/patternfly/components/Avatar/avatar.css";
|
||||
|
||||
export interface IAppIcon {
|
||||
name?: string;
|
||||
icon?: string;
|
||||
size?: PFSize;
|
||||
}
|
||||
|
||||
@customElement("ak-app-icon")
|
||||
export class AppIcon extends AKElement implements IAppIcon {
|
||||
@property({ type: String })
|
||||
name?: string;
|
||||
|
||||
@property({ type: String })
|
||||
icon?: string;
|
||||
|
||||
@property()
|
||||
size: PFSize = PFSize.Medium;
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
PFFAIcons,
|
||||
PFAvatar,
|
||||
css`
|
||||
:host {
|
||||
max-height: calc(var(--icon-height) + var(--icon-border) + var(--icon-border));
|
||||
}
|
||||
:host([size="pf-m-lg"]) {
|
||||
--icon-height: 4rem;
|
||||
--icon-border: 0.25rem;
|
||||
}
|
||||
:host([size="pf-m-md"]) {
|
||||
--icon-height: 2rem;
|
||||
--icon-border: 0.125rem;
|
||||
}
|
||||
:host([size="pf-m-sm"]) {
|
||||
--icon-height: 1rem;
|
||||
--icon-border: 0.125rem;
|
||||
}
|
||||
:host([size="pf-m-xl"]) {
|
||||
--icon-height: 6rem;
|
||||
--icon-border: 0.25rem;
|
||||
}
|
||||
.pf-c-avatar {
|
||||
--pf-c-avatar--BorderRadius: 0;
|
||||
--pf-c-avatar--Height: calc(
|
||||
var(--icon-height) + var(--icon-border) + var(--icon-border)
|
||||
);
|
||||
--pf-c-avatar--Width: calc(
|
||||
var(--icon-height) + var(--icon-border) + var(--icon-border)
|
||||
);
|
||||
}
|
||||
.icon {
|
||||
font-size: var(--icon-height);
|
||||
color: var(--ak-global--Color--100);
|
||||
padding: var(--icon-border);
|
||||
max-height: calc(var(--icon-height) + var(--icon-border) + var(--icon-border));
|
||||
line-height: calc(var(--icon-height) + var(--icon-border) + var(--icon-border));
|
||||
filter: drop-shadow(5px 5px 5px rgba(128, 128, 128, 0.25));
|
||||
}
|
||||
div {
|
||||
height: calc(var(--icon-height) + var(--icon-border) + var(--icon-border));
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
// prettier-ignore
|
||||
return match([this.name, this.icon])
|
||||
.with([undefined, undefined],
|
||||
() => html`<div><i class="icon fas fa-question-circle"></i></div>`)
|
||||
.with([P._, P.string.startsWith("fa://")],
|
||||
([_name, icon]) => html`<div><i class="icon fas ${icon.replaceAll("fa://", "")}"></i></div>`)
|
||||
.with([P._, P.string],
|
||||
([_name, icon]) => html`<img class="icon pf-c-avatar" src="${icon}" alt="${msg("Application Icon")}" />`)
|
||||
.with([P.string, undefined],
|
||||
([name]) => html`<span class="icon">${name.charAt(0).toUpperCase()}</span>`)
|
||||
.exhaustive();
|
||||
}
|
||||
}
|
||||
|
||||
export default AppIcon;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ak-app-icon": AppIcon;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user