web: provide a "select / select all" tool for the dual list multiselect
**This commit** Provides one of several of the sub-controls needed to make the multi-list multi-select thing work. This is the simplest control, and I decided to go with it first because it's all presentation; all it does is show the buttons and send events from those buttons. A Storybook component is provided to show how well it works.
This commit is contained in:
parent
6fb543b94f
commit
1cba9e88cb
|
@ -0,0 +1,101 @@
|
|||
import "@goauthentik/elements/messages/MessageContainer";
|
||||
import { Meta, StoryObj } from "@storybook/web-components";
|
||||
|
||||
import { TemplateResult, html } from "lit";
|
||||
|
||||
import "./ak-dual-select-controls";
|
||||
import { AkDualSelectControls } from "./ak-dual-select-controls";
|
||||
|
||||
const metadata: Meta<AkDualSelectControls> = {
|
||||
title: "Elements / Dual Select / Control Panel",
|
||||
component: "ak-dual-select-controls",
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component: "The vertical panel separating two dual-select elements.",
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
addActive: {
|
||||
type: "boolean",
|
||||
description:
|
||||
"Highlighted if the sample panel has something to move to the result panel.",
|
||||
},
|
||||
removeActive: {
|
||||
type: "boolean",
|
||||
description:
|
||||
"Highlighted if the result panel has something to move to the sample panel.",
|
||||
},
|
||||
selectAll: {
|
||||
type: "boolean",
|
||||
description: "Enable if you want both the 'move all visible' buttons.",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default metadata;
|
||||
|
||||
const container = (testItem: TemplateResult) =>
|
||||
html` <div style="background: #fff; padding: 2em">
|
||||
<style>
|
||||
li {
|
||||
display: block;
|
||||
}
|
||||
p {
|
||||
margin-top: 1em;
|
||||
}
|
||||
</style>
|
||||
<ak-message-container></ak-message-container>
|
||||
${testItem}
|
||||
<p>Messages received from the button:</p>
|
||||
<ul id="action-button-message-pad" style="margin-top: 1em"></ul>
|
||||
</div>`;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const displayMessage = (result: any) => {
|
||||
const doc = new DOMParser().parseFromString(`<li><i>Event</i>: ${result}</li>`, "text/xml");
|
||||
const target = document.querySelector("#action-button-message-pad");
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
target!.appendChild(doc.firstChild!);
|
||||
};
|
||||
|
||||
window.addEventListener("ak-dual-select-add", () => displayMessage("add"));
|
||||
window.addEventListener("ak-dual-select-remove", () => displayMessage("remove"));
|
||||
window.addEventListener("ak-dual-select-add-all", () => displayMessage("add all"));
|
||||
window.addEventListener("ak-dual-select-remove-all", () => displayMessage("remove all"));
|
||||
|
||||
type Story = StoryObj;
|
||||
|
||||
export const Default: Story = {
|
||||
render: () => container(html` <ak-dual-select-controls></ak-dual-select-controls>`),
|
||||
};
|
||||
|
||||
export const AddActive: Story = {
|
||||
render: () => container(html` <ak-dual-select-controls add-active></ak-dual-select-controls>`),
|
||||
};
|
||||
|
||||
export const RemoveActive: Story = {
|
||||
render: () =>
|
||||
container(html` <ak-dual-select-controls remove-active></ak-dual-select-controls>`),
|
||||
};
|
||||
|
||||
export const AddAllActive: Story = {
|
||||
render: () =>
|
||||
container(
|
||||
html` <ak-dual-select-controls
|
||||
enable-select-all
|
||||
add-all-active
|
||||
></ak-dual-select-controls>`,
|
||||
),
|
||||
};
|
||||
|
||||
export const RemoveAllActive: Story = {
|
||||
render: () =>
|
||||
container(
|
||||
html` <ak-dual-select-controls
|
||||
enable-select-all
|
||||
remove-all-active
|
||||
></ak-dual-select-controls>`,
|
||||
),
|
||||
};
|
84
web/src/elements/ak-dual-select/ak-dual-select-controls.ts
Normal file
84
web/src/elements/ak-dual-select/ak-dual-select-controls.ts
Normal file
|
@ -0,0 +1,84 @@
|
|||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { html, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
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];
|
||||
|
||||
@customElement("ak-dual-select-controls")
|
||||
export class AkDualSelectControls extends CustomEmitterElement(AKElement) {
|
||||
static get styles() {
|
||||
return styles;
|
||||
}
|
||||
|
||||
@property({ attribute: "add-active", type: Boolean })
|
||||
addActive = false;
|
||||
|
||||
@property({ attribute: "remove-active", type: Boolean })
|
||||
removeActive = false;
|
||||
|
||||
@property({ attribute: "add-all-active", type: Boolean })
|
||||
addAllActive = false;
|
||||
|
||||
@property({ attribute: "remove-all-active", type: Boolean })
|
||||
removeAllActive = false;
|
||||
|
||||
@property({ attribute: "disabled", type: Boolean })
|
||||
disabled = false;
|
||||
|
||||
@property({ attribute: "enable-select-all", type: Boolean })
|
||||
selectAll = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.onClick = this.onClick.bind(this);
|
||||
}
|
||||
|
||||
onClick(eventName: string) {
|
||||
this.dispatchCustomEvent(eventName);
|
||||
}
|
||||
|
||||
renderButton(label: string, event: string, active: boolean, direction: string) {
|
||||
return html`
|
||||
<div class="pf-c-dual-list-selector__controls-item">
|
||||
<button
|
||||
?aria-disabled=${this.disabled || !active}
|
||||
?disabled=${this.disabled || !active}
|
||||
aria-label=${label}
|
||||
class="pf-c-button pf-m-plain"
|
||||
type="button"
|
||||
@click=${() => this.onClick(event)}
|
||||
data-ouia-component-type="AK/Button"
|
||||
>
|
||||
<i class="fa ${direction}"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
render() {
|
||||
// prettier-ignore
|
||||
return html`
|
||||
<div class="pf-c-dual-list-selector">
|
||||
<div class="pf-c-dual-list-selector__controls">
|
||||
${this.renderButton(msg("Add"), "ak-dual-select-add", this.addActive, "fa-angle-right")}
|
||||
${this.selectAll
|
||||
? html`
|
||||
${this.renderButton(msg("Add All"), "ak-dual-select-add-all", this.addAllActive, "fa-angle-double-right")}
|
||||
${this.renderButton(msg("Remove All"), "ak-dual-select-remove-all", this.removeAllActive, "fa-angle-double-left")}
|
||||
`
|
||||
: nothing}
|
||||
${this.renderButton(msg("Remove"), "ak-dual-select-remove", this.removeActive, "fa-angle-left")}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
export default AkDualSelectControls;
|
Reference in a new issue