This repository has been archived on 2024-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
authentik/web/src/elements/forms/ModelForm.ts
Jens L 14f0034a0a
web/elements: only render form once instance is loaded (#5049)
* web/elements: only render form once instance is loaded

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* use radio for transport

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* only wait for instance to be loaded if set

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add hook to load additional data in form

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* make send an abstract function instead of attribute

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* ensure form is updated after data is loaded

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* remove until for select and multi-selects in forms

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* don't use until for file uploads

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* remove last until from form

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* remove deprecated import

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* prevent form double load, add error handling for PreventFormSubmit

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix double creation of inner element in proxy form

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* make PreventFormSubmit work correctly

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-23 14:05:14 +01:00

92 lines
2.9 KiB
TypeScript

import { EVENT_REFRESH } from "@goauthentik/common/constants";
import "@goauthentik/elements/EmptyState";
import { Form } from "@goauthentik/elements/forms/Form";
import { TemplateResult, html } from "lit";
import { property } from "lit/decorators.js";
export abstract class ModelForm<T, PKT extends string | number> extends Form<T> {
abstract loadInstance(pk: PKT): Promise<T>;
async load(): Promise<void> {
return Promise.resolve();
}
@property({ attribute: false })
set instancePk(value: PKT) {
this._instancePk = value;
if (this.viewportCheck && !this.isInViewport) {
return;
}
if (this._isLoading) {
return;
}
this._isLoading = true;
this.load().then(() => {
this.loadInstance(value).then((instance) => {
this.instance = instance;
this._isLoading = false;
this.requestUpdate();
});
});
}
private _instancePk?: PKT;
// Keep track if we've loaded the model instance
private _initialLoad = false;
// Keep track if we've done the general data loading of load()
private _initialDataLoad = false;
private _isLoading = false;
@property({ attribute: false })
instance?: T = this.defaultInstance;
get defaultInstance(): T | undefined {
return undefined;
}
constructor() {
super();
this.addEventListener(EVENT_REFRESH, () => {
if (!this._instancePk) return;
this.loadInstance(this._instancePk).then((instance) => {
this.instance = instance;
});
});
}
resetForm(): void {
this.instance = undefined;
this._initialLoad = false;
}
renderVisible(): TemplateResult {
if ((this._instancePk && !this.instance) || !this._initialDataLoad) {
return html`<ak-empty-state ?loading=${true}></ak-empty-state>`;
}
return super.renderVisible();
}
render(): TemplateResult {
// if we're in viewport now and haven't loaded AND have a PK set, load now
// Or if we don't check for viewport in some cases
const viewportVisible = this.isInViewport || !this.viewportCheck;
if (this._instancePk && !this._initialLoad && viewportVisible) {
this.instancePk = this._instancePk;
this._initialLoad = true;
} else if (!this._initialDataLoad && viewportVisible) {
// else if since if the above case triggered that will also call this.load(), so
// ensure we don't load again
this.load().then(() => {
this._initialDataLoad = true;
// Class attributes changed in this.load() might not be @property()
// or @state() so let's trigger a re-render to be sure we get updated
this.requestUpdate();
});
}
return super.render();
}
}