web: replace 'description-list' with list of descriptions (#7392)
* web: break circular dependency between AKElement & Interface. This commit changes the way the root node of the web application shell is discovered by child components, such that the base class shared by both no longer results in a circular dependency between the two models. I've run this in isolation and have seen no failures of discovery; the identity token exists as soon as the Interface is constructed and is found by every item on the page. * web: fix broken typescript references This built... and then it didn't? Anyway, the current fix is to provide type information the AkInterface for the data that consumers require. * web: description lists as functions One thing I hate is clutter. Just tell me what you're going to do. "Description Lists" in our code are renderings of Patternfly's DescriptionList; we use only four of their idioms: horizontal, compact, 2col, and 3col. With that in mind, I've stripped out the DescriptionList rendering code from UserViewPage and replaced it with a list of "Here's what to render" and a function call to render them. The calling code is still responsible for having the right styles available, as this is not a component or an attempt at isolation; it is *just* a function (at this point). * web: fix issue that prevented the classMap from being rendered properly * web: added comments to the description list. * web: analyze & prettier had opinions * web: Fix description-list demo This commit re-instals the demo for the "description list" of user fields. * web: prettier had opinions. * any -> unknown Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> Co-authored-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
94
web/src/components/DescriptionList.ts
Normal file
94
web/src/components/DescriptionList.ts
Normal file
@ -0,0 +1,94 @@
|
||||
import { TemplateResult, html, nothing } from "lit";
|
||||
import { classMap } from "lit/directives/class-map.js";
|
||||
import { map } from "lit/directives/map.js";
|
||||
|
||||
export type DescriptionDesc = string | TemplateResult | undefined | typeof nothing;
|
||||
export type DescriptionPair = [string, DescriptionDesc];
|
||||
export type DescriptionRecord = { term: string; desc: DescriptionDesc };
|
||||
|
||||
interface DescriptionConfig {
|
||||
horizontal: boolean;
|
||||
compact: boolean;
|
||||
twocolumn: boolean;
|
||||
threecolumn: boolean;
|
||||
}
|
||||
|
||||
const isDescriptionRecordCollection = (v: Array<unknown>): v is DescriptionRecord[] =>
|
||||
v.length > 0 && typeof v[0] === "object" && !Array.isArray(v[0]);
|
||||
|
||||
function renderDescriptionGroup([term, description]: DescriptionPair) {
|
||||
return html` <div class="pf-c-description-list__group">
|
||||
<dt class="pf-c-description-list__term">
|
||||
<span class="pf-c-description-list__text">${term}</span>
|
||||
</dt>
|
||||
<dd class="pf-c-description-list__description">
|
||||
<div class="pf-c-description-list__text">${description ?? nothing}</div>
|
||||
</dd>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function recordToPair({ term, desc }: DescriptionRecord): DescriptionPair {
|
||||
return [term, desc];
|
||||
}
|
||||
|
||||
function alignTermType(terms: DescriptionRecord[] | DescriptionPair[] = []) {
|
||||
if (isDescriptionRecordCollection(terms)) {
|
||||
return terms.map(recordToPair);
|
||||
}
|
||||
return terms ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* renderDescriptionList
|
||||
*
|
||||
* This function renders the most common form of the PatternFly description list used in our code.
|
||||
* It expects either an array of term/description pairs or an array of `{ term: string, description:
|
||||
* string | TemplateResult }`.
|
||||
*
|
||||
* An optional dictionary of configuration options is available. These enable the Patternfly
|
||||
* "horizontal," "compact", "2 column on large," or "3 column on large" layouts that are (so far)
|
||||
* the layouts used in Authentik's (and Gravity's, for that matter) code.
|
||||
*
|
||||
* This is not a web component and it does not bring its own styling ; calling code will still have
|
||||
* to provide the styling necessary. It is only a function to replace the repetitious boilerplate of
|
||||
* routine description lists. Its output is a standard TemplateResult that will be fully realized
|
||||
* within the context of the DOM or ShadowDOM in which it is called.
|
||||
*/
|
||||
|
||||
const defaultConfig = {
|
||||
horizontal: false,
|
||||
compact: false,
|
||||
twocolumn: false,
|
||||
threecolumn: false,
|
||||
};
|
||||
|
||||
export function renderDescriptionList(
|
||||
terms: DescriptionRecord[],
|
||||
config?: DescriptionConfig,
|
||||
): TemplateResult;
|
||||
|
||||
export function renderDescriptionList(
|
||||
terms: DescriptionPair[],
|
||||
config?: DescriptionConfig,
|
||||
): TemplateResult;
|
||||
|
||||
export function renderDescriptionList(
|
||||
terms: DescriptionRecord[] | DescriptionPair[] = [],
|
||||
config: DescriptionConfig = defaultConfig,
|
||||
) {
|
||||
const checkedTerms = alignTermType(terms);
|
||||
const classes = classMap({
|
||||
"pf-m-horizontal": config.horizontal,
|
||||
"pf-m-compact": config.compact,
|
||||
"pf-m-2-col-on-lg": config.twocolumn,
|
||||
"pf-m-3-col-on-lg": config.threecolumn,
|
||||
});
|
||||
|
||||
return html`
|
||||
<dl class="pf-c-description-list ${classes}">
|
||||
${map(checkedTerms, renderDescriptionGroup)}
|
||||
</dl>
|
||||
`;
|
||||
}
|
||||
|
||||
export default renderDescriptionList;
|
||||
Reference in New Issue
Block a user