diff --git a/web/src/admin/applications/ApplicationForm.ts b/web/src/admin/applications/ApplicationForm.ts index a142c77491..a90d82209e 100644 --- a/web/src/admin/applications/ApplicationForm.ts +++ b/web/src/admin/applications/ApplicationForm.ts @@ -99,6 +99,9 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm${alertMsg}`} @@ -134,9 +137,10 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm item.name; const renderValue = (item: Provider | undefined) => item?.pk; @@ -53,6 +54,9 @@ export class AkProviderInput extends AKElement { @property({ type: Number }) value?: number; + @property({ type: Boolean, attribute: "readonly" }) + readOnly = false; + @property({ type: Boolean }) required = false; @@ -76,6 +80,8 @@ export class AkProviderInput extends AKElement { }; render() { + const readOnlyValue = this.readOnly && typeof this.value === "number"; + return html` ${AKLabel( { @@ -86,7 +92,9 @@ export class AkProviderInput extends AKElement { }, this.label, )} - + ${readOnlyValue + ? html`` + : nothing} ${this.help ? html`

${this.help}

` : nothing} diff --git a/web/src/elements/forms/SearchSelect/SearchSelect.ts b/web/src/elements/forms/SearchSelect/SearchSelect.ts index 92410b25ec..6554870cbd 100644 --- a/web/src/elements/forms/SearchSelect/SearchSelect.ts +++ b/web/src/elements/forms/SearchSelect/SearchSelect.ts @@ -23,6 +23,7 @@ type Group = [string, T[]]; export interface ISearchSelectBase { blankable?: boolean; + readOnly?: boolean; query?: string; objects?: T[]; selectedObject: T | null; @@ -93,6 +94,14 @@ export abstract class SearchSelectBase @property({ type: Boolean }) public creatable?: boolean; + /** + * Prevent user interaction while still rendering the current value. + * @property + * @attr + */ + @property({ type: Boolean, attribute: "readonly" }) + public readOnly = false; + /** * An initial string to filter the search contents, * and the value of the input which further serves to restrict the search. @@ -254,6 +263,8 @@ export abstract class SearchSelectBase } #searchListener = (event: InputEvent) => { + if (this.readOnly) return; + const value = (event.target as SearchSelectView).rawValue; if (!value) { @@ -277,6 +288,8 @@ export abstract class SearchSelectBase }; private onSelect(event: InputEvent) { + if (this.readOnly) return; + const value = (event.target as SearchSelectView).value; if (!value) { @@ -381,6 +394,7 @@ export abstract class SearchSelectBase .options=${options} value=${ifPresent(value)} ?blankable=${this.blankable} + ?readonly=${this.readOnly} label=${ifPresent(this.label)} name=${ifPresent(this.name)} placeholder=${ifPresent(this.placeholder)} diff --git a/web/src/elements/forms/SearchSelect/ak-search-select-view.ts b/web/src/elements/forms/SearchSelect/ak-search-select-view.ts index 25157bbb42..a4832185a7 100644 --- a/web/src/elements/forms/SearchSelect/ak-search-select-view.ts +++ b/web/src/elements/forms/SearchSelect/ak-search-select-view.ts @@ -24,6 +24,7 @@ export interface ISearchSelectView { value?: string; open: boolean; blankable: boolean; + readOnly: boolean; caseSensitive: boolean; name?: string; placeholder: string; @@ -126,6 +127,14 @@ export class SearchSelectView extends AKElement implements ISearchSelectView { @property({ type: Boolean }) public blankable = false; + /** + * Prevents user interaction while showing the current value. + * + * @attr + */ + @property({ type: Boolean, attribute: "readonly" }) + public readOnly = false; + /** * If not managed, make the matcher case-sensitive during interaction. If managed, * the manager must handle this. @@ -248,6 +257,8 @@ export class SearchSelectView extends AKElement implements ISearchSelectView { //#region Event Listeners #clickListener = (_ev: Event) => { + if (this.readOnly) return; + this.open = !this.open; this.#inputRef.value?.focus(); }; @@ -263,6 +274,8 @@ export class SearchSelectView extends AKElement implements ISearchSelectView { } #searchKeyupListener = (event: KeyboardEvent) => { + if (this.readOnly) return; + if (event.key === "Escape") { event.stopPropagation(); event.preventDefault(); @@ -277,6 +290,8 @@ export class SearchSelectView extends AKElement implements ISearchSelectView { }; #searchKeydownListener = (event: KeyboardEvent) => { + if (this.readOnly) return; + if (!this.open) return; switch (event.key) { @@ -339,6 +354,8 @@ export class SearchSelectView extends AKElement implements ISearchSelectView { } #inputListener = (_ev: InputEvent) => { + if (this.readOnly) return; + if (!this.managed) { this.findValueForInput(); this.requestUpdate(); @@ -356,6 +373,8 @@ export class SearchSelectView extends AKElement implements ISearchSelectView { }; #listKeydownListener = (event: KeyboardEvent) => { + if (this.readOnly) return; + if (event.key === "Tab" && event.shiftKey) { event.preventDefault(); @@ -364,6 +383,8 @@ export class SearchSelectView extends AKElement implements ISearchSelectView { }; #changeListener = (event: InputEvent) => { + if (this.readOnly) return; + if (!event.target) { return; } @@ -441,6 +462,7 @@ export class SearchSelectView extends AKElement implements ISearchSelectView { @keyup=${this.#searchKeyupListener} @keydown=${this.#searchKeydownListener} value=${this.displayValue} + ?readonly=${this.readOnly} />