web: refactor status label to separate component (#7407)
* 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. * A quality of life thing: `<ak-status-label good>` There's an idiom throughout the UI: ``` HTML <ak-label color=${item.enabled ? PFColor.Green : PFColor.Red}> ${item.enabled ? msg("Yes") : msg("No")} </ak-label> ``` There are two problems with this. - Repeating the conditional multiple times is error-prone - The color scheme doesn't communicate much. There are uses for ak-label that aren't like this, but I'm focusing on this particular use case, which occurs about 20 times throughout the UI. Since it's so common, let's isolate the most common case: `<ak-status-label good />` gives you the "good" status, and `<ak-status-label/>` gives you the "bad" status, which is the default (no arguments to the function). There wasn't much clarity in the system for when to use orange vs red vs grey, but looking through the use cases, it became clear that Red meant fail/inaccessible, Orange meant "Warning, but not blocking," and Grey just means "info: this thing is off". So let's define that with meaning: there are three types, error, warning, and info. Which corresponds to debugging levels, but whatever, nerds grok that stuff. So that example at the top becomes ```<ak-status-label ?good=${item.enabled}></ak-status-label>``` ... and we can now more clearly understand what that conveys. There is some heavy tension in this case: this is an easier and quicker-to-write solution to informing the user of a binary status in an iconic way, but the developer has to remember that it exists. Story provided, and changes to the existing uses of the existing idiom provided. * Added the 'compact label' story to storybook.
This commit is contained in:
parent
bb52765f51
commit
73751e5cd9
|
@ -1,5 +1,5 @@
|
|||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import { Form } from "@goauthentik/elements/forms/Form";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
@ -57,9 +57,7 @@ export class ApplicationCheckAccessForm extends Form<{ forUser: number }> {
|
|||
<div class="pf-c-form__group-label">
|
||||
<div class="c-form__horizontal-group">
|
||||
<span class="pf-c-form__label-text">
|
||||
<ak-label color=${this.result?.passing ? PFColor.Green : PFColor.Red}>
|
||||
${this.result?.passing ? msg("Yes") : msg("No")}
|
||||
</ak-label>
|
||||
<ak-status-label ?good=${this.result?.passing}></ak-status-label>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,7 +2,7 @@ import "@goauthentik/admin/blueprints/BlueprintForm";
|
|||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { EVENT_REFRESH } from "@goauthentik/common/constants";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import "@goauthentik/elements/buttons/ActionButton";
|
||||
import "@goauthentik/elements/buttons/SpinnerButton";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
|
@ -144,9 +144,7 @@ export class BlueprintListPage extends TablePage<BlueprintInstance> {
|
|||
${description ? html`<small>${description}</small>` : html``}`,
|
||||
html`${BlueprintStatus(item)}`,
|
||||
html`${item.lastApplied.toLocaleString()}`,
|
||||
html`<ak-label color=${item.enabled ? PFColor.Green : PFColor.Red}>
|
||||
${item.enabled ? msg("Yes") : msg("No")}
|
||||
</ak-label>`,
|
||||
html`<ak-status-label ?good=${item.enabled}></ak-status-label>`,
|
||||
html`<ak-forms-modal>
|
||||
<span slot="submit"> ${msg("Update")} </span>
|
||||
<span slot="header"> ${msg("Update Blueprint")} </span>
|
||||
|
|
|
@ -2,6 +2,7 @@ import "@goauthentik/admin/crypto/CertificateGenerateForm";
|
|||
import "@goauthentik/admin/crypto/CertificateKeyPairForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/elements/buttons/SpinnerButton";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
|
@ -117,11 +118,12 @@ export class CertificateKeyPairListPage extends TablePage<CertificateKeyPair> {
|
|||
return [
|
||||
html`<div>${item.name}</div>
|
||||
${item.managed ? html`<small>${managedSubText}</small>` : html``}`,
|
||||
html`<ak-label color=${item.privateKeyAvailable ? PFColor.Green : PFColor.Grey}>
|
||||
${item.privateKeyAvailable
|
||||
? msg(str`Yes (${item.privateKeyType?.toUpperCase()})`)
|
||||
: msg("No")}
|
||||
</ak-label>`,
|
||||
html`<ak-status-label
|
||||
type="info"
|
||||
?good=${item.privateKeyAvailable}
|
||||
good-label=${msg(str`Yes (${item.privateKeyType?.toUpperCase()})`)}
|
||||
>
|
||||
</ak-status-label>`,
|
||||
html`<ak-label color=${color}> ${item.certExpiry?.toLocaleString()} </ak-label>`,
|
||||
html`<ak-forms-modal>
|
||||
<span slot="submit"> ${msg("Update")} </span>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { SentryIgnoredError } from "@goauthentik/common/errors";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import { Form } from "@goauthentik/elements/forms/Form";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
|
||||
|
@ -46,9 +46,7 @@ export class FlowImportForm extends Form<Flow> {
|
|||
<div class="pf-c-form__group-label">
|
||||
<div class="c-form__horizontal-group">
|
||||
<span class="pf-c-form__label-text">
|
||||
<ak-label color=${this.result?.success ? PFColor.Green : PFColor.Red}>
|
||||
${this.result?.success ? msg("Yes") : msg("No")}
|
||||
</ak-label>
|
||||
<ak-status-label ?good=${this.result?.success}></ak-status-label>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import "@goauthentik/admin/groups/GroupForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import "@goauthentik/elements/buttons/SpinnerButton";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
import "@goauthentik/elements/forms/ModalForm";
|
||||
|
@ -81,10 +81,8 @@ export class GroupListPage extends TablePage<Group> {
|
|||
html`<a href="#/identity/groups/${item.pk}">${item.name}</a>`,
|
||||
html`${item.parentName || msg("-")}`,
|
||||
html`${Array.from(item.users || []).length}`,
|
||||
html`<ak-label color=${item.isSuperuser ? PFColor.Green : PFColor.Grey}>
|
||||
${item.isSuperuser ? msg("Yes") : msg("No")}
|
||||
</ak-label>`,
|
||||
html` <ak-forms-modal>
|
||||
html`<ak-label type="info" ?good=${item.isSuperuser}></ak-label>`,
|
||||
html`<ak-forms-modal>
|
||||
<span slot="submit"> ${msg("Update")} </span>
|
||||
<span slot="header"> ${msg("Update Group")} </span>
|
||||
<ak-group-form slot="form" .instancePk=${item.pk}> </ak-group-form>
|
||||
|
|
|
@ -3,10 +3,10 @@ import "@goauthentik/app/admin/groups/RelatedUserList";
|
|||
import "@goauthentik/app/elements/rbac/ObjectPermissionsPage";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { EVENT_REFRESH } from "@goauthentik/common/constants";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import "@goauthentik/components/events/ObjectChangelog";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/elements/PageHeader";
|
||||
import "@goauthentik/elements/Tabs";
|
||||
import "@goauthentik/elements/buttons/ActionButton";
|
||||
|
@ -116,11 +116,10 @@ export class GroupViewPage extends AKElement {
|
|||
</dt>
|
||||
<dd class="pf-c-description-list__description">
|
||||
<div class="pf-c-description-list__text">
|
||||
<ak-label
|
||||
color=${this.group.isSuperuser
|
||||
? PFColor.Green
|
||||
: PFColor.Orange}
|
||||
></ak-label>
|
||||
<ak-status-label
|
||||
type="warning"
|
||||
?good${this.group.isSuperuser}
|
||||
></ak-status-label>
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import "@goauthentik/elements/buttons/SpinnerButton";
|
||||
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
|
||||
import { TableColumn } from "@goauthentik/elements/table/Table";
|
||||
|
@ -48,9 +48,7 @@ export class MemberSelectTable extends TableModal<User> {
|
|||
return [
|
||||
html`<div>${item.username}</div>
|
||||
<small>${item.name}</small>`,
|
||||
html` <ak-label color=${item.isActive ? PFColor.Green : PFColor.Orange}>
|
||||
${item.isActive ? msg("Yes") : msg("No")}
|
||||
</ak-label>`,
|
||||
html` <ak-status-label type="warning" ?good=${item.isActive}></ak-status-label>`,
|
||||
html`${first(item.lastLogin?.toLocaleString(), msg("-"))}`,
|
||||
];
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import "@goauthentik/admin/groups/GroupForm";
|
|||
import "@goauthentik/admin/users/GroupSelectModal";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import "@goauthentik/elements/buttons/SpinnerButton";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
import { Form } from "@goauthentik/elements/forms/Form";
|
||||
|
@ -145,9 +145,7 @@ export class RelatedGroupList extends Table<Group> {
|
|||
return [
|
||||
html`<a href="#/identity/groups/${item.pk}">${item.name}</a>`,
|
||||
html`${item.parentName || msg("-")}`,
|
||||
html`<ak-label color=${item.isSuperuser ? PFColor.Green : PFColor.Grey}>
|
||||
${item.isSuperuser ? msg("Yes") : msg("No")}
|
||||
</ak-label>`,
|
||||
html`<ak-label type="info" ?good=${item.isSuperuser}></ak-label>`,
|
||||
html` <ak-forms-modal>
|
||||
<span slot="submit"> ${msg("Update")} </span>
|
||||
<span slot="header"> ${msg("Update Group")} </span>
|
||||
|
|
|
@ -8,8 +8,8 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
|||
import { MessageLevel } from "@goauthentik/common/messages";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import { rootInterface } from "@goauthentik/elements/Base";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/elements/buttons/ActionButton";
|
||||
import "@goauthentik/elements/buttons/Dropdown";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
|
@ -195,9 +195,7 @@ export class RelatedUserList extends Table<User> {
|
|||
<div>${item.username}</div>
|
||||
<small>${item.name}</small>
|
||||
</a>`,
|
||||
html`<ak-label color=${item.isActive ? PFColor.Green : PFColor.Red}>
|
||||
${item.isActive ? msg("Yes") : msg("No")}
|
||||
</ak-label>`,
|
||||
html`<ak-status-label ?good=${item.isActive}></ak-status-label>`,
|
||||
html`${first(item.lastLogin?.toLocaleString(), msg("-"))}`,
|
||||
html`<ak-forms-modal>
|
||||
<span slot="submit"> ${msg("Update")} </span>
|
||||
|
|
|
@ -4,6 +4,7 @@ import "@goauthentik/admin/outposts/ServiceConnectionKubernetesForm";
|
|||
import "@goauthentik/admin/outposts/ServiceConnectionWizard";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/elements/buttons/SpinnerButton";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
|
@ -83,9 +84,7 @@ export class OutpostServiceConnectionListPage extends TablePage<ServiceConnectio
|
|||
return [
|
||||
html`${item.name}`,
|
||||
html`${item.verboseName}`,
|
||||
html`<ak-label color=${item.local ? PFColor.Grey : PFColor.Green}>
|
||||
${item.local ? msg("Yes") : msg("No")}
|
||||
</ak-label>`,
|
||||
html`<ak-status-label type="info" ?good=${item.local}></ak-status-label>`,
|
||||
html`${itemState?.healthy
|
||||
? html`<ak-label color=${PFColor.Green}>${ifDefined(itemState.version)}</ak-label>`
|
||||
: html`<ak-label color=${PFColor.Red}>${msg("Unhealthy")}</ak-label>`}`,
|
||||
|
|
|
@ -4,7 +4,7 @@ import "@goauthentik/admin/policies/PolicyWizard";
|
|||
import "@goauthentik/admin/users/UserForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import { PFSize } from "@goauthentik/elements/Spinner";
|
||||
import "@goauthentik/elements/Tabs";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
|
@ -147,9 +147,7 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
|||
return [
|
||||
html`<pre>${item.order}</pre>`,
|
||||
html`${this.getPolicyUserGroupRow(item)}`,
|
||||
html` <ak-label color=${item.enabled ? PFColor.Green : PFColor.Orange}>
|
||||
${item.enabled ? msg("Yes") : msg("No")}
|
||||
</ak-label>`,
|
||||
html`<ak-status-label type="warning" ?good=${item.enabled}></ak-status-label>`,
|
||||
html`${item.timeout}`,
|
||||
html` ${this.getObjectEditButton(item)}
|
||||
<ak-forms-modal size=${PFSize.Medium}>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import { Form } from "@goauthentik/elements/forms/Form";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
@ -58,9 +58,7 @@ export class PolicyTestForm extends Form<PolicyTestRequest> {
|
|||
<div class="pf-c-form__group-label">
|
||||
<div class="c-form__horizontal-group">
|
||||
<span class="pf-c-form__label-text">
|
||||
<ak-label color=${this.result?.passing ? PFColor.Green : PFColor.Red}>
|
||||
${this.result?.passing ? msg("Yes") : msg("No")}
|
||||
</ak-label>
|
||||
<ak-status-label ?good=${this.result?.passing}></ak-status-label>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4,6 +4,7 @@ import "@goauthentik/app/elements/rbac/ObjectPermissionsPage";
|
|||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { EVENT_REFRESH } from "@goauthentik/common/constants";
|
||||
import { convertToSlug } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import "@goauthentik/components/events/ObjectChangelog";
|
||||
import MDCaddyStandalone from "@goauthentik/docs/providers/proxy/_caddy_standalone.md";
|
||||
import MDNginxIngress from "@goauthentik/docs/providers/proxy/_nginx_ingress.md";
|
||||
|
@ -15,7 +16,6 @@ import MDTraefikStandalone from "@goauthentik/docs/providers/proxy/_traefik_stan
|
|||
import MDHeaderAuthentication from "@goauthentik/docs/providers/proxy/header_authentication.md";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/elements/Markdown";
|
||||
import "@goauthentik/elements/Markdown";
|
||||
import { Replacer } from "@goauthentik/elements/Markdown";
|
||||
|
@ -330,15 +330,10 @@ export class ProxyProviderViewPage extends AKElement {
|
|||
</dt>
|
||||
<dd class="pf-c-description-list__description">
|
||||
<div class="pf-c-description-list__text">
|
||||
<ak-label
|
||||
color=${this.provider.basicAuthEnabled
|
||||
? PFColor.Green
|
||||
: PFColor.Grey}
|
||||
>
|
||||
${this.provider.basicAuthEnabled
|
||||
? msg("Yes")
|
||||
: msg("No")}
|
||||
</ak-label>
|
||||
<ak-status-label
|
||||
type="info"
|
||||
?good=${this.provider.basicAuthEnabled}
|
||||
></ak-status-label>
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import "@goauthentik/admin/tenants/TenantForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import "@goauthentik/elements/buttons/SpinnerButton";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
import "@goauthentik/elements/forms/ModalForm";
|
||||
|
@ -82,9 +83,7 @@ export class TenantListPage extends TablePage<Tenant> {
|
|||
row(item: Tenant): TemplateResult[] {
|
||||
return [
|
||||
html`${item.domain}`,
|
||||
html`<ak-label color=${item._default ? PFColor.Green : PFColor.Red}>
|
||||
${item._default ? msg("Yes") : msg("No")}
|
||||
</ak-label>`,
|
||||
html`<ak-status-label ?good=${item._default}></ak-status-label>`,
|
||||
html`<ak-forms-modal>
|
||||
<span slot="submit"> ${msg("Update")} </span>
|
||||
<span slot="header"> ${msg("Update Tenant")} </span>
|
||||
|
|
|
@ -2,7 +2,7 @@ import "@goauthentik/admin/tokens/TokenForm";
|
|||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { intentToLabel } from "@goauthentik/common/labels";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import "@goauthentik/elements/buttons/Dropdown";
|
||||
import "@goauthentik/elements/buttons/TokenCopyButton";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
|
@ -109,9 +109,7 @@ export class TokenListPage extends TablePage<Token> {
|
|||
? html`<small>${msg("Token is managed by authentik.")}</small>`
|
||||
: html``}`,
|
||||
html`<a href="#/identity/users/${item.userObj?.pk}">${item.userObj?.username}</a>`,
|
||||
html` <ak-label color=${item.expiring ? PFColor.Green : PFColor.Orange}>
|
||||
${item.expiring ? msg("Yes") : msg("No")}
|
||||
</ak-label>`,
|
||||
html`<ak-status-label type="warning" ?good=${item.expiring}></ak-status-label>`,
|
||||
html`${item.expiring ? item.expires?.toLocaleString() : msg("-")}`,
|
||||
html`${intentToLabel(item.intent ?? IntentEnum.Api)}`,
|
||||
html`
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import "@goauthentik/elements/buttons/SpinnerButton";
|
||||
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
|
||||
import { TableColumn } from "@goauthentik/elements/table/Table";
|
||||
|
@ -54,9 +54,7 @@ export class GroupSelectModal extends TableModal<Group> {
|
|||
html`<div>
|
||||
<div>${item.name}</div>
|
||||
</div>`,
|
||||
html` <ak-label color=${item.isSuperuser ? PFColor.Green : PFColor.Grey}>
|
||||
${item.isSuperuser ? msg("Yes") : msg("No")}
|
||||
</ak-label>`,
|
||||
html` <ak-status-label type="info" ?good=${item.isSuperuser}></ak-status-label>`,
|
||||
html`${(item.users || []).length}`,
|
||||
];
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ import { userTypeToLabel } from "@goauthentik/common/labels";
|
|||
import { MessageLevel } from "@goauthentik/common/messages";
|
||||
import { DefaultUIConfig, uiConfig } from "@goauthentik/common/ui/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import { rootInterface } from "@goauthentik/elements/Base";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import { PFSize } from "@goauthentik/elements/Spinner";
|
||||
import "@goauthentik/elements/TreeView";
|
||||
import "@goauthentik/elements/buttons/ActionButton";
|
||||
|
@ -251,9 +251,7 @@ export class UserListPage extends TablePage<User> {
|
|||
<div>${item.username}</div>
|
||||
<small>${item.name === "" ? msg("<No name set>") : item.name}</small> </a
|
||||
> <small>${userTypeToLabel(item.type)}</small>`,
|
||||
html`<ak-label color=${item.isActive ? PFColor.Green : PFColor.Red}>
|
||||
${item.isActive ? msg("Yes") : msg("No")}
|
||||
</ak-label>`,
|
||||
html`<ak-status-label ?good=${item.isActive}></ak-status-label>`,
|
||||
html`${first(item.lastLogin?.toLocaleString(), msg("-"))}`,
|
||||
html`<ak-forms-modal>
|
||||
<span slot="submit"> ${msg("Update")} </span>
|
||||
|
|
|
@ -14,11 +14,11 @@ import "@goauthentik/app/elements/rbac/ObjectPermissionsPage";
|
|||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { EVENT_REFRESH } from "@goauthentik/common/constants";
|
||||
import { userTypeToLabel } from "@goauthentik/common/labels";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import "@goauthentik/components/events/ObjectChangelog";
|
||||
import "@goauthentik/components/events/UserEvents";
|
||||
import { AKElement, rootInterface } from "@goauthentik/elements/Base";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/elements/PageHeader";
|
||||
import { PFSize } from "@goauthentik/elements/Spinner";
|
||||
import "@goauthentik/elements/Tabs";
|
||||
|
@ -185,9 +185,10 @@ export class UserViewPage extends AKElement {
|
|||
</dt>
|
||||
<dd class="pf-c-description-list__description">
|
||||
<div class="pf-c-description-list__text">
|
||||
<ak-label
|
||||
color=${user.isActive ? PFColor.Green : PFColor.Orange}
|
||||
></ak-label>
|
||||
<ak-status-label
|
||||
type="warning"
|
||||
?good=${user.isActive}
|
||||
></ak-status-label>
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
|
@ -207,9 +208,10 @@ export class UserViewPage extends AKElement {
|
|||
</dt>
|
||||
<dd class="pf-c-description-list__description">
|
||||
<div class="pf-c-description-list__text">
|
||||
<ak-label
|
||||
color=${user.isSuperuser ? PFColor.Green : PFColor.Orange}
|
||||
></ak-label>
|
||||
<ak-status-label
|
||||
type="warning"
|
||||
?good=${user.isSuperuser}
|
||||
></ak-status-label>
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
|
|
116
web/src/components/ak-status-label.ts
Normal file
116
web/src/components/ak-status-label.ts
Normal file
|
@ -0,0 +1,116 @@
|
|||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { css, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { classMap } from "lit/directives/class-map.js";
|
||||
|
||||
import PFLabel from "@patternfly/patternfly/components/Label/label.css";
|
||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
|
||||
const statusNames = ["error", "warning", "info"] as const;
|
||||
type StatusName = (typeof statusNames)[number];
|
||||
|
||||
const statusToDetails = new Map<StatusName, [string, string]>([
|
||||
["error", ["pf-m-red", "fa-times"]],
|
||||
["warning", ["pf-m-orange", "fa-exclamation-triangle"]],
|
||||
["info", ["pf-m-gray", "fa-info-circle"]],
|
||||
]);
|
||||
|
||||
const styles = css`
|
||||
:host {
|
||||
--pf-c-label--m-gray--BackgroundColor: var(--pf-global--palette--black-100);
|
||||
--pf-c-label--m-gray__icon--Color: var(--pf-global--primary-color--100);
|
||||
--pf-c-label--m-gray__content--Color: var(--pf-global--info-color--200);
|
||||
--pf-c-label--m-gray__content--before--BorderColor: var(--pf-global--palette--black-400);
|
||||
--pf-c-label--m-gray__content--link--hover--before--BorderColor: var(
|
||||
--pf-global--primary-color--100
|
||||
);
|
||||
--pf-c-label--m-gray__content--link--focus--before--BorderColor: var(
|
||||
--pf-global--primary-color--100
|
||||
);
|
||||
}
|
||||
|
||||
.pf-c-label.pf-m-gray {
|
||||
--pf-c-label--BackgroundColor: var(--pf-c-label--m-gray--BackgroundColor);
|
||||
--pf-c-label__icon--Color: var(--pf-c-label--m-gray__icon--Color);
|
||||
--pf-c-label__content--Color: var(--pf-c-label--m-gray__content--Color);
|
||||
--pf-c-label__content--before--BorderColor: var(
|
||||
--pf-c-label--m-gray__content--before--BorderColor
|
||||
);
|
||||
--pf-c-label__content--link--hover--before--BorderColor: var(
|
||||
--pf-c-label--m-gray__content--link--hover--before--BorderColor
|
||||
);
|
||||
--pf-c-label__content--link--focus--before--BorderColor: var(
|
||||
--pf-c-label--m-gray__content--link--focus--before--BorderColor
|
||||
);
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* A boolean status indicator
|
||||
*
|
||||
* Based on the Patternfly "label" pattern, this component exists to display "Yes" or "No", but this
|
||||
* is configurable.
|
||||
*
|
||||
* When the boolean attribute `good` is present, the background will be green and the icon will be a
|
||||
* ✓. If the `good` attribute is not present, the background will be a warning color and an
|
||||
* alternative symbol. Which color and symbol depends on the `type` of the negative status we want
|
||||
* to show:
|
||||
*
|
||||
* - type="error" (default): A Red ✖
|
||||
* - type="warning" An orange ⚠
|
||||
* - type="info" A grey ⓘ
|
||||
*
|
||||
* By default, the messages for "good" and "other" are "Yes" and "No" respectively, but these can be
|
||||
* customized with the attributes `good-label` and `bad-label`.
|
||||
*/
|
||||
|
||||
@customElement("ak-status-label")
|
||||
export class AkStatusLabel extends AKElement {
|
||||
static get styles() {
|
||||
return [PFBase, PFLabel, styles];
|
||||
}
|
||||
|
||||
@property({ type: Boolean })
|
||||
good = false;
|
||||
|
||||
@property({ type: String, attribute: "good-label" })
|
||||
goodLabel = msg("Yes");
|
||||
|
||||
@property({ type: String, attribute: "bad-label" })
|
||||
badLabel = msg("No");
|
||||
|
||||
@property({ type: Boolean })
|
||||
compact = false;
|
||||
|
||||
@property({ type: String })
|
||||
type: StatusName = "error";
|
||||
|
||||
render() {
|
||||
const details = statusToDetails.get(this.type);
|
||||
if (!details) {
|
||||
throw new Error(`Bad status type [${this.type}] passed to ak-status-label`);
|
||||
}
|
||||
|
||||
const [label, color, icon] = this.good
|
||||
? [this.goodLabel, "pf-m-green", "fa-check"]
|
||||
: [this.badLabel, ...details];
|
||||
|
||||
const classes = {
|
||||
"pf-c-label": true,
|
||||
[color]: true,
|
||||
"pf-m-compact": this.compact,
|
||||
};
|
||||
|
||||
return html`<span class="${classMap(classes)}">
|
||||
<span class="pf-c-label__content">
|
||||
<span class="pf-c-label__icon">
|
||||
<i class="fas fa-fw ${icon}" aria-hidden="true"></i> </span
|
||||
>${label}
|
||||
</span>
|
||||
</span>`;
|
||||
}
|
||||
}
|
||||
|
||||
export default AkStatusLabel;
|
101
web/src/components/stories/ak-status-label.stories.ts
Normal file
101
web/src/components/stories/ak-status-label.stories.ts
Normal file
|
@ -0,0 +1,101 @@
|
|||
import "@goauthentik/elements/messages/MessageContainer";
|
||||
import { Meta } from "@storybook/web-components";
|
||||
|
||||
import { TemplateResult, html } from "lit";
|
||||
|
||||
import "../ak-status-label";
|
||||
import AkStatusLabel from "../ak-status-label";
|
||||
|
||||
const metadata: Meta<AkStatusLabel> = {
|
||||
title: "Components / App Status Label",
|
||||
component: "ak-status-label",
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component: "A status label display",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default metadata;
|
||||
|
||||
const container = (testItem: TemplateResult) =>
|
||||
html` <div style="background: #fff; padding: 2em">
|
||||
<style>
|
||||
dl {
|
||||
display: grid;
|
||||
grid-template-columns: 22ch 1fr;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
${testItem}
|
||||
</div>`;
|
||||
|
||||
export const AppIcon = () => {
|
||||
// prettier-ignore
|
||||
return container(html`
|
||||
<dl>
|
||||
<dt>Good</dt><dd>
|
||||
|
||||
<ak-status-label good></ak-status-label>
|
||||
|
||||
</dd>
|
||||
<dt>Bad (Default)</dt><dd>
|
||||
|
||||
<ak-status-label></ak-status-label>
|
||||
|
||||
</dd>
|
||||
<dt>Programmatically Good</dt><dd>
|
||||
|
||||
<ak-status-label ?good=${true}></ak-status-label>
|
||||
|
||||
</dd>
|
||||
<dt>Programmatically Bad</dt><dd>
|
||||
|
||||
<ak-status-label ?good=${false}></ak-status-label>
|
||||
|
||||
</dd>
|
||||
<dt>Good Warning</dt><dd>
|
||||
|
||||
<ak-status-label type="warning" good></ak-status-label>
|
||||
|
||||
</dd>
|
||||
<dt>Bad Warning</dt><dd>
|
||||
|
||||
<ak-status-label type="warning"></ak-status-label>
|
||||
|
||||
</dd>
|
||||
<dt>Good Info</dt><dd>
|
||||
|
||||
<ak-status-label type="info" good></ak-status-label>
|
||||
|
||||
</dd>
|
||||
<dt>Bad Info</dt><dd>
|
||||
|
||||
<ak-status-label type="info"></ak-status-label>
|
||||
|
||||
</dd>
|
||||
<dt>Good With Alternative Message</dt><dd>
|
||||
|
||||
<ak-status-label good good-label="Hurray!" bad-label="Boo!"></ak-status-label>
|
||||
|
||||
</dd>
|
||||
<dt>Bad with Alternative Message</dt><dd>
|
||||
|
||||
<ak-status-label good-label="Hurray!" bad-label="Boo!"></ak-status-label>
|
||||
|
||||
</dd>
|
||||
<dt>Good, Compact</dt><dd>
|
||||
|
||||
<ak-status-label good compact></ak-status-label>
|
||||
|
||||
</dd>
|
||||
<dt>Bad, Compact</dt><dd>
|
||||
|
||||
<ak-status-label compact></ak-status-label>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
`);
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
|
||||
import { Table, TableColumn } from "@goauthentik/elements/table/Table";
|
||||
|
@ -85,9 +85,7 @@ export class UserOAuthRefreshList extends Table<TokenModel> {
|
|||
row(item: TokenModel): TemplateResult[] {
|
||||
return [
|
||||
html`<a href="#/core/providers/${item.provider?.pk}"> ${item.provider?.name} </a>`,
|
||||
html`<ak-label color=${item.revoked ? PFColor.Orange : PFColor.Green}>
|
||||
${item.revoked ? msg("Yes") : msg("No")}
|
||||
</ak-label>`,
|
||||
html`<ak-status-label type="warning" ?good=${item.revoked}></ak-status-label>`,
|
||||
html`${item.expires?.toLocaleString()}`,
|
||||
html`${item.scope.join(", ")}`,
|
||||
];
|
||||
|
|
|
@ -2,7 +2,7 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
|||
import { intentToLabel } from "@goauthentik/common/labels";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import { me } from "@goauthentik/common/users";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import "@goauthentik/elements/buttons/Dropdown";
|
||||
import "@goauthentik/elements/buttons/ModalButton";
|
||||
import "@goauthentik/elements/buttons/TokenCopyButton";
|
||||
|
@ -97,9 +97,7 @@ export class UserTokenList extends Table<Token> {
|
|||
</dt>
|
||||
<dd class="pf-c-description-list__description">
|
||||
<div class="pf-c-description-list__text">
|
||||
<ak-label color=${item.expiring ? PFColor.Green : PFColor.Red}>
|
||||
${item.expiring ? msg("Yes") : msg("No")}
|
||||
</ak-label>
|
||||
<ak-status-label ?good=${item.expiring}></ak-status-label>
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
|
|
Reference in a new issue