Files
authentik/web/src/components/ak-multi-select.ts
Ken Sternberg 79c01ca473 web: update to ESLint 9 (#10812)
* web: update to ESLint 9

ESLint 9 has been out for awhile now, and all of the plug-ins that we use have caught up, so it is
time to bite the bullet and upgrade.  This commit:

- upgrades to ESLint 9, and upgrades all associated plugins
- Replaces the `.eslintrc` and `.eslintignore` files with the new, "flat" configuration file,
  "eslint.config.mjs".
- Places the previous "precommit" and "nightmare" rules in `./scripts/eslint.precommit.mjs` and
  `./scripts/eslint.nightmare.mjs`, respectively
- Replaces the scripted wrappers for eslint (`eslint`, `eslint-precommit`) with a single executable
  that takes the arguments `--precommit`, which applies a stricter set of rules, and `--nightmare`,
  which applies an even more terrifyingly strict set of rules.
- Provides the scripted wrapper `./scripts/eslint.mjs` so that eslint can be run from `bun`, if one
  so chooses.
- Fixes *all* of the lint `eslint.config.mjs` now finds, including removing all of the `eslint`
  styling rules and overrides because Eslint now proudly leaves that entirely up to Prettier.

To shut Dependabot up about ESLint.

* Added explanation for no-console removal.

* web: did not need the old and unmaintained nightmare mode; it can be configured directly.
2024-08-07 15:04:18 -07:00

157 lines
4.4 KiB
TypeScript

import { AkControlElement } from "@goauthentik/elements/AkControlElement.js";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { TemplateResult, css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import { map } from "lit/directives/map.js";
import { Ref, createRef, ref } from "lit/directives/ref.js";
import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
type Pair = [string, string];
const selectStyles = css`
select[multiple] {
min-height: 15rem;
}
`;
/**
* Horizontal layout control with a multi-select.
*
* @part select - The select itself, to override the height specified above.
*/
@customElement("ak-multi-select")
export class AkMultiSelect extends AkControlElement {
static get styles() {
return [PFBase, PFForm, PFFormControl, selectStyles];
}
/**
* The [name] attribute, which is also distributed to the layout manager and the input control.
*/
@property({ type: String })
name!: string;
/**
* The text label to display on the control
*/
@property({ type: String })
label = "";
/**
* The values to be displayed in the select. The format is [Value, Label], where the label is
* what will be displayed.
*/
@property({ attribute: false })
options: Pair[] = [];
/**
* If true, at least one object must be selected
*/
@property({ type: Boolean })
required = false;
/**
* Supporting a simple help string
*/
@property({ type: String })
help = "";
/**
* For more complex help instructions, provide a template result.
*/
@property({ type: Object })
bighelp!: TemplateResult | TemplateResult[];
/**
* An array of strings representing the objects currently selected.
*/
@property({ type: Array })
values: string[] = [];
/**
* Helper accessor for older code
*/
get value() {
return this.values;
}
/**
* One of two criteria (the other being the data-ak-control flag) that specifies this as a
* control that produces values of specific interest to our REST API. This is our modern
* accessor name.
*/
json() {
return this.values;
}
connectedCallback() {
super.connectedCallback();
this.dataset.akControl = "true";
}
renderHelp() {
return [
this.help ? html`<p class="pf-c-form__helper-text">${this.help}</p>` : nothing,
this.bighelp ? this.bighelp : nothing,
];
}
handleChange(ev: Event) {
if (ev.type === "change") {
this.values = Array.from(this.selectRef.value!.querySelectorAll("option"))
.filter((option) => option.selected)
.map((option) => option.value);
this.dispatchEvent(
new CustomEvent("ak-select", {
detail: this.values,
composed: true,
bubbles: true,
}),
);
}
}
selectRef: Ref<HTMLSelectElement> = createRef();
render() {
return html` <div class="pf-c-form">
<ak-form-element-horizontal
label=${this.label}
?required=${this.required}
name=${this.name}
>
<select
part="select"
class="pf-c-form-control"
name=${ifDefined(this.name)}
multiple
${ref(this.selectRef)}
@change=${this.handleChange}
>
${map(
this.options,
([value, label]) =>
html`<option value=${value} ?selected=${this.values.includes(value)}>
${label}
</option>`,
)}
</select>
${this.renderHelp()}
</ak-form-element-horizontal>
</div>`;
}
}
export default AkMultiSelect;
declare global {
interface HTMLElementTagNameMap {
"ak-multi-select": AkMultiSelect;
}
}