diff --git a/web/src/elements/ak-checkbox-group/ak-checkbox-group.ts b/web/src/elements/ak-checkbox-group/ak-checkbox-group.ts index 60fe49b224..addb13395a 100644 --- a/web/src/elements/ak-checkbox-group/ak-checkbox-group.ts +++ b/web/src/elements/ak-checkbox-group/ak-checkbox-group.ts @@ -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; - 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) { + 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(); }; diff --git a/web/src/elements/ak-dual-select/ak-dual-select-provider.ts b/web/src/elements/ak-dual-select/ak-dual-select-provider.ts index 147e2f01a9..15f274460a 100644 --- a/web/src/elements/ak-dual-select/ak-dual-select-provider.ts +++ b/web/src/elements/ak-dual-select/ak-dual-select-provider.ts @@ -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) { + 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``; diff --git a/web/src/elements/forms/Form.ts b/web/src/elements/forms/Form.ts index 0530f499bb..7f08433ea9 100644 --- a/web/src/elements/forms/Form.ts +++ b/web/src/elements/forms/Form.ts @@ -80,7 +80,7 @@ export function serializeForm( } if ("akControl" in inputElement.dataset) { - assignValue(element, inputElement.value, json); + assignValue(element, (inputElement as unknown as AkControlElement).json(), json); return; }