Compare commits
	
		
			29 Commits
		
	
	
		
			celery-2-d
			...
			web/legibi
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1bc8fa0a9d | |||
| 3ec0d30965 | |||
| 50d2f69332 | |||
| 7d972ec711 | |||
| 854427e463 | |||
| be349e2e14 | |||
| bd0e81b8ad | |||
| f6afb59515 | |||
| dddde09be5 | |||
| 6d7fc94698 | |||
| 1dcf9108ad | |||
| 7bb6a3dfe6 | |||
| 9cc440eee1 | |||
| fe9e4526ac | |||
| 20b66f850c | |||
| 67b327414b | |||
| 5b8d86b5a9 | |||
| 67aed3e318 | |||
| 9809b94030 | |||
| e7527c551b | |||
| 36b10b434a | |||
| 831797b871 | |||
| 5cc2c0f45f | |||
| 32442766f4 | |||
| 75790909a8 | |||
| e0d5df89ca | |||
| f25a9c624e | |||
| 914993a788 | |||
| 89dad07a66 | 
@ -1,6 +1,5 @@
 | 
				
			|||||||
import { AkControlElement } from "@goauthentik/elements/AkControlElement.js";
 | 
					import { AkControlElement } from "@goauthentik/elements/AkControlElement.js";
 | 
				
			||||||
import { debounce } from "@goauthentik/elements/utils/debounce";
 | 
					import { debounce } from "@goauthentik/elements/utils/debounce";
 | 
				
			||||||
import { CustomListenerElement } from "@goauthentik/elements/utils/eventEmitter";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { msg } from "@lit/localize";
 | 
					import { msg } from "@lit/localize";
 | 
				
			||||||
import { PropertyValues, html } from "lit";
 | 
					import { PropertyValues, html } from "lit";
 | 
				
			||||||
@ -12,6 +11,11 @@ import type { Pagination } from "@goauthentik/api";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import "./ak-dual-select";
 | 
					import "./ak-dual-select";
 | 
				
			||||||
import { AkDualSelect } from "./ak-dual-select";
 | 
					import { AkDualSelect } from "./ak-dual-select";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					    DualSelectChangeEvent,
 | 
				
			||||||
 | 
					    DualSelectPaginatorNavEvent,
 | 
				
			||||||
 | 
					    DualSelectSearchEvent,
 | 
				
			||||||
 | 
					} from "./events";
 | 
				
			||||||
import type { DataProvider, DualSelectPair } from "./types";
 | 
					import type { DataProvider, DualSelectPair } from "./types";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -26,7 +30,7 @@ import type { DataProvider, DualSelectPair } from "./types";
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@customElement("ak-dual-select-provider")
 | 
					@customElement("ak-dual-select-provider")
 | 
				
			||||||
export class AkDualSelectProvider extends CustomListenerElement(AkControlElement) {
 | 
					export class AkDualSelectProvider extends AkControlElement {
 | 
				
			||||||
    /** A function that takes a page and returns the DualSelectPair[] collection with which to update
 | 
					    /** A function that takes a page and returns the DualSelectPair[] collection with which to update
 | 
				
			||||||
     * the "Available" pane.
 | 
					     * the "Available" pane.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
@ -86,9 +90,9 @@ export class AkDualSelectProvider extends CustomListenerElement(AkControlElement
 | 
				
			|||||||
        this.onNav = this.onNav.bind(this);
 | 
					        this.onNav = this.onNav.bind(this);
 | 
				
			||||||
        this.onChange = this.onChange.bind(this);
 | 
					        this.onChange = this.onChange.bind(this);
 | 
				
			||||||
        this.onSearch = this.onSearch.bind(this);
 | 
					        this.onSearch = this.onSearch.bind(this);
 | 
				
			||||||
        this.addCustomListener("ak-pagination-nav-to", this.onNav);
 | 
					        this.addEventListener(DualSelectPaginatorNavEvent.eventName, this.onNav);
 | 
				
			||||||
        this.addCustomListener("ak-dual-select-change", this.onChange);
 | 
					        this.addEventListener(DualSelectSearchEvent.eventName, this.onSearch);
 | 
				
			||||||
        this.addCustomListener("ak-dual-select-search", this.onSearch);
 | 
					        this.addEventListener(DualSelectChangeEvent.eventName, this.onChange);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    willUpdate(changedProperties: PropertyValues<this>) {
 | 
					    willUpdate(changedProperties: PropertyValues<this>) {
 | 
				
			||||||
@ -122,26 +126,16 @@ export class AkDualSelectProvider extends CustomListenerElement(AkControlElement
 | 
				
			|||||||
        this.isLoading = false;
 | 
					        this.isLoading = false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    onNav(event: Event) {
 | 
					    onNav(event: DualSelectPaginatorNavEvent) {
 | 
				
			||||||
        if (!(event instanceof CustomEvent)) {
 | 
					        this.fetch(event.page);
 | 
				
			||||||
            throw new Error(`Expecting a CustomEvent for navigation, received ${event} instead`);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.fetch(event.detail);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    onChange(event: Event) {
 | 
					    onChange(event: DualSelectChangeEvent) {
 | 
				
			||||||
        if (!(event instanceof CustomEvent)) {
 | 
					        this.selected = this.internalSelected = event.selected;
 | 
				
			||||||
            throw new Error(`Expecting a CustomEvent for change, received ${event} instead`);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.internalSelected = event.detail.value;
 | 
					 | 
				
			||||||
        this.selected = this.internalSelected;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    onSearch(event: Event) {
 | 
					    onSearch(event: DualSelectSearchEvent) {
 | 
				
			||||||
        if (!(event instanceof CustomEvent)) {
 | 
					        this.doSearch(event.search);
 | 
				
			||||||
            throw new Error(`Expecting a CustomEvent for change, received ${event} instead`);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.doSearch(event.detail);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    doSearch(search: string) {
 | 
					    doSearch(search: string) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,5 @@
 | 
				
			|||||||
import { AKElement } from "@goauthentik/elements/Base";
 | 
					import { AKElement } from "@goauthentik/elements/Base";
 | 
				
			||||||
import {
 | 
					import { match } from "ts-pattern";
 | 
				
			||||||
    CustomEmitterElement,
 | 
					 | 
				
			||||||
    CustomListenerElement,
 | 
					 | 
				
			||||||
} from "@goauthentik/elements/utils/eventEmitter";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { msg, str } from "@lit/localize";
 | 
					import { msg, str } from "@lit/localize";
 | 
				
			||||||
import { PropertyValues, html, nothing } from "lit";
 | 
					import { PropertyValues, html, nothing } from "lit";
 | 
				
			||||||
@ -23,15 +20,13 @@ import { AkDualSelectSelectedPane } from "./components/ak-dual-select-selected-p
 | 
				
			|||||||
import "./components/ak-pagination";
 | 
					import "./components/ak-pagination";
 | 
				
			||||||
import "./components/ak-search-bar";
 | 
					import "./components/ak-search-bar";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    EVENT_ADD_ALL,
 | 
					    DualSelectChangeEvent,
 | 
				
			||||||
    EVENT_ADD_ONE,
 | 
					    DualSelectMoveRequestEvent,
 | 
				
			||||||
    EVENT_ADD_SELECTED,
 | 
					    DualSelectPanelSearchEvent,
 | 
				
			||||||
    EVENT_DELETE_ALL,
 | 
					    DualSelectSearchEvent,
 | 
				
			||||||
    EVENT_REMOVE_ALL,
 | 
					    DualSelectUpdateEvent,
 | 
				
			||||||
    EVENT_REMOVE_ONE,
 | 
					} from "./events";
 | 
				
			||||||
    EVENT_REMOVE_SELECTED,
 | 
					import type { BasePagination, DualSelectPair } from "./types";
 | 
				
			||||||
} from "./constants";
 | 
					 | 
				
			||||||
import type { BasePagination, DualSelectPair, SearchbarEvent } from "./types";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
function alphaSort([_k1, v1, s1]: DualSelectPair, [_k2, v2, s2]: DualSelectPair) {
 | 
					function alphaSort([_k1, v1, s1]: DualSelectPair, [_k2, v2, s2]: DualSelectPair) {
 | 
				
			||||||
    const [l, r] = [s1 !== undefined ? s1 : v1, s2 !== undefined ? s2 : v2];
 | 
					    const [l, r] = [s1 !== undefined ? s1 : v1, s2 !== undefined ? s2 : v2];
 | 
				
			||||||
@ -60,7 +55,7 @@ const keyfinder =
 | 
				
			|||||||
        k === key;
 | 
					        k === key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@customElement("ak-dual-select")
 | 
					@customElement("ak-dual-select")
 | 
				
			||||||
export class AkDualSelect extends CustomEmitterElement(CustomListenerElement(AKElement)) {
 | 
					export class AkDualSelect extends AKElement {
 | 
				
			||||||
    static get styles() {
 | 
					    static get styles() {
 | 
				
			||||||
        return styles;
 | 
					        return styles;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -96,21 +91,9 @@ export class AkDualSelect extends CustomEmitterElement(CustomListenerElement(AKE
 | 
				
			|||||||
        super();
 | 
					        super();
 | 
				
			||||||
        this.handleMove = this.handleMove.bind(this);
 | 
					        this.handleMove = this.handleMove.bind(this);
 | 
				
			||||||
        this.handleSearch = this.handleSearch.bind(this);
 | 
					        this.handleSearch = this.handleSearch.bind(this);
 | 
				
			||||||
        [
 | 
					        this.addEventListener(DualSelectMoveRequestEvent.eventName, this.handleMove);
 | 
				
			||||||
            EVENT_ADD_ALL,
 | 
					        this.addEventListener(DualSelectUpdateEvent.eventName, () => this.requestUpdate());
 | 
				
			||||||
            EVENT_ADD_SELECTED,
 | 
					        this.addEventListener(DualSelectPanelSearchEvent.eventName, this.handleSearch);
 | 
				
			||||||
            EVENT_DELETE_ALL,
 | 
					 | 
				
			||||||
            EVENT_REMOVE_ALL,
 | 
					 | 
				
			||||||
            EVENT_REMOVE_SELECTED,
 | 
					 | 
				
			||||||
            EVENT_ADD_ONE,
 | 
					 | 
				
			||||||
            EVENT_REMOVE_ONE,
 | 
					 | 
				
			||||||
        ].forEach((eventName: string) => {
 | 
					 | 
				
			||||||
            this.addCustomListener(eventName, (event: Event) => this.handleMove(eventName, event));
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        this.addCustomListener("ak-dual-select-move", () => {
 | 
					 | 
				
			||||||
            this.requestUpdate();
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        this.addCustomListener("ak-search", this.handleSearch);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    willUpdate(changedProperties: PropertyValues<this>) {
 | 
					    willUpdate(changedProperties: PropertyValues<this>) {
 | 
				
			||||||
@ -123,47 +106,17 @@ export class AkDualSelect extends CustomEmitterElement(CustomListenerElement(AKE
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    handleMove(eventName: string, event: Event) {
 | 
					    handleMove(event: DualSelectMoveRequestEvent) {
 | 
				
			||||||
        if (!(event instanceof CustomEvent)) {
 | 
					        match(event.move)
 | 
				
			||||||
            throw new Error(`Expected move event here, got ${eventName}`);
 | 
					            .with("add-all", () => this.addAllVisible())
 | 
				
			||||||
        }
 | 
					            .with("add-one", () => this.addOne(event.key))
 | 
				
			||||||
 | 
					            .with("add-selected", () => this.addSelected())
 | 
				
			||||||
        switch (eventName) {
 | 
					            .with("delete-all", () => this.removeAll())
 | 
				
			||||||
            case EVENT_ADD_SELECTED: {
 | 
					            .with("remove-all", () => this.removeAllVisible())
 | 
				
			||||||
                this.addSelected();
 | 
					            .with("remove-one", () => this.removeOne(event.key))
 | 
				
			||||||
                break;
 | 
					            .with("remove-selected", () => this.removeSelected())
 | 
				
			||||||
            }
 | 
					            .exhaustive();
 | 
				
			||||||
            case EVENT_REMOVE_SELECTED: {
 | 
					        this.dispatchEvent(new DualSelectChangeEvent(this.value));
 | 
				
			||||||
                this.removeSelected();
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            case EVENT_ADD_ALL: {
 | 
					 | 
				
			||||||
                this.addAllVisible();
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            case EVENT_REMOVE_ALL: {
 | 
					 | 
				
			||||||
                this.removeAllVisible();
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            case EVENT_DELETE_ALL: {
 | 
					 | 
				
			||||||
                this.removeAll();
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            case EVENT_ADD_ONE: {
 | 
					 | 
				
			||||||
                this.addOne(event.detail);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            case EVENT_REMOVE_ONE: {
 | 
					 | 
				
			||||||
                this.removeOne(event.detail);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            default:
 | 
					 | 
				
			||||||
                throw new Error(
 | 
					 | 
				
			||||||
                    `AkDualSelect.handleMove received unknown event type: ${eventName}`,
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.dispatchCustomEvent("ak-dual-select-change", { value: this.value });
 | 
					 | 
				
			||||||
        event.stopPropagation();
 | 
					        event.stopPropagation();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -182,7 +135,10 @@ export class AkDualSelect extends CustomEmitterElement(CustomListenerElement(AKE
 | 
				
			|||||||
        this.availablePane.value!.clearMove();
 | 
					        this.availablePane.value!.clearMove();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    addOne(key: string) {
 | 
					    addOne(key?: string) {
 | 
				
			||||||
 | 
					        if (!key) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        const requested = this.options.find(keyfinder(key));
 | 
					        const requested = this.options.find(keyfinder(key));
 | 
				
			||||||
        if (requested && !this.selected.find(keyfinder(requested[0]))) {
 | 
					        if (requested && !this.selected.find(keyfinder(requested[0]))) {
 | 
				
			||||||
            this.selected = [...this.selected, requested];
 | 
					            this.selected = [...this.selected, requested];
 | 
				
			||||||
@ -207,7 +163,10 @@ export class AkDualSelect extends CustomEmitterElement(CustomListenerElement(AKE
 | 
				
			|||||||
        this.selectedPane.value!.clearMove();
 | 
					        this.selectedPane.value!.clearMove();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    removeOne(key: string) {
 | 
					    removeOne(key?: string) {
 | 
				
			||||||
 | 
					        if (!key) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        this.selected = this.selected.filter(([k]) => k !== key);
 | 
					        this.selected = this.selected.filter(([k]) => k !== key);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -223,18 +182,18 @@ export class AkDualSelect extends CustomEmitterElement(CustomListenerElement(AKE
 | 
				
			|||||||
        this.selectedPane.value!.clearMove();
 | 
					        this.selectedPane.value!.clearMove();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    handleSearch(event: SearchbarEvent) {
 | 
					    handleSearch(event: DualSelectPanelSearchEvent) {
 | 
				
			||||||
        switch (event.detail.source) {
 | 
					        switch (event.source) {
 | 
				
			||||||
            case "ak-dual-list-available-search":
 | 
					            case "ak-dual-list-available-search":
 | 
				
			||||||
                return this.handleAvailableSearch(event.detail.value);
 | 
					                return this.handleAvailableSearch(event.filterOn);
 | 
				
			||||||
            case "ak-dual-list-selected-search":
 | 
					            case "ak-dual-list-selected-search":
 | 
				
			||||||
                return this.handleSelectedSearch(event.detail.value);
 | 
					                return this.handleSelectedSearch(event.filterOn);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        event.stopPropagation();
 | 
					        event.stopPropagation();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    handleAvailableSearch(value: string) {
 | 
					    handleAvailableSearch(value: string) {
 | 
				
			||||||
        this.dispatchCustomEvent("ak-dual-select-search", value);
 | 
					        this.dispatchEvent(new DualSelectSearchEvent(value));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    handleSelectedSearch(value: string) {
 | 
					    handleSelectedSearch(value: string) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,26 +1,19 @@
 | 
				
			|||||||
import { AKElement } from "@goauthentik/elements/Base";
 | 
					import { bound } from "@goauthentik/elements/decorators/bound";
 | 
				
			||||||
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { html, nothing } from "lit";
 | 
					import { html, nothing } from "lit";
 | 
				
			||||||
import { customElement, property, state } from "lit/decorators.js";
 | 
					import { customElement, property } from "lit/decorators.js";
 | 
				
			||||||
import { classMap } from "lit/directives/class-map.js";
 | 
					import { classMap } from "lit/directives/class-map.js";
 | 
				
			||||||
import { map } from "lit/directives/map.js";
 | 
					import { map } from "lit/directives/map.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { availablePaneStyles, listStyles } from "./styles.css";
 | 
					import { availablePaneStyles } from "./styles.css";
 | 
				
			||||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
 | 
					 | 
				
			||||||
import PFDualListSelector from "@patternfly/patternfly/components/DualListSelector/dual-list-selector.css";
 | 
					 | 
				
			||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { EVENT_ADD_ONE } from "../constants";
 | 
					import {
 | 
				
			||||||
 | 
					    DualSelectMoveAvailableEvent,
 | 
				
			||||||
 | 
					    DualSelectMoveRequestEvent,
 | 
				
			||||||
 | 
					    DualSelectUpdateEvent,
 | 
				
			||||||
 | 
					} from "../events";
 | 
				
			||||||
import type { DualSelectPair } from "../types";
 | 
					import type { DualSelectPair } from "../types";
 | 
				
			||||||
 | 
					import { AkDualSelectAbstractPane } from "./ak-dual-select-pane";
 | 
				
			||||||
const styles = [PFBase, PFButton, PFDualListSelector, listStyles, availablePaneStyles];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const hostAttributes = [
 | 
					 | 
				
			||||||
    ["aria-labelledby", "dual-list-selector-available-pane-status"],
 | 
					 | 
				
			||||||
    ["aria-multiselectable", "true"],
 | 
					 | 
				
			||||||
    ["role", "listbox"],
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @element ak-dual-select-available-panel
 | 
					 * @element ak-dual-select-available-panel
 | 
				
			||||||
@ -40,9 +33,9 @@ const hostAttributes = [
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@customElement("ak-dual-select-available-pane")
 | 
					@customElement("ak-dual-select-available-pane")
 | 
				
			||||||
export class AkDualSelectAvailablePane extends CustomEmitterElement(AKElement) {
 | 
					export class AkDualSelectAvailablePane extends AkDualSelectAbstractPane {
 | 
				
			||||||
    static get styles() {
 | 
					    static get styles() {
 | 
				
			||||||
        return styles;
 | 
					        return [...AkDualSelectAbstractPane.styles, availablePaneStyles];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* The array of key/value pairs this pane is currently showing */
 | 
					    /* The array of key/value pairs this pane is currently showing */
 | 
				
			||||||
@ -56,68 +49,31 @@ export class AkDualSelectAvailablePane extends CustomEmitterElement(AKElement) {
 | 
				
			|||||||
    @property({ type: Object })
 | 
					    @property({ type: Object })
 | 
				
			||||||
    readonly selected: Set<string> = new Set();
 | 
					    readonly selected: Set<string> = new Set();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* This is the only mutator for this object. It collects the list of objects the user has
 | 
					    @bound
 | 
				
			||||||
     * clicked on *in this pane*. It is explicitly marked as "public" to emphasize that the parent
 | 
					 | 
				
			||||||
     * orchestrator for the dual-select widget can and will access it to get the list of keys to be
 | 
					 | 
				
			||||||
     * moved (removed) if the user so requests.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @state()
 | 
					 | 
				
			||||||
    public toMove: Set<string> = new Set();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    constructor() {
 | 
					 | 
				
			||||||
        super();
 | 
					 | 
				
			||||||
        this.onClick = this.onClick.bind(this);
 | 
					 | 
				
			||||||
        this.onMove = this.onMove.bind(this);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    connectedCallback() {
 | 
					 | 
				
			||||||
        super.connectedCallback();
 | 
					 | 
				
			||||||
        hostAttributes.forEach(([attr, value]) => {
 | 
					 | 
				
			||||||
            if (!this.hasAttribute(attr)) {
 | 
					 | 
				
			||||||
                this.setAttribute(attr, value);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    clearMove() {
 | 
					 | 
				
			||||||
        this.toMove = new Set();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    onClick(key: string) {
 | 
					    onClick(key: string) {
 | 
				
			||||||
        if (this.selected.has(key)) {
 | 
					        if (this.selected.has(key)) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (this.toMove.has(key)) {
 | 
					        this.move(key);
 | 
				
			||||||
            this.toMove.delete(key);
 | 
					        this.dispatchEvent(new DualSelectMoveAvailableEvent(this.moveable.sort()));
 | 
				
			||||||
        } else {
 | 
					        this.dispatchEvent(new DualSelectUpdateEvent());
 | 
				
			||||||
            this.toMove.add(key);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.dispatchCustomEvent(
 | 
					 | 
				
			||||||
            "ak-dual-select-available-move-changed",
 | 
					 | 
				
			||||||
            Array.from(this.toMove.values()).sort(),
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        this.dispatchCustomEvent("ak-dual-select-move");
 | 
					 | 
				
			||||||
        // Necessary because updating a map won't trigger a state change
 | 
					        // Necessary because updating a map won't trigger a state change
 | 
				
			||||||
        this.requestUpdate();
 | 
					        this.requestUpdate();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @bound
 | 
				
			||||||
    onMove(key: string) {
 | 
					    onMove(key: string) {
 | 
				
			||||||
        this.toMove.delete(key);
 | 
					        this.toMove.delete(key);
 | 
				
			||||||
        this.dispatchCustomEvent(EVENT_ADD_ONE, key);
 | 
					        this.dispatchEvent(new DualSelectMoveRequestEvent("add-one", key));
 | 
				
			||||||
        this.requestUpdate();
 | 
					        this.requestUpdate();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get moveable() {
 | 
					 | 
				
			||||||
        return Array.from(this.toMove.values());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // DO NOT use `Array.map()` instead of Lit's `map()` function. Lit's `map()` is object-aware and
 | 
					    // DO NOT use `Array.map()` instead of Lit's `map()` function. Lit's `map()` is object-aware and
 | 
				
			||||||
    // will not re-arrange or reconstruct the list automatically if the actual sources do not
 | 
					    // will not re-arrange or reconstruct the list automatically if the actual sources do not
 | 
				
			||||||
    // change; this allows the available pane to illustrate selected items with the checkmark
 | 
					    // change; this allows the available pane to illustrate selected items with the checkmark
 | 
				
			||||||
    // without causing the list to scroll back up to the top.
 | 
					    // without causing the list to scroll back up to the top.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render() {
 | 
					    override render() {
 | 
				
			||||||
        return html`
 | 
					        return html`
 | 
				
			||||||
            <div class="pf-c-dual-list-selector__menu">
 | 
					            <div class="pf-c-dual-list-selector__menu">
 | 
				
			||||||
                <ul class="pf-c-dual-list-selector__list">
 | 
					                <ul class="pf-c-dual-list-selector__list">
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,4 @@
 | 
				
			|||||||
import { AKElement } from "@goauthentik/elements/Base";
 | 
					import { AKElement } from "@goauthentik/elements/Base";
 | 
				
			||||||
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { msg } from "@lit/localize";
 | 
					import { msg } from "@lit/localize";
 | 
				
			||||||
import { css, html, nothing } from "lit";
 | 
					import { css, html, nothing } from "lit";
 | 
				
			||||||
@ -8,13 +7,7 @@ import { customElement, property } from "lit/decorators.js";
 | 
				
			|||||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
 | 
					import PFButton from "@patternfly/patternfly/components/Button/button.css";
 | 
				
			||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
					import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {
 | 
					import { DualSelectMoveRequestEvent, type MoveEventType } from "../events";
 | 
				
			||||||
    EVENT_ADD_ALL,
 | 
					 | 
				
			||||||
    EVENT_ADD_SELECTED,
 | 
					 | 
				
			||||||
    EVENT_DELETE_ALL,
 | 
					 | 
				
			||||||
    EVENT_REMOVE_ALL,
 | 
					 | 
				
			||||||
    EVENT_REMOVE_SELECTED,
 | 
					 | 
				
			||||||
} from "../constants";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const styles = [
 | 
					const styles = [
 | 
				
			||||||
    PFBase,
 | 
					    PFBase,
 | 
				
			||||||
@ -47,7 +40,7 @@ const styles = [
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@customElement("ak-dual-select-controls")
 | 
					@customElement("ak-dual-select-controls")
 | 
				
			||||||
export class AkDualSelectControls extends CustomEmitterElement(AKElement) {
 | 
					export class AkDualSelectControls extends AKElement {
 | 
				
			||||||
    static get styles() {
 | 
					    static get styles() {
 | 
				
			||||||
        return styles;
 | 
					        return styles;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -96,11 +89,11 @@ export class AkDualSelectControls extends CustomEmitterElement(AKElement) {
 | 
				
			|||||||
        this.onClick = this.onClick.bind(this);
 | 
					        this.onClick = this.onClick.bind(this);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    onClick(eventName: string) {
 | 
					    onClick(eventName: MoveEventType) {
 | 
				
			||||||
        this.dispatchCustomEvent(eventName);
 | 
					        this.dispatchEvent(new DualSelectMoveRequestEvent(eventName));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    renderButton(label: string, event: string, active: boolean, direction: string) {
 | 
					    renderButton(label: string, event: MoveEventType, active: boolean, direction: string) {
 | 
				
			||||||
        return html`
 | 
					        return html`
 | 
				
			||||||
            <div class="pf-c-dual-list-selector__controls-item">
 | 
					            <div class="pf-c-dual-list-selector__controls-item">
 | 
				
			||||||
                <button
 | 
					                <button
 | 
				
			||||||
@ -121,23 +114,18 @@ export class AkDualSelectControls extends CustomEmitterElement(AKElement) {
 | 
				
			|||||||
    render() {
 | 
					    render() {
 | 
				
			||||||
        return html`
 | 
					        return html`
 | 
				
			||||||
            <div class="ak-dual-list-selector__controls">
 | 
					            <div class="ak-dual-list-selector__controls">
 | 
				
			||||||
                ${this.renderButton(
 | 
					                ${this.renderButton(msg("Add"), "add-selected", this.addActive, "fa-angle-right")}
 | 
				
			||||||
                    msg("Add"),
 | 
					 | 
				
			||||||
                    EVENT_ADD_SELECTED,
 | 
					 | 
				
			||||||
                    this.addActive,
 | 
					 | 
				
			||||||
                    "fa-angle-right",
 | 
					 | 
				
			||||||
                )}
 | 
					 | 
				
			||||||
                ${this.selectAll
 | 
					                ${this.selectAll
 | 
				
			||||||
                    ? html`
 | 
					                    ? html`
 | 
				
			||||||
                          ${this.renderButton(
 | 
					                          ${this.renderButton(
 | 
				
			||||||
                              msg("Add All Available"),
 | 
					                              msg("Add All Available"),
 | 
				
			||||||
                              EVENT_ADD_ALL,
 | 
					                              "add-all",
 | 
				
			||||||
                              this.addAllActive,
 | 
					                              this.addAllActive,
 | 
				
			||||||
                              "fa-angle-double-right",
 | 
					                              "fa-angle-double-right",
 | 
				
			||||||
                          )}
 | 
					                          )}
 | 
				
			||||||
                          ${this.renderButton(
 | 
					                          ${this.renderButton(
 | 
				
			||||||
                              msg("Remove All Available"),
 | 
					                              msg("Remove All Available"),
 | 
				
			||||||
                              EVENT_REMOVE_ALL,
 | 
					                              "remove-all",
 | 
				
			||||||
                              this.removeAllActive,
 | 
					                              this.removeAllActive,
 | 
				
			||||||
                              "fa-angle-double-left",
 | 
					                              "fa-angle-double-left",
 | 
				
			||||||
                          )}
 | 
					                          )}
 | 
				
			||||||
@ -145,14 +133,14 @@ export class AkDualSelectControls extends CustomEmitterElement(AKElement) {
 | 
				
			|||||||
                    : nothing}
 | 
					                    : nothing}
 | 
				
			||||||
                ${this.renderButton(
 | 
					                ${this.renderButton(
 | 
				
			||||||
                    msg("Remove"),
 | 
					                    msg("Remove"),
 | 
				
			||||||
                    EVENT_REMOVE_SELECTED,
 | 
					                    "remove-selected",
 | 
				
			||||||
                    this.removeActive,
 | 
					                    this.removeActive,
 | 
				
			||||||
                    "fa-angle-left",
 | 
					                    "fa-angle-left",
 | 
				
			||||||
                )}
 | 
					                )}
 | 
				
			||||||
                ${this.deleteAll
 | 
					                ${this.deleteAll
 | 
				
			||||||
                    ? html`${this.renderButton(
 | 
					                    ? html`${this.renderButton(
 | 
				
			||||||
                          msg("Remove All"),
 | 
					                          msg("Remove All"),
 | 
				
			||||||
                          EVENT_DELETE_ALL,
 | 
					                          "delete-all",
 | 
				
			||||||
                          this.enableDeleteAll,
 | 
					                          this.enableDeleteAll,
 | 
				
			||||||
                          "fa-times",
 | 
					                          "fa-times",
 | 
				
			||||||
                      )}`
 | 
					                      )}`
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,75 @@
 | 
				
			|||||||
 | 
					import { AKElement } from "@goauthentik/elements/Base";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { TemplateResult } from "lit";
 | 
				
			||||||
 | 
					import { state } from "lit/decorators.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { listStyles } from "./styles.css";
 | 
				
			||||||
 | 
					import PFButton from "@patternfly/patternfly/components/Button/button.css";
 | 
				
			||||||
 | 
					import PFDualListSelector from "@patternfly/patternfly/components/DualListSelector/dual-list-selector.css";
 | 
				
			||||||
 | 
					import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const styles = [PFBase, PFButton, PFDualListSelector, listStyles];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const hostAttributes = [
 | 
				
			||||||
 | 
					    ["aria-labelledby", "dual-list-selector-selected-pane-status"],
 | 
				
			||||||
 | 
					    ["aria-multiselectable", "true"],
 | 
				
			||||||
 | 
					    ["role", "listbox"],
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @element ak-dual-select-panel
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The "selected options" or "right" pane in a dual-list multi-select.  It receives from its parent
 | 
				
			||||||
 | 
					 * a list of the selected options, and maintains an internal list of objects selected to move.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @fires ak-dual-select-selected-move-changed - When the list of "to move" entries changed.
 | 
				
			||||||
 | 
					 * Includes the current `toMove` content.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @fires ak-dual-select-remove-one - Double-click with the element clicked on.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * It is not expected that the `ak-dual-select-selected-move-changed` will be used; instead, the
 | 
				
			||||||
 | 
					 * attribute will be read by the parent when a control is clicked.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export abstract class AkDualSelectAbstractPane extends AKElement {
 | 
				
			||||||
 | 
					    static get styles() {
 | 
				
			||||||
 | 
					        return styles;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * This is the only mutator for this object. It collects the list of objects the user has
 | 
				
			||||||
 | 
					     * clicked on *in this pane*. It is explicitly marked as "public" to emphasize that the parent
 | 
				
			||||||
 | 
					     * orchestrator for the dual-select widget can and will access it to get the list of keys to be
 | 
				
			||||||
 | 
					     * moved (removed) if the user so requests.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @state()
 | 
				
			||||||
 | 
					    public toMove: Set<string> = new Set();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    connectedCallback() {
 | 
				
			||||||
 | 
					        super.connectedCallback();
 | 
				
			||||||
 | 
					        hostAttributes.forEach(([attr, value]) => {
 | 
				
			||||||
 | 
					            if (!this.hasAttribute(attr)) {
 | 
				
			||||||
 | 
					                this.setAttribute(attr, value);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    clearMove() {
 | 
				
			||||||
 | 
					        this.toMove = new Set();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    move(key: string) {
 | 
				
			||||||
 | 
					        if (this.toMove.has(key)) {
 | 
				
			||||||
 | 
					            this.toMove.delete(key);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            this.toMove.add(key);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get moveable() {
 | 
				
			||||||
 | 
					        return Array.from(this.toMove.values());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    abstract render(): TemplateResult;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,26 +1,19 @@
 | 
				
			|||||||
import { AKElement } from "@goauthentik/elements/Base";
 | 
					import { bound } from "@goauthentik/elements/decorators/bound";
 | 
				
			||||||
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { html } from "lit";
 | 
					import { html } from "lit";
 | 
				
			||||||
import { customElement, property, state } from "lit/decorators.js";
 | 
					import { customElement, property } from "lit/decorators.js";
 | 
				
			||||||
import { classMap } from "lit/directives/class-map.js";
 | 
					import { classMap } from "lit/directives/class-map.js";
 | 
				
			||||||
import { map } from "lit/directives/map.js";
 | 
					import { map } from "lit/directives/map.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { listStyles, selectedPaneStyles } from "./styles.css";
 | 
					import { selectedPaneStyles } from "./styles.css";
 | 
				
			||||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
 | 
					 | 
				
			||||||
import PFDualListSelector from "@patternfly/patternfly/components/DualListSelector/dual-list-selector.css";
 | 
					 | 
				
			||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { EVENT_REMOVE_ONE } from "../constants";
 | 
					import {
 | 
				
			||||||
 | 
					    DualSelectMoveRequestEvent,
 | 
				
			||||||
 | 
					    DualSelectMoveSelectedEvent,
 | 
				
			||||||
 | 
					    DualSelectUpdateEvent,
 | 
				
			||||||
 | 
					} from "../events";
 | 
				
			||||||
import type { DualSelectPair } from "../types";
 | 
					import type { DualSelectPair } from "../types";
 | 
				
			||||||
 | 
					import { AkDualSelectAbstractPane } from "./ak-dual-select-pane";
 | 
				
			||||||
const styles = [PFBase, PFButton, PFDualListSelector, listStyles, selectedPaneStyles];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const hostAttributes = [
 | 
					 | 
				
			||||||
    ["aria-labelledby", "dual-list-selector-selected-pane-status"],
 | 
					 | 
				
			||||||
    ["aria-multiselectable", "true"],
 | 
					 | 
				
			||||||
    ["role", "listbox"],
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @element ak-dual-select-available-panel
 | 
					 * @element ak-dual-select-available-panel
 | 
				
			||||||
@ -38,70 +31,32 @@ const hostAttributes = [
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@customElement("ak-dual-select-selected-pane")
 | 
					@customElement("ak-dual-select-selected-pane")
 | 
				
			||||||
export class AkDualSelectSelectedPane extends CustomEmitterElement(AKElement) {
 | 
					export class AkDualSelectSelectedPane extends AkDualSelectAbstractPane {
 | 
				
			||||||
    static get styles() {
 | 
					    static get styles() {
 | 
				
			||||||
        return styles;
 | 
					        return [...AkDualSelectAbstractPane.styles, selectedPaneStyles];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* The array of key/value pairs that are in the selected list.  ALL of them. */
 | 
					    /* The array of key/value pairs that are in the selected list.  ALL of them. */
 | 
				
			||||||
    @property({ type: Array })
 | 
					    @property({ type: Array })
 | 
				
			||||||
    readonly selected: DualSelectPair[] = [];
 | 
					    readonly selected: DualSelectPair[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    @bound
 | 
				
			||||||
     * This is the only mutator for this object. It collects the list of objects the user has
 | 
					 | 
				
			||||||
     * clicked on *in this pane*. It is explicitly marked as "public" to emphasize that the parent
 | 
					 | 
				
			||||||
     * orchestrator for the dual-select widget can and will access it to get the list of keys to be
 | 
					 | 
				
			||||||
     * moved (removed) if the user so requests.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @state()
 | 
					 | 
				
			||||||
    public toMove: Set<string> = new Set();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    constructor() {
 | 
					 | 
				
			||||||
        super();
 | 
					 | 
				
			||||||
        this.onClick = this.onClick.bind(this);
 | 
					 | 
				
			||||||
        this.onMove = this.onMove.bind(this);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    connectedCallback() {
 | 
					 | 
				
			||||||
        super.connectedCallback();
 | 
					 | 
				
			||||||
        hostAttributes.forEach(([attr, value]) => {
 | 
					 | 
				
			||||||
            if (!this.hasAttribute(attr)) {
 | 
					 | 
				
			||||||
                this.setAttribute(attr, value);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    clearMove() {
 | 
					 | 
				
			||||||
        this.toMove = new Set();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    onClick(key: string) {
 | 
					    onClick(key: string) {
 | 
				
			||||||
        if (this.toMove.has(key)) {
 | 
					        this.move(key);
 | 
				
			||||||
            this.toMove.delete(key);
 | 
					        this.dispatchEvent(new DualSelectMoveSelectedEvent(this.moveable.sort()));
 | 
				
			||||||
        } else {
 | 
					        this.dispatchEvent(new DualSelectUpdateEvent());
 | 
				
			||||||
            this.toMove.add(key);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.dispatchCustomEvent(
 | 
					 | 
				
			||||||
            "ak-dual-select-selected-move-changed",
 | 
					 | 
				
			||||||
            Array.from(this.toMove.values()).sort(),
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        this.dispatchCustomEvent("ak-dual-select-move");
 | 
					 | 
				
			||||||
        // Necessary because updating a map won't trigger a state change
 | 
					        // Necessary because updating a map won't trigger a state change
 | 
				
			||||||
        this.requestUpdate();
 | 
					        this.requestUpdate();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @bound
 | 
				
			||||||
    onMove(key: string) {
 | 
					    onMove(key: string) {
 | 
				
			||||||
        this.toMove.delete(key);
 | 
					        this.toMove.delete(key);
 | 
				
			||||||
        this.dispatchCustomEvent(EVENT_REMOVE_ONE, key);
 | 
					        this.dispatchEvent(new DualSelectMoveRequestEvent("remove-one", key));
 | 
				
			||||||
        this.requestUpdate();
 | 
					        this.requestUpdate();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get moveable() {
 | 
					    override render() {
 | 
				
			||||||
        return Array.from(this.toMove.values());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    render() {
 | 
					 | 
				
			||||||
        return html`
 | 
					        return html`
 | 
				
			||||||
            <div class="pf-c-dual-list-selector__menu">
 | 
					            <div class="pf-c-dual-list-selector__menu">
 | 
				
			||||||
                <ul class="pf-c-dual-list-selector__list">
 | 
					                <ul class="pf-c-dual-list-selector__list">
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,4 @@
 | 
				
			|||||||
import { AKElement } from "@goauthentik/elements/Base";
 | 
					import { AKElement } from "@goauthentik/elements/Base";
 | 
				
			||||||
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { msg, str } from "@lit/localize";
 | 
					import { msg, str } from "@lit/localize";
 | 
				
			||||||
import { css, html, nothing } from "lit";
 | 
					import { css, html, nothing } from "lit";
 | 
				
			||||||
@ -9,6 +8,7 @@ import PFButton from "@patternfly/patternfly/components/Button/button.css";
 | 
				
			|||||||
import PFPagination from "@patternfly/patternfly/components/Pagination/pagination.css";
 | 
					import PFPagination from "@patternfly/patternfly/components/Pagination/pagination.css";
 | 
				
			||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
					import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { DualSelectPaginatorNavEvent } from "../events";
 | 
				
			||||||
import type { BasePagination } from "../types";
 | 
					import type { BasePagination } from "../types";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const styles = [
 | 
					const styles = [
 | 
				
			||||||
@ -27,7 +27,7 @@ const styles = [
 | 
				
			|||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@customElement("ak-pagination")
 | 
					@customElement("ak-pagination")
 | 
				
			||||||
export class AkPagination extends CustomEmitterElement(AKElement) {
 | 
					export class AkPagination extends AKElement {
 | 
				
			||||||
    static get styles() {
 | 
					    static get styles() {
 | 
				
			||||||
        return styles;
 | 
					        return styles;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -41,7 +41,7 @@ export class AkPagination extends CustomEmitterElement(AKElement) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    onClick(nav: number | undefined) {
 | 
					    onClick(nav: number | undefined) {
 | 
				
			||||||
        this.dispatchCustomEvent("ak-pagination-nav-to", nav ?? 0);
 | 
					        this.dispatchEvent(new DualSelectPaginatorNavEvent(nav ?? 0));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render() {
 | 
					    render() {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,4 @@
 | 
				
			|||||||
import { AKElement } from "@goauthentik/elements/Base";
 | 
					import { AKElement } from "@goauthentik/elements/Base";
 | 
				
			||||||
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { html } from "lit";
 | 
					import { html } from "lit";
 | 
				
			||||||
import { customElement, property } from "lit/decorators.js";
 | 
					import { customElement, property } from "lit/decorators.js";
 | 
				
			||||||
@ -9,12 +8,12 @@ import type { Ref } from "lit/directives/ref.js";
 | 
				
			|||||||
import { globalVariables, searchStyles } from "./search.css";
 | 
					import { globalVariables, searchStyles } from "./search.css";
 | 
				
			||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
					import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import type { SearchbarEvent } from "../types";
 | 
					import { DualSelectPanelSearchEvent } from "../events";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const styles = [PFBase, globalVariables, searchStyles];
 | 
					const styles = [PFBase, globalVariables, searchStyles];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@customElement("ak-search-bar")
 | 
					@customElement("ak-search-bar")
 | 
				
			||||||
export class AkSearchbar extends CustomEmitterElement(AKElement) {
 | 
					export class AkSearchbar extends AKElement {
 | 
				
			||||||
    static get styles() {
 | 
					    static get styles() {
 | 
				
			||||||
        return styles;
 | 
					        return styles;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -40,10 +39,7 @@ export class AkSearchbar extends CustomEmitterElement(AKElement) {
 | 
				
			|||||||
        if (this.input.value) {
 | 
					        if (this.input.value) {
 | 
				
			||||||
            this.value = this.input.value.value;
 | 
					            this.value = this.input.value.value;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        this.dispatchCustomEvent<SearchbarEvent>("ak-search", {
 | 
					        this.dispatchEvent(new DualSelectPanelSearchEvent(this.name, this.value));
 | 
				
			||||||
            source: this.name,
 | 
					 | 
				
			||||||
            value: this.value,
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render() {
 | 
					    render() {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										112
									
								
								web/src/elements/ak-dual-select/events.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								web/src/elements/ak-dual-select/events.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,112 @@
 | 
				
			|||||||
 | 
					import { DualSelectPair } from "./types";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Handled by the Server layer provider
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Request to provide a different page of the paginated results in the "available" panel.
 | 
				
			||||||
 | 
					export class DualSelectPaginatorNavEvent extends Event {
 | 
				
			||||||
 | 
					    static readonly eventName = "ak-dual-select-paginator-nav";
 | 
				
			||||||
 | 
					    constructor(public page: number = 0) {
 | 
				
			||||||
 | 
					        super(DualSelectPaginatorNavEvent.eventName, { bubbles: true, composed: true });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Request to provide a filtered collection for the "available" panel via a search string
 | 
				
			||||||
 | 
					export class DualSelectSearchEvent extends Event {
 | 
				
			||||||
 | 
					    static readonly eventName = "ak-dual-select-search";
 | 
				
			||||||
 | 
					    constructor(public search: string) {
 | 
				
			||||||
 | 
					        super(DualSelectSearchEvent.eventName, { bubbles: true, composed: true });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Request to update the "selected" list in the provider
 | 
				
			||||||
 | 
					export class DualSelectChangeEvent extends Event {
 | 
				
			||||||
 | 
					    static readonly eventName = "ak-dual-select-change";
 | 
				
			||||||
 | 
					    constructor(public selected: DualSelectPair[]) {
 | 
				
			||||||
 | 
					        super(DualSelectChangeEvent.eventName, { bubbles: true, composed: true });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Paginator and specific item events
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const moveEvents = [
 | 
				
			||||||
 | 
					    "add-all",
 | 
				
			||||||
 | 
					    "add-one",
 | 
				
			||||||
 | 
					    "add-selected",
 | 
				
			||||||
 | 
					    "delete-all",
 | 
				
			||||||
 | 
					    "remove-all",
 | 
				
			||||||
 | 
					    "remove-one",
 | 
				
			||||||
 | 
					    "remove-selected",
 | 
				
			||||||
 | 
					] as const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type MoveEventType = (typeof moveEvents)[number];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Request to add or remove all, some, or just one item from the "selected" panel
 | 
				
			||||||
 | 
					export class DualSelectMoveRequestEvent extends Event {
 | 
				
			||||||
 | 
					    static readonly eventName = "ak-dual-select-request-move";
 | 
				
			||||||
 | 
					    constructor(
 | 
				
			||||||
 | 
					        public move: MoveEventType,
 | 
				
			||||||
 | 
					        public key?: string,
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        super(DualSelectMoveRequestEvent.eventName, { bubbles: true, composed: true });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Update events
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Request to update the viewset
 | 
				
			||||||
 | 
					export class DualSelectUpdateEvent extends Event {
 | 
				
			||||||
 | 
					    static readonly eventName = "ak-dual-select-update";
 | 
				
			||||||
 | 
					    constructor() {
 | 
				
			||||||
 | 
					        super(DualSelectUpdateEvent.eventName, { bubbles: true, composed: true });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface DualSelectMoveChangedEvent {
 | 
				
			||||||
 | 
					    keys: string[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Request to update the list of "marked for move" items in the "available" panel
 | 
				
			||||||
 | 
					export class DualSelectMoveAvailableEvent extends Event implements DualSelectMoveChangedEvent {
 | 
				
			||||||
 | 
					    static readonly eventName = "ak-dual-select-move-available";
 | 
				
			||||||
 | 
					    constructor(public keys: string[]) {
 | 
				
			||||||
 | 
					        super(DualSelectMoveAvailableEvent.eventName, { bubbles: true, composed: true });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Request to update the list of "marked for move" items in the "selected" panel
 | 
				
			||||||
 | 
					export class DualSelectMoveSelectedEvent extends Event implements DualSelectMoveChangedEvent {
 | 
				
			||||||
 | 
					    static readonly eventName = "ak-dual-select-move-selected";
 | 
				
			||||||
 | 
					    constructor(public keys: string[]) {
 | 
				
			||||||
 | 
					        super(DualSelectMoveSelectedEvent.eventName, { bubbles: true, composed: true });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Request to update either panel with a Filter
 | 
				
			||||||
 | 
					export class DualSelectPanelSearchEvent extends Event {
 | 
				
			||||||
 | 
					    static readonly eventName = "ak-dual-select-panel-search";
 | 
				
			||||||
 | 
					    constructor(
 | 
				
			||||||
 | 
					        public source: string,
 | 
				
			||||||
 | 
					        public filterOn: string,
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        super(DualSelectPanelSearchEvent.eventName, { bubbles: true, composed: true });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					declare global {
 | 
				
			||||||
 | 
					    interface HTMLElementEventMap {
 | 
				
			||||||
 | 
					        [DualSelectUpdateEvent.eventName]: DualSelectUpdateEvent;
 | 
				
			||||||
 | 
					        [DualSelectMoveAvailableEvent.eventName]: DualSelectMoveAvailableEvent;
 | 
				
			||||||
 | 
					        [DualSelectMoveSelectedEvent.eventName]: DualSelectMoveSelectedEvent;
 | 
				
			||||||
 | 
					        [DualSelectMoveRequestEvent.eventName]: DualSelectMoveRequestEvent;
 | 
				
			||||||
 | 
					        [DualSelectPaginatorNavEvent.eventName]: DualSelectPaginatorNavEvent;
 | 
				
			||||||
 | 
					        [DualSelectSearchEvent.eventName]: DualSelectSearchEvent;
 | 
				
			||||||
 | 
					        [DualSelectChangeEvent.eventName]: DualSelectChangeEvent;
 | 
				
			||||||
 | 
					        [DualSelectPanelSearchEvent.eventName]: DualSelectPanelSearchEvent;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    interface WindowEventMap {
 | 
				
			||||||
 | 
					        [DualSelectMoveRequestEvent.eventName]: DualSelectMoveRequestEvent;
 | 
				
			||||||
 | 
					        [DualSelectPaginatorNavEvent.eventName]: DualSelectPaginatorNavEvent;
 | 
				
			||||||
 | 
					        [DualSelectMoveSelectedEvent.eventName]: DualSelectMoveSelectedEvent;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -6,6 +6,7 @@ import { TemplateResult, html } from "lit";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import "../components/ak-dual-select-available-pane";
 | 
					import "../components/ak-dual-select-available-pane";
 | 
				
			||||||
import { AkDualSelectAvailablePane } from "../components/ak-dual-select-available-pane";
 | 
					import { AkDualSelectAvailablePane } from "../components/ak-dual-select-available-pane";
 | 
				
			||||||
 | 
					import { DualSelectMoveSelectedEvent } from "../events";
 | 
				
			||||||
import "./sb-host-provider";
 | 
					import "./sb-host-provider";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const metadata: Meta<AkDualSelectAvailablePane> = {
 | 
					const metadata: Meta<AkDualSelectAvailablePane> = {
 | 
				
			||||||
@ -53,15 +54,15 @@ const container = (testItem: TemplateResult) =>
 | 
				
			|||||||
    </div>`;
 | 
					    </div>`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
					// eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
				
			||||||
const handleMoveChanged = (result: any) => {
 | 
					const handleMoveChanged = (result: DualSelectMoveSelectedEvent) => {
 | 
				
			||||||
    const target = document.querySelector("#action-button-message-pad");
 | 
					    const target = document.querySelector("#action-button-message-pad");
 | 
				
			||||||
    target!.innerHTML = "";
 | 
					    target!.innerHTML = "";
 | 
				
			||||||
    result.detail.forEach((key: string) => {
 | 
					    result.keys.forEach((key: string) => {
 | 
				
			||||||
        target!.append(new DOMParser().parseFromString(`<li>${key}</li>`, "text/xml").firstChild!);
 | 
					        target!.append(new DOMParser().parseFromString(`<li>${key}</li>`, "text/xml").firstChild!);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
window.addEventListener("ak-dual-select-available-move-changed", handleMoveChanged);
 | 
					window.addEventListener(DualSelectMoveSelectedEvent.eventName, handleMoveChanged);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Story = StoryObj;
 | 
					type Story = StoryObj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@ import { TemplateResult, html } from "lit";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import "../components/ak-dual-select-controls";
 | 
					import "../components/ak-dual-select-controls";
 | 
				
			||||||
import { AkDualSelectControls } from "../components/ak-dual-select-controls";
 | 
					import { AkDualSelectControls } from "../components/ak-dual-select-controls";
 | 
				
			||||||
 | 
					import { DualSelectMoveRequestEvent } from "../events";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const metadata: Meta<AkDualSelectControls> = {
 | 
					const metadata: Meta<AkDualSelectControls> = {
 | 
				
			||||||
    title: "Elements / Dual Select / Control Panel",
 | 
					    title: "Elements / Dual Select / Control Panel",
 | 
				
			||||||
@ -59,10 +60,9 @@ const displayMessage = (result: any) => {
 | 
				
			|||||||
    target!.appendChild(doc.firstChild!);
 | 
					    target!.appendChild(doc.firstChild!);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
window.addEventListener("ak-dual-select-add", () => displayMessage("add"));
 | 
					window.addEventListener(DualSelectMoveRequestEvent.eventName, (ev: DualSelectMoveRequestEvent) =>
 | 
				
			||||||
window.addEventListener("ak-dual-select-remove", () => displayMessage("remove"));
 | 
					    displayMessage(ev.move.toString()),
 | 
				
			||||||
window.addEventListener("ak-dual-select-add-all", () => displayMessage("add all"));
 | 
					);
 | 
				
			||||||
window.addEventListener("ak-dual-select-remove-all", () => displayMessage("remove all"));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Story = StoryObj;
 | 
					type Story = StoryObj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,7 @@ import { Pagination } from "@goauthentik/api";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import "../ak-dual-select";
 | 
					import "../ak-dual-select";
 | 
				
			||||||
import { AkDualSelect } from "../ak-dual-select";
 | 
					import { AkDualSelect } from "../ak-dual-select";
 | 
				
			||||||
 | 
					import { DualSelectPaginatorNavEvent } from "../events";
 | 
				
			||||||
import type { DualSelectPair } from "../types";
 | 
					import type { DualSelectPair } from "../types";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const goodForYouRaw = `
 | 
					const goodForYouRaw = `
 | 
				
			||||||
@ -83,11 +84,11 @@ export class AkSbFruity extends LitElement {
 | 
				
			|||||||
            totalPages: Math.ceil(this.options.length / this.pageLength),
 | 
					            totalPages: Math.ceil(this.options.length / this.pageLength),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        this.onNavigation = this.onNavigation.bind(this);
 | 
					        this.onNavigation = this.onNavigation.bind(this);
 | 
				
			||||||
        this.addEventListener("ak-pagination-nav-to", this.onNavigation);
 | 
					        this.addEventListener(DualSelectPaginatorNavEvent.eventName, this.onNavigation);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    onNavigation(evt: Event) {
 | 
					    onNavigation(evt: DualSelectPaginatorNavEvent) {
 | 
				
			||||||
        const current: number = (evt as CustomEvent).detail;
 | 
					        const current = evt.page;
 | 
				
			||||||
        const index = current - 1;
 | 
					        const index = current - 1;
 | 
				
			||||||
        if (index * this.pageLength > this.options.length) {
 | 
					        if (index * this.pageLength > this.options.length) {
 | 
				
			||||||
            console.warn(
 | 
					            console.warn(
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@ import { TemplateResult, html } from "lit";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import "../components/ak-dual-select-selected-pane";
 | 
					import "../components/ak-dual-select-selected-pane";
 | 
				
			||||||
import { AkDualSelectSelectedPane } from "../components/ak-dual-select-selected-pane";
 | 
					import { AkDualSelectSelectedPane } from "../components/ak-dual-select-selected-pane";
 | 
				
			||||||
 | 
					import { DualSelectMoveSelectedEvent } from "../events";
 | 
				
			||||||
import "./sb-host-provider";
 | 
					import "./sb-host-provider";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const metadata: Meta<AkDualSelectSelectedPane> = {
 | 
					const metadata: Meta<AkDualSelectSelectedPane> = {
 | 
				
			||||||
@ -50,15 +51,15 @@ const container = (testItem: TemplateResult) =>
 | 
				
			|||||||
    </div>`;
 | 
					    </div>`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
					// eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
				
			||||||
const handleMoveChanged = (result: any) => {
 | 
					const handleMoveChanged = (result: DualSelectMoveSelectedEvent) => {
 | 
				
			||||||
    const target = document.querySelector("#action-button-message-pad");
 | 
					    const target = document.querySelector("#action-button-message-pad");
 | 
				
			||||||
    target!.innerHTML = "";
 | 
					    target!.innerHTML = "";
 | 
				
			||||||
    result.detail.forEach((key: string) => {
 | 
					    result.keys.forEach((key: string) => {
 | 
				
			||||||
        target!.append(new DOMParser().parseFromString(`<li>${key}</li>`, "text/xml").firstChild!);
 | 
					        target!.append(new DOMParser().parseFromString(`<li>${key}</li>`, "text/xml").firstChild!);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
window.addEventListener("ak-dual-select-selected-move-changed", handleMoveChanged);
 | 
					window.addEventListener(DualSelectMoveSelectedEvent.eventName, handleMoveChanged);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Story = StoryObj;
 | 
					type Story = StoryObj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@ import { TemplateResult, html } from "lit";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import "../components/ak-pagination";
 | 
					import "../components/ak-pagination";
 | 
				
			||||||
import { AkPagination } from "../components/ak-pagination";
 | 
					import { AkPagination } from "../components/ak-pagination";
 | 
				
			||||||
 | 
					import { DualSelectPaginatorNavEvent } from "../events";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const metadata: Meta<AkPagination> = {
 | 
					const metadata: Meta<AkPagination> = {
 | 
				
			||||||
    title: "Elements / Dual Select / Pagination Control",
 | 
					    title: "Elements / Dual Select / Pagination Control",
 | 
				
			||||||
@ -43,18 +44,18 @@ const container = (testItem: TemplateResult) =>
 | 
				
			|||||||
    </div>`;
 | 
					    </div>`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
					// eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
				
			||||||
const handleMoveChanged = (result: any) => {
 | 
					const handleMoveChanged = (result: DualSelectPaginatorNavEvent) => {
 | 
				
			||||||
    console.debug(result);
 | 
					    console.debug(result);
 | 
				
			||||||
    const target = document.querySelector("#action-button-message-pad");
 | 
					    const target = document.querySelector("#action-button-message-pad");
 | 
				
			||||||
    target!.append(
 | 
					    target!.append(
 | 
				
			||||||
        new DOMParser().parseFromString(
 | 
					        new DOMParser().parseFromString(
 | 
				
			||||||
            `<li>Request to move to page ${result.detail}</li>`,
 | 
					            `<li>Request to move to page ${result.page}</li>`,
 | 
				
			||||||
            "text/xml",
 | 
					            "text/xml",
 | 
				
			||||||
        ).firstChild!,
 | 
					        ).firstChild!,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
window.addEventListener("ak-pagination-nav-to", handleMoveChanged);
 | 
					window.addEventListener(DualSelectPaginatorNavEvent.eventName, handleMoveChanged);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Story = StoryObj;
 | 
					type Story = StoryObj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -29,10 +29,3 @@ export type DataProvision = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type DataProvider = (page: number, search?: string) => Promise<DataProvision>;
 | 
					export type DataProvider = (page: number, search?: string) => Promise<DataProvision>;
 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface SearchbarEvent extends CustomEvent {
 | 
					 | 
				
			||||||
    detail: {
 | 
					 | 
				
			||||||
        source: string;
 | 
					 | 
				
			||||||
        value: string;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user