/
dimamir
/
authentik
Обзор
Документация
Войти
/
dimamir
/
authentik
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
web/src/elements/buttons/SpinnerButton/BaseTaskButton.ts
142 строки
4 KB
Ken Sternberg
web: fix needed because recent upgrade to task breaks spinner button (#10142)
18 июн 2024, 11:09
Не верифицирован
18 июн 2024, 11:09
7c3eb96
Код
Авторство
О чём код?
import { ERROR_CLASS, PROGRESS_CLASS, SUCCESS_CLASS } from "@goauthentik/common/constants"; import { PFSize } from "@goauthentik/common/enums.js"; import { AKElement } from "@goauthentik/elements/Base"; import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter"; import { Task, TaskStatus } from "@lit/task"; import { css, html } from "lit"; import { property } from "lit/decorators.js"; import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFSpinner from "@patternfly/patternfly/components/Spinner/spinner.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css"; // `pointer-events: none` makes the button inaccessible during the processing phase. const buttonStyles = [ PFBase, PFButton, PFSpinner, css` #spinner-button { transition: all var(--pf-c-button--m-progress--TransitionDuration) ease 0s; } #spinner-button.working { pointer-events: none; } `, ]; const StatusMap = new Map<TaskStatus, string>([ [TaskStatus.INITIAL, ""], [TaskStatus.PENDING, PROGRESS_CLASS], [TaskStatus.COMPLETE, SUCCESS_CLASS], [TaskStatus.ERROR, ERROR_CLASS], ]); const SPINNER_TIMEOUT = 1000 * 1.5; // milliseconds /** * BaseTaskButton * * This is an abstract base class for our four-state buttons. It provides the four basic events of * this class: click, success, failure, reset. Subclasses can override any of these event handlers, * but overriding onSuccess() or onFailure() means that you must either call `onComplete` if you * want to preserve the TaskButton's "reset after completion" semantics, or inside `onSuccess` and * `onFailure` call their `super.` equivalents. * */ export abstract class BaseTaskButton extends CustomEmitterElement(AKElement) { eventPrefix = "ak-button"; static get styles() { return buttonStyles; } callAction!: () => Promise<unknown>; actionTask: Task; @property({ type: Boolean }) disabled = false; constructor() { super(); this.onSuccess = this.onSuccess.bind(this); this.onError = this.onError.bind(this); this.onClick = this.onClick.bind(this); this.actionTask = this.buildTask(); } buildTask() { return new Task(this, { task: () => this.callAction(), args: () => [], autoRun: false, onComplete: (r: unknown) => this.onSuccess(r), onError: (r: unknown) => this.onError(r), }); } onComplete() { setTimeout(() => { this.dispatchCustomEvent(`${this.eventPrefix}-reset`); // set-up for the next task... this.actionTask = this.buildTask(); this.requestUpdate(); }, SPINNER_TIMEOUT); } onSuccess(r: unknown) { this.dispatchCustomEvent(`${this.eventPrefix}-success`, { result: r, }); this.onComplete(); } onError(error: unknown) { this.dispatchCustomEvent(`${this.eventPrefix}-failure`, { error, }); this.onComplete(); } onClick() { // Don't accept clicks when a task is in progress.. if (this.actionTask.status === TaskStatus.PENDING) { return; } this.dispatchCustomEvent(`${this.eventPrefix}-click`); this.actionTask.run(); } private spinner = html`<span class="pf-c-button__progress"> <ak-spinner size=${PFSize.Medium}></ak-spinner> </span>`; get buttonClasses() { return [ ...this.classList, StatusMap.get(this.actionTask.status), this.actionTask.status === TaskStatus.INITIAL ? "" : "working", ] .join(" ") .trim(); } render() { return html`<button id="spinner-button" part="spinner-button" class="pf-c-button pf-m-progress ${this.buttonClasses}" @click=${this.onClick} ?disabled=${this.disabled} > ${this.actionTask.render({ pending: () => this.spinner })} <slot></slot> </button>`; } } export default BaseTaskButton;