Compare commits
42 Commits
monorepo-v
...
web/legibi
Author | SHA1 | Date | |
---|---|---|---|
8f995aab62 | |||
2846e49657 | |||
0e60e755d4 | |||
6cf2433e2b | |||
e1d565d40e | |||
ee37e9235b | |||
8248163958 | |||
9acebec1f6 | |||
2a96900dc7 | |||
ca42506fa0 | |||
34de6bfd3a | |||
2d94b16411 | |||
98503f6009 | |||
ac4ba5d9e2 | |||
f19ed14bf8 | |||
085debf170 | |||
cacdf64408 | |||
23665d173f | |||
272fdc516b | |||
b08dcc2289 | |||
c84be1d961 | |||
875fc5c735 | |||
66cefcc918 | |||
5d4c38032f | |||
7123b2c57b | |||
fc00bdee63 | |||
a056703da0 | |||
3f9502072d | |||
2d254d6a7e | |||
a7e3dca917 | |||
5d8408287f | |||
30beca9118 | |||
8946b81dbd | |||
db96e1a901 | |||
8b4e0361c4 | |||
22cb5b7379 | |||
2d0117d096 | |||
035bda4eac | |||
50906214e5 | |||
e505f274b6 | |||
fe52f44dca | |||
3146e5a50f |
@ -3,7 +3,6 @@ import "@goauthentik/admin/applications/ApplicationCheckAccessForm";
|
||||
import "@goauthentik/admin/applications/ApplicationForm";
|
||||
import "@goauthentik/admin/policies/BoundPoliciesList";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { PFSize } from "@goauthentik/common/enums.js";
|
||||
import "@goauthentik/components/ak-app-icon";
|
||||
import "@goauthentik/components/events/ObjectChangelog";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
@ -13,10 +12,8 @@ import "@goauthentik/elements/Tabs";
|
||||
import "@goauthentik/elements/buttons/SpinnerButton";
|
||||
import "@goauthentik/elements/rbac/ObjectPermissionsPage";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { CSSResult, PropertyValues, TemplateResult, html } from "lit";
|
||||
import { PropertyValues } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import PFBanner from "@patternfly/patternfly/components/Banner/banner.css";
|
||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||
@ -35,18 +32,14 @@ import {
|
||||
RbacPermissionsAssignedByUsersListModelEnum,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
import {
|
||||
ApplicationViewPageLoadingRenderer,
|
||||
ApplicationViewPageRenderer,
|
||||
} from "./ApplicationViewPageRenderers.js";
|
||||
|
||||
@customElement("ak-application-view")
|
||||
export class ApplicationViewPage extends AKElement {
|
||||
@property({ type: String })
|
||||
applicationSlug?: string;
|
||||
|
||||
@state()
|
||||
application?: Application;
|
||||
|
||||
@state()
|
||||
missingOutpost = false;
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
static get styles() {
|
||||
return [
|
||||
PFBase,
|
||||
PFList,
|
||||
@ -60,6 +53,15 @@ export class ApplicationViewPage extends AKElement {
|
||||
];
|
||||
}
|
||||
|
||||
@property({ type: String })
|
||||
applicationSlug?: string;
|
||||
|
||||
@state()
|
||||
application?: Application;
|
||||
|
||||
@state()
|
||||
missingOutpost = false;
|
||||
|
||||
fetchIsMissingOutpost(providersByPk: Array<number>) {
|
||||
new OutpostsApi(DEFAULT_CONFIG)
|
||||
.outpostsInstancesList({
|
||||
@ -94,231 +96,15 @@ export class ApplicationViewPage extends AKElement {
|
||||
}
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
return html`<ak-page-header
|
||||
header=${this.application?.name || msg("Loading")}
|
||||
description=${ifDefined(this.application?.metaPublisher)}
|
||||
.iconImage=${true}
|
||||
>
|
||||
<ak-app-icon
|
||||
size=${PFSize.Medium}
|
||||
slot="icon"
|
||||
.app=${this.application}
|
||||
></ak-app-icon>
|
||||
</ak-page-header>
|
||||
${this.renderApp()}`;
|
||||
}
|
||||
render() {
|
||||
const renderer = this.application
|
||||
? new ApplicationViewPageRenderer(
|
||||
this.application,
|
||||
this.missingOutpost,
|
||||
RbacPermissionsAssignedByUsersListModelEnum.CoreApplication,
|
||||
)
|
||||
: new ApplicationViewPageLoadingRenderer();
|
||||
|
||||
renderApp(): TemplateResult {
|
||||
if (!this.application) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
}
|
||||
return html`<ak-tabs>
|
||||
${this.missingOutpost
|
||||
? html`<div slot="header" class="pf-c-banner pf-m-warning">
|
||||
${msg("Warning: Application is not used by any Outpost.")}
|
||||
</div>`
|
||||
: html``}
|
||||
<section
|
||||
slot="page-overview"
|
||||
data-tab-title="${msg("Overview")}"
|
||||
class="pf-c-page__main-section pf-m-no-padding-mobile"
|
||||
>
|
||||
<div class="pf-l-grid pf-m-gutter">
|
||||
<div
|
||||
class="pf-c-card pf-l-grid__item pf-m-12-col pf-m-2-col-on-xl pf-m-2-col-on-2xl"
|
||||
>
|
||||
<div class="pf-c-card__title">${msg("Related")}</div>
|
||||
<div class="pf-c-card__body">
|
||||
<dl class="pf-c-description-list">
|
||||
${this.application.providerObj
|
||||
? html`<div class="pf-c-description-list__group">
|
||||
<dt class="pf-c-description-list__term">
|
||||
<span class="pf-c-description-list__text"
|
||||
>${msg("Provider")}</span
|
||||
>
|
||||
</dt>
|
||||
<dd class="pf-c-description-list__description">
|
||||
<div class="pf-c-description-list__text">
|
||||
<a
|
||||
href="#/core/providers/${this.application
|
||||
.providerObj?.pk}"
|
||||
>
|
||||
${this.application.providerObj?.name}
|
||||
(${this.application.providerObj?.verboseName})
|
||||
</a>
|
||||
</div>
|
||||
</dd>
|
||||
</div>`
|
||||
: html``}
|
||||
${(this.application.backchannelProvidersObj || []).length > 0
|
||||
? html`<div class="pf-c-description-list__group">
|
||||
<dt class="pf-c-description-list__term">
|
||||
<span class="pf-c-description-list__text"
|
||||
>${msg("Backchannel Providers")}</span
|
||||
>
|
||||
</dt>
|
||||
<dd class="pf-c-description-list__description">
|
||||
<div class="pf-c-description-list__text">
|
||||
<ul class="pf-c-list">
|
||||
${this.application.backchannelProvidersObj.map(
|
||||
(provider) => {
|
||||
return html`
|
||||
<li>
|
||||
<a
|
||||
href="#/core/providers/${provider.pk}"
|
||||
>
|
||||
${provider.name}
|
||||
(${provider.verboseName})
|
||||
</a>
|
||||
</li>
|
||||
`;
|
||||
},
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
</dd>
|
||||
</div>`
|
||||
: html``}
|
||||
<div class="pf-c-description-list__group">
|
||||
<dt class="pf-c-description-list__term">
|
||||
<span class="pf-c-description-list__text"
|
||||
>${msg("Policy engine mode")}</span
|
||||
>
|
||||
</dt>
|
||||
<dd class="pf-c-description-list__description">
|
||||
<div class="pf-c-description-list__text">
|
||||
${this.application.policyEngineMode?.toUpperCase()}
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="pf-c-description-list__group">
|
||||
<dt class="pf-c-description-list__term">
|
||||
<span class="pf-c-description-list__text"
|
||||
>${msg("Edit")}</span
|
||||
>
|
||||
</dt>
|
||||
<dd class="pf-c-description-list__description">
|
||||
<div class="pf-c-description-list__text">
|
||||
<ak-forms-modal>
|
||||
<span slot="submit"> ${msg("Update")} </span>
|
||||
<span slot="header">
|
||||
${msg("Update Application")}
|
||||
</span>
|
||||
<ak-application-form
|
||||
slot="form"
|
||||
.instancePk=${this.application.slug}
|
||||
>
|
||||
</ak-application-form>
|
||||
<button
|
||||
slot="trigger"
|
||||
class="pf-c-button pf-m-secondary"
|
||||
>
|
||||
${msg("Edit")}
|
||||
</button>
|
||||
</ak-forms-modal>
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="pf-c-description-list__group">
|
||||
<dt class="pf-c-description-list__term">
|
||||
<span class="pf-c-description-list__text"
|
||||
>${msg("Check access")}</span
|
||||
>
|
||||
</dt>
|
||||
<dd class="pf-c-description-list__description">
|
||||
<div class="pf-c-description-list__text">
|
||||
<ak-forms-modal .closeAfterSuccessfulSubmit=${false}>
|
||||
<span slot="submit"> ${msg("Check")} </span>
|
||||
<span slot="header">
|
||||
${msg("Check Application access")}
|
||||
</span>
|
||||
<ak-application-check-access-form
|
||||
slot="form"
|
||||
.application=${this.application}
|
||||
>
|
||||
</ak-application-check-access-form>
|
||||
<button
|
||||
slot="trigger"
|
||||
class="pf-c-button pf-m-secondary"
|
||||
>
|
||||
${msg("Test")}
|
||||
</button>
|
||||
</ak-forms-modal>
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
${this.application.launchUrl
|
||||
? html`<div class="pf-c-description-list__group">
|
||||
<dt class="pf-c-description-list__term">
|
||||
<span class="pf-c-description-list__text"
|
||||
>${msg("Launch")}</span
|
||||
>
|
||||
</dt>
|
||||
<dd class="pf-c-description-list__description">
|
||||
<div class="pf-c-description-list__text">
|
||||
<a
|
||||
target="_blank"
|
||||
href=${this.application.launchUrl}
|
||||
slot="trigger"
|
||||
class="pf-c-button pf-m-secondary"
|
||||
>
|
||||
${msg("Launch")}
|
||||
</a>
|
||||
</div>
|
||||
</dd>
|
||||
</div>`
|
||||
: html``}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="pf-c-card pf-l-grid__item pf-m-12-col pf-m-10-col-on-xl pf-m-10-col-on-2xl"
|
||||
>
|
||||
<div class="pf-c-card__title">
|
||||
${msg("Logins over the last week (per 8 hours)")}
|
||||
</div>
|
||||
<div class="pf-c-card__body">
|
||||
${this.application &&
|
||||
html` <ak-charts-application-authorize
|
||||
applicationSlug=${this.application.slug}
|
||||
>
|
||||
</ak-charts-application-authorize>`}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-c-card pf-l-grid__item pf-m-12-col">
|
||||
<div class="pf-c-card__title">${msg("Changelog")}</div>
|
||||
<div class="pf-c-card__body">
|
||||
<ak-object-changelog
|
||||
targetModelPk=${this.application.pk || ""}
|
||||
targetModelApp="authentik_core"
|
||||
targetModelName="application"
|
||||
>
|
||||
</ak-object-changelog>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
slot="page-policy-bindings"
|
||||
data-tab-title="${msg("Policy / Group / User Bindings")}"
|
||||
class="pf-c-page__main-section pf-m-no-padding-mobile"
|
||||
>
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__title">
|
||||
${msg("These policies control which users can access this application.")}
|
||||
</div>
|
||||
<ak-bound-policies-list .target=${this.application.pk}>
|
||||
</ak-bound-policies-list>
|
||||
</div>
|
||||
</section>
|
||||
<ak-rbac-object-permission-page
|
||||
slot="page-permissions"
|
||||
data-tab-title="${msg("Permissions")}"
|
||||
model=${RbacPermissionsAssignedByUsersListModelEnum.CoreApplication}
|
||||
objectPk=${this.application.pk}
|
||||
></ak-rbac-object-permission-page>
|
||||
</ak-tabs>`;
|
||||
return renderer.render();
|
||||
}
|
||||
}
|
||||
|
214
web/src/admin/applications/ApplicationViewPageRenderers.ts
Normal file
214
web/src/admin/applications/ApplicationViewPageRenderers.ts
Normal file
@ -0,0 +1,214 @@
|
||||
import { PFSize } from "@goauthentik/common/enums.js";
|
||||
import { DescriptionPair, renderDescriptionList } from "@goauthentik/components/DescriptionList.js";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { html, nothing } from "lit";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import type { Application, RbacPermissionsAssignedByUsersListModelEnum } from "@goauthentik/api";
|
||||
|
||||
export class ApplicationViewPageLoadingRenderer {
|
||||
constructor() {}
|
||||
|
||||
render() {
|
||||
return html`<ak-page-header header=${msg("Loading")}
|
||||
><ak-empty-state ?loading="${true}" header=${msg("Loading")}> </ak-empty-state
|
||||
></ak-page-header>`;
|
||||
}
|
||||
}
|
||||
|
||||
export class ApplicationViewPageRenderer {
|
||||
constructor(
|
||||
private app: Application,
|
||||
private noOutpost: boolean,
|
||||
private rbacModel: RbacPermissionsAssignedByUsersListModelEnum,
|
||||
) {}
|
||||
|
||||
missingOutpostMessage() {
|
||||
return this.noOutpost
|
||||
? html`<div slot="header" class="pf-c-banner pf-m-warning">
|
||||
${msg("Warning: Application is not used by any Outpost.")}
|
||||
</div>`
|
||||
: nothing;
|
||||
}
|
||||
|
||||
controlCardContents(app: Application): DescriptionPair[] {
|
||||
// prettier-ignore
|
||||
const rows: (DescriptionPair | null)[] = [
|
||||
app.providerObj
|
||||
? [
|
||||
msg("Provider"),
|
||||
html`
|
||||
<a href="#/core/providers/${app.providerObj?.pk}">
|
||||
${app.providerObj?.name} (${app.providerObj?.verboseName})
|
||||
</a>
|
||||
`,
|
||||
]
|
||||
: null,
|
||||
|
||||
(app.backchannelProvidersObj || []).length > 0
|
||||
? [
|
||||
msg("Backchannel Providers"),
|
||||
html`
|
||||
<ul class="pf-c-list">
|
||||
${app.backchannelProvidersObj.map((provider) => {
|
||||
return html`
|
||||
<li>
|
||||
<a href="#/core/providers/${provider.pk}">
|
||||
${provider.name} (${provider.verboseName})
|
||||
</a>
|
||||
</li>
|
||||
`;
|
||||
})}
|
||||
</ul>
|
||||
`,
|
||||
]
|
||||
: null,
|
||||
|
||||
[
|
||||
msg("Policy engine mode"),
|
||||
app.policyEngineMode?.toUpperCase()
|
||||
],
|
||||
|
||||
[
|
||||
msg("Edit"),
|
||||
html`
|
||||
<ak-forms-modal>
|
||||
<span slot="submit"> ${msg("Update")} </span>
|
||||
<span slot="header"> ${msg("Update Application")} </span>
|
||||
<ak-application-form slot="form" .instancePk=${app.slug}>
|
||||
</ak-application-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${msg("Edit")}
|
||||
</button>
|
||||
</ak-forms-modal>
|
||||
`,
|
||||
],
|
||||
|
||||
[
|
||||
msg("Check access"),
|
||||
html`
|
||||
<ak-forms-modal .closeAfterSuccessfulSubmit=${false}>
|
||||
<span slot="submit"> ${msg("Check")} </span>
|
||||
<span slot="header"> ${msg("Check Application access")} </span>
|
||||
<ak-application-check-access-form slot="form" .application=${app}>
|
||||
</ak-application-check-access-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${msg("Test")}
|
||||
</button>
|
||||
</ak-forms-modal>
|
||||
`,
|
||||
],
|
||||
|
||||
app.launchUrl
|
||||
? [
|
||||
msg("Launch"),
|
||||
html`
|
||||
<a
|
||||
target="_blank"
|
||||
href=${app.launchUrl}
|
||||
slot="trigger"
|
||||
class="pf-c-button pf-m-secondary"
|
||||
>
|
||||
${msg("Launch")}
|
||||
</a>
|
||||
`,
|
||||
]
|
||||
: null,
|
||||
];
|
||||
|
||||
return rows.filter((row) => row !== null) as DescriptionPair[];
|
||||
}
|
||||
|
||||
controlCard(app: Application) {
|
||||
return html`
|
||||
<div class="pf-c-card pf-l-grid__item pf-m-12-col pf-m-2-col-on-xl pf-m-2-col-on-2xl">
|
||||
<div class="pf-c-card__title">${msg("Related")}</div>
|
||||
<div class="pf-c-card__body">
|
||||
${renderDescriptionList(this.controlCardContents(app))}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
loginsChart(app: Application) {
|
||||
return html`<div
|
||||
class="pf-c-card pf-l-grid__item pf-m-12-col pf-m-10-col-on-xl pf-m-10-col-on-2xl"
|
||||
>
|
||||
<div class="pf-c-card__title">${msg("Logins over the last week (per 8 hours)")}</div>
|
||||
<div class="pf-c-card__body">
|
||||
${app &&
|
||||
html` <ak-charts-application-authorize applicationSlug=${app.slug}>
|
||||
</ak-charts-application-authorize>`}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
changelog(app: Application) {
|
||||
return html`
|
||||
<div class="pf-c-card pf-l-grid__item pf-m-12-col">
|
||||
<div class="pf-c-card__title">${msg("Changelog")}</div>
|
||||
<div class="pf-c-card__body">
|
||||
<ak-object-changelog
|
||||
targetModelPk=${app.pk || ""}
|
||||
targetModelApp="authentik_core"
|
||||
targetModelName="application"
|
||||
>
|
||||
</ak-object-changelog>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
overview(app: Application) {
|
||||
return html`
|
||||
<div class="pf-l-grid pf-m-gutter">
|
||||
${this.controlCard(app)} ${this.loginsChart(app)} ${this.changelog(app)}
|
||||
</div>
|
||||
</section>`;
|
||||
}
|
||||
|
||||
policiesList(app: Application) {
|
||||
return html`
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__title">
|
||||
${msg("These policies control which users can access this application.")}
|
||||
</div>
|
||||
<ak-bound-policies-list .target=${app.pk}> </ak-bound-policies-list>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html` <ak-page-header
|
||||
header=${this.app.name}
|
||||
description=${ifDefined(this.app.metaPublisher)}
|
||||
.iconImage=${true}
|
||||
>
|
||||
<ak-app-icon size=${PFSize.Medium} slot="icon" .app=${this.app}></ak-app-icon>
|
||||
</ak-page-header>
|
||||
<ak-tabs>
|
||||
${this.missingOutpostMessage()}
|
||||
<section
|
||||
slot="page-overview"
|
||||
data-tab-title="${msg("Overview")}"
|
||||
class="pf-c-page__main-section pf-m-no-padding-mobile"
|
||||
>
|
||||
${this.overview(this.app)}
|
||||
</section>
|
||||
<section
|
||||
slot="page-policy-bindings"
|
||||
data-tab-title="${msg("Policy / Group / User Bindings")}"
|
||||
class="pf-c-page__main-section pf-m-no-padding-mobile"
|
||||
>
|
||||
${this.policiesList(this.app)}
|
||||
</section>
|
||||
<ak-rbac-object-permission-page
|
||||
slot="page-permissions"
|
||||
data-tab-title="${msg("Permissions")}"
|
||||
model=${this.rbacModel}
|
||||
objectPk=${this.app.pk}
|
||||
></ak-rbac-object-permission-page>
|
||||
</ak-tabs>`;
|
||||
}
|
||||
}
|
@ -2,8 +2,9 @@ import { AKElement } from "@goauthentik/elements/Base";
|
||||
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { PropertyValues } from "@lit/reactive-element/reactive-element";
|
||||
import { TemplateResult, css, html } from "lit";
|
||||
import { customElement, property, queryAll } from "lit/decorators.js";
|
||||
import { customElement, property, queryAll, state } from "lit/decorators.js";
|
||||
import { map } from "lit/directives/map.js";
|
||||
|
||||
import PFCheck from "@patternfly/patternfly/components/Check/check.css";
|
||||
@ -112,10 +113,14 @@ export class CheckboxGroup extends AkElementWithCustomEvents {
|
||||
@queryAll('input[type="checkbox"]')
|
||||
checkboxes!: NodeListOf<HTMLInputElement>;
|
||||
|
||||
internals?: ElementInternals;
|
||||
@state()
|
||||
values: string[] = [];
|
||||
|
||||
get json() {
|
||||
return this.value;
|
||||
internals?: ElementInternals;
|
||||
doneFirstUpdate = false;
|
||||
|
||||
json() {
|
||||
return this.values;
|
||||
}
|
||||
|
||||
private get formValue() {
|
||||
@ -124,7 +129,7 @@ export class CheckboxGroup extends AkElementWithCustomEvents {
|
||||
}
|
||||
const name = this.name;
|
||||
const entries = new FormData();
|
||||
this.value.forEach((v) => entries.append(name, v));
|
||||
this.values.forEach((v) => entries.append(name, v));
|
||||
return entries;
|
||||
}
|
||||
|
||||
@ -136,14 +141,14 @@ export class CheckboxGroup extends AkElementWithCustomEvents {
|
||||
|
||||
onClick(ev: Event) {
|
||||
ev.stopPropagation();
|
||||
this.value = Array.from(this.checkboxes)
|
||||
this.values = Array.from(this.checkboxes)
|
||||
.filter((checkbox) => checkbox.checked)
|
||||
.map((checkbox) => checkbox.name);
|
||||
this.dispatchCustomEvent("change", this.value);
|
||||
this.dispatchCustomEvent("input", this.value);
|
||||
this.dispatchCustomEvent("change", this.values);
|
||||
this.dispatchCustomEvent("input", this.values);
|
||||
if (this.internals) {
|
||||
this.internals.setValidity({});
|
||||
if (this.required && this.value.length === 0) {
|
||||
if (this.required && this.values.length === 0) {
|
||||
this.internals.setValidity(
|
||||
{
|
||||
valueMissing: true,
|
||||
@ -154,6 +159,16 @@ export class CheckboxGroup extends AkElementWithCustomEvents {
|
||||
}
|
||||
this.internals.setFormValue(this.formValue);
|
||||
}
|
||||
// Doing a write-back so anyone examining the checkbox.value field will get something
|
||||
// meaningful. Doesn't do anything for anyone, usually, but it's nice to have.
|
||||
this.value = this.values;
|
||||
}
|
||||
|
||||
willUpdate(changed: PropertyValues<this>) {
|
||||
if (changed.has("value") && !this.doneFirstUpdate) {
|
||||
this.doneFirstUpdate = true;
|
||||
this.values = this.value;
|
||||
}
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
@ -183,7 +198,7 @@ export class CheckboxGroup extends AkElementWithCustomEvents {
|
||||
|
||||
render() {
|
||||
const renderOne = ([name, label]: CheckboxPr) => {
|
||||
const selected = this.value.includes(name);
|
||||
const selected = this.values.includes(name);
|
||||
const blockFwd = (e: Event) => {
|
||||
e.stopImmediatePropagation();
|
||||
};
|
||||
|
@ -53,6 +53,9 @@ export class AkDualSelectProvider extends CustomListenerElement(AKElement) {
|
||||
|
||||
private isLoading = false;
|
||||
|
||||
private doneFirstUpdate = false;
|
||||
private internalSelected: DualSelectPair[] = [];
|
||||
|
||||
private pagination?: Pagination;
|
||||
|
||||
constructor() {
|
||||
@ -69,6 +72,11 @@ export class AkDualSelectProvider extends CustomListenerElement(AKElement) {
|
||||
}
|
||||
|
||||
willUpdate(changedProperties: PropertyValues<this>) {
|
||||
if (changedProperties.has("selected") && !this.doneFirstUpdate) {
|
||||
this.doneFirstUpdate = true;
|
||||
this.internalSelected = this.selected;
|
||||
}
|
||||
|
||||
if (changedProperties.has("searchDelay")) {
|
||||
this.doSearch = debounce(
|
||||
AkDualSelectProvider.prototype.doSearch.bind(this),
|
||||
@ -105,7 +113,8 @@ export class AkDualSelectProvider extends CustomListenerElement(AKElement) {
|
||||
if (!(event instanceof CustomEvent)) {
|
||||
throw new Error(`Expecting a CustomEvent for change, received ${event} instead`);
|
||||
}
|
||||
this.selected = event.detail.value;
|
||||
this.internalSelected = event.detail.value;
|
||||
this.selected = this.internalSelected;
|
||||
}
|
||||
|
||||
onSearch(event: Event) {
|
||||
@ -124,12 +133,16 @@ export class AkDualSelectProvider extends CustomListenerElement(AKElement) {
|
||||
return this.dualSelector.value!.selected.map(([k, _]) => k);
|
||||
}
|
||||
|
||||
json() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`<ak-dual-select
|
||||
${ref(this.dualSelector)}
|
||||
.options=${this.options}
|
||||
.pages=${this.pagination}
|
||||
.selected=${this.selected}
|
||||
.selected=${this.internalSelected}
|
||||
available-label=${this.availableLabel}
|
||||
selected-label=${this.selectedLabel}
|
||||
></ak-dual-select>`;
|
||||
|
@ -80,7 +80,7 @@ export function serializeForm<T extends KeyUnknown>(
|
||||
}
|
||||
|
||||
if ("akControl" in inputElement.dataset) {
|
||||
assignValue(element, inputElement.value, json);
|
||||
assignValue(element, (inputElement as unknown as AkControlElement).json(), json);
|
||||
return;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user