mirror of
https://github.com/goauthentik/authentik.git
synced 2026-06-17 19:09:11 +03:00
web/admin: fix read-only provider selection for application form (cherry-pick #18768 to version-2025.12) (#18803)
Co-authored-by: Dominic R <dominic@sdko.org> fix read-only provider selection for application form (#18768)
This commit is contained in:
committed by
GitHub
parent
409652e874
commit
e73edc2fce
@@ -99,6 +99,9 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm<Applicatio
|
||||
const alertMsg = msg(
|
||||
"Using this form will only create an Application. In order to authenticate with the application, you will have to manually pair it with a Provider.",
|
||||
);
|
||||
const providerFromInstance = this.instance?.provider;
|
||||
const providerValue = providerFromInstance ?? this.provider;
|
||||
const providerPrefilled = !this.instance && this.provider !== undefined;
|
||||
|
||||
return html`
|
||||
${this.instance ? nothing : html`<ak-alert level="pf-m-info">${alertMsg}</ak-alert>`}
|
||||
@@ -134,9 +137,10 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm<Applicatio
|
||||
<ak-provider-search-input
|
||||
name="provider"
|
||||
label=${msg("Provider")}
|
||||
value=${ifPresent(this.instance?.provider)}
|
||||
.value=${providerValue}
|
||||
.readOnly=${providerPrefilled}
|
||||
?blankable=${!providerPrefilled}
|
||||
help=${msg("Select a provider that this application should use.")}
|
||||
blankable
|
||||
></ak-provider-search-input>
|
||||
<ak-backchannel-providers-input
|
||||
name="backchannelProviders"
|
||||
|
||||
@@ -13,6 +13,7 @@ import { Provider, ProvidersAllListRequest, ProvidersApi } from "@goauthentik/ap
|
||||
|
||||
import { html, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
const renderElement = (item: Provider) => 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` <ak-form-element-horizontal name=${this.name}>
|
||||
${AKLabel(
|
||||
{
|
||||
@@ -86,7 +92,9 @@ export class AkProviderInput extends AKElement {
|
||||
},
|
||||
this.label,
|
||||
)}
|
||||
|
||||
${readOnlyValue
|
||||
? html`<input type="hidden" name=${this.name} value=${this.value ?? ""} />`
|
||||
: nothing}
|
||||
<ak-search-select
|
||||
.fieldID=${this.fieldID}
|
||||
.selected=${this.#selected}
|
||||
@@ -94,7 +102,9 @@ export class AkProviderInput extends AKElement {
|
||||
.renderElement=${renderElement}
|
||||
.value=${renderValue}
|
||||
.groupBy=${doGroupBy}
|
||||
?blankable=${!!this.blankable}
|
||||
?blankable=${readOnlyValue ? false : !!this.blankable}
|
||||
?readonly=${this.readOnly}
|
||||
name=${ifDefined(readOnlyValue ? undefined : this.name)}
|
||||
>
|
||||
</ak-search-select>
|
||||
${this.help ? html`<p class="pf-c-form__helper-text">${this.help}</p>` : nothing}
|
||||
|
||||
@@ -23,6 +23,7 @@ type Group<T> = [string, T[]];
|
||||
|
||||
export interface ISearchSelectBase<T> {
|
||||
blankable?: boolean;
|
||||
readOnly?: boolean;
|
||||
query?: string;
|
||||
objects?: T[];
|
||||
selectedObject: T | null;
|
||||
@@ -93,6 +94,14 @@ export abstract class SearchSelectBase<T>
|
||||
@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<T>
|
||||
}
|
||||
|
||||
#searchListener = (event: InputEvent) => {
|
||||
if (this.readOnly) return;
|
||||
|
||||
const value = (event.target as SearchSelectView).rawValue;
|
||||
|
||||
if (!value) {
|
||||
@@ -277,6 +288,8 @@ export abstract class SearchSelectBase<T>
|
||||
};
|
||||
|
||||
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<T>
|
||||
.options=${options}
|
||||
value=${ifPresent(value)}
|
||||
?blankable=${this.blankable}
|
||||
?readonly=${this.readOnly}
|
||||
label=${ifPresent(this.label)}
|
||||
name=${ifPresent(this.name)}
|
||||
placeholder=${ifPresent(this.placeholder)}
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user