web: bad default in select (#8258)

* web: fix event propogation in search-select wrappers

Two different patches, an older one that extracted long search
blocks that were cut-and-pasted into a standalone component, and a
newer one that fixed displaying placeholder values properly,
conflicted and broke a relationship that allowed for the values to
be propagated through those standalone components correctly.

This restores the event handling and updates the listener set-ups
with more idiomatic hooks into Lit's event system.

* Updated search-select to properly render with Storybook, and provided a
foundation for testing the Search-Select component with Storybook.

* Accidentally deleted this line while making Sonar accept my test data.

* Fixing a small issue that's bugged me for awhile: there's no reason to manually duplicate what code can duplicate.

* Provided a storybook for testing out the flow search.

Discovered along the way that I'd mis-used a prop-drilling technique which caused the currentFlow
to be "undefined" when pass forward, giving rise to Marc's bug.

I *think* this shakes out the last of the bugs.  Events are passed up correctly and the initial value
is recorded correctly.

* Added comments and prettier had opinions.

* Restoring old variable names; they didn't have to change after all.

* fix lint

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Ken Sternberg
2024-01-23 08:54:34 -08:00
committed by GitHub
parent 862aece9fc
commit 830689f1cb
7 changed files with 371 additions and 127 deletions

View File

@ -24,6 +24,7 @@
"semi": ["error", "always"],
"@typescript-eslint/ban-ts-comment": "off",
"sonarjs/cognitive-complexity": ["error", 9],
"sonarjs/no-duplicate-string": "off",
"sonarjs/no-nested-template-literals": "off"
}
}

View File

@ -7,123 +7,72 @@
// Sometime around 2030 or so, the Javascript community may finally get its collective act together
// and we'll have one unified way of doing this. I can only hope.
export const cssImportMaps = {
'import AKGlobal from "@goauthentik/common/styles/authentik.css";':
'import AKGlobal from "@goauthentik/common/styles/authentik.css?inline";',
'import PFAlert from "@patternfly/patternfly/components/Alert/alert.css";':
'import PFAlert from "@patternfly/patternfly/components/Alert/alert.css?inline";',
'import PFAlertGroup from "@patternfly/patternfly/components/AlertGroup/alert-group.css";':
'import PFAlertGroup from "@patternfly/patternfly/components/AlertGroup/alert-group.css?inline";',
'import PFAvatar from "@patternfly/patternfly/components/Avatar/avatar.css";':
'import PFAvatar from "@patternfly/patternfly/components/Avatar/avatar.css?inline";',
'import PFBackdrop from "@patternfly/patternfly/components/Backdrop/backdrop.css";':
'import PFBackdrop from "@patternfly/patternfly/components/Backdrop/backdrop.css?inline";',
'import PFBackgroundImage from "@patternfly/patternfly/components/BackgroundImage/background-image.css";':
'import PFBackgroundImage from "@patternfly/patternfly/components/BackgroundImage/background-image.css?inline";',
'import PFBanner from "@patternfly/patternfly/components/Banner/banner.css";':
'import PFBanner from "@patternfly/patternfly/components/Banner/banner.css?inline";',
'import PFBase from "@patternfly/patternfly/patternfly-base.css";':
'import PFBase from "@patternfly/patternfly/patternfly-base.css?inline";',
'import PFBrand from "@patternfly/patternfly/components/Brand/brand.css";':
'import PFBrand from "@patternfly/patternfly/components/Brand/brand.css?inline";',
'import PFBullseye from "@patternfly/patternfly/layouts/Bullseye/bullseye.css";':
'import PFBullseye from "@patternfly/patternfly/layouts/Bullseye/bullseye.css?inline";',
'import PFButton from "@patternfly/patternfly/components/Button/button.css";':
'import PFButton from "@patternfly/patternfly/components/Button/button.css?inline";',
'import PFCard from "@patternfly/patternfly/components/Card/card.css";':
'import PFCard from "@patternfly/patternfly/components/Card/card.css?inline";',
'import PFCheck from "@patternfly/patternfly/components/Check/check.css";':
'import PFCheck from "@patternfly/patternfly/components/Check/check.css?inline";',
'import PFChip from "@patternfly/patternfly/components/Chip/chip.css";':
'import PFChip from "@patternfly/patternfly/components/Chip/chip.css?inline";',
'import PFChipGroup from "@patternfly/patternfly/components/ChipGroup/chip-group.css";':
'import PFChipGroup from "@patternfly/patternfly/components/ChipGroup/chip-group.css?inline";',
'import PFContent from "@patternfly/patternfly/components/Content/content.css";':
'import PFContent from "@patternfly/patternfly/components/Content/content.css?inline";',
'import PFDataList from "@patternfly/patternfly/components/DataList/data-list.css";':
'import PFDataList from "@patternfly/patternfly/components/DataList/data-list.css?inline";',
'import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";':
'import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css?inline";',
'import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css";':
'import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css?inline";',
'import PFDrawer from "@patternfly/patternfly/components/Drawer/drawer.css";':
'import PFDrawer from "@patternfly/patternfly/components/Drawer/drawer.css?inline";',
'import PFDropdown from "@patternfly/patternfly/components/Dropdown/dropdown.css";':
'import PFDropdown from "@patternfly/patternfly/components/Dropdown/dropdown.css?inline";',
'import PFEmptyState from "@patternfly/patternfly/components/EmptyState/empty-state.css";':
'import PFEmptyState from "@patternfly/patternfly/components/EmptyState/empty-state.css?inline";',
'import PFExpandableSection from "@patternfly/patternfly/components/ExpandableSection/expandable-section.css";':
'import PFExpandableSection from "@patternfly/patternfly/components/ExpandableSection/expandable-section.css?inline";',
'import PFFAIcons from "@patternfly/patternfly/base/patternfly-fa-icons.css";':
'import PFFAIcons from "@patternfly/patternfly/base/patternfly-fa-icons.css?inline";',
'import PFFlex from "@patternfly/patternfly/layouts/Flex/flex.css";':
'import PFFlex from "@patternfly/patternfly/layouts/Flex/flex.css?inline";',
'import PFForm from "@patternfly/patternfly/components/Form/form.css";':
'import PFForm from "@patternfly/patternfly/components/Form/form.css?inline";',
'import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";':
'import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css?inline";',
'import PFGallery from "@patternfly/patternfly/layouts/Gallery/gallery.css";':
'import PFGallery from "@patternfly/patternfly/layouts/Gallery/gallery.css?inline";',
'import PFGlobal from "@patternfly/patternfly/patternfly-base.css";':
'import PFGlobal from "@patternfly/patternfly/patternfly-base.css?inline";',
'import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css";':
'import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css?inline";',
'import PFHint from "@patternfly/patternfly/components/Hint/hint.css";':
'import PFHint from "@patternfly/patternfly/components/Hint/hint.css?inline";',
'import PFInputGroup from "@patternfly/patternfly/components/InputGroup/input-group.css";':
'import PFInputGroup from "@patternfly/patternfly/components/InputGroup/input-group.css?inline";',
'import PFLabel from "@patternfly/patternfly/components/Label/label.css";':
'import PFLabel from "@patternfly/patternfly/components/Label/label.css?inline";',
'import PFList from "@patternfly/patternfly/components/List/list.css";':
'import PFList from "@patternfly/patternfly/components/List/list.css?inline";',
'import PFLogin from "@patternfly/patternfly/components/Login/login.css";':
'import PFLogin from "@patternfly/patternfly/components/Login/login.css?inline";',
'import PFModalBox from "@patternfly/patternfly/components/ModalBox/modal-box.css";':
'import PFModalBox from "@patternfly/patternfly/components/ModalBox/modal-box.css?inline";',
'import PFNav from "@patternfly/patternfly/components/Nav/nav.css";':
'import PFNav from "@patternfly/patternfly/components/Nav/nav.css?inline";',
'import PFNotificationBadge from "@patternfly/patternfly/components/NotificationBadge/notification-badge.css";':
'import PFNotificationBadge from "@patternfly/patternfly/components/NotificationBadge/notification-badge.css?inline";',
'import PFNotificationDrawer from "@patternfly/patternfly/components/NotificationDrawer/notification-drawer.css";':
'import PFNotificationDrawer from "@patternfly/patternfly/components/NotificationDrawer/notification-drawer.css?inline";',
'import PFPage from "@patternfly/patternfly/components/Page/page.css";':
'import PFPage from "@patternfly/patternfly/components/Page/page.css?inline";',
'import PFPagination from "@patternfly/patternfly/components/Pagination/pagination.css";':
'import PFPagination from "@patternfly/patternfly/components/Pagination/pagination.css?inline";',
'import PFProgressStepper from "@patternfly/patternfly/components/ProgressStepper/progress-stepper.css";':
'import PFProgressStepper from "@patternfly/patternfly/components/ProgressStepper/progress-stepper.css?inline";',
'import PFRadio from "@patternfly/patternfly/components/Radio/radio.css";':
'import PFRadio from "@patternfly/patternfly/components/Radio/radio.css?inline";',
'import PFSelect from "@patternfly/patternfly/components/Select/select.css";':
'import PFSelect from "@patternfly/patternfly/components/Select/select.css?inline";',
'import PFSidebar from "@patternfly/patternfly/components/Sidebar/sidebar.css";':
'import PFSidebar from "@patternfly/patternfly/components/Sidebar/sidebar.css?inline";',
'import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css";':
'import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css?inline";',
'import PFSpacing from "@patternfly/patternfly/utilities/Spacing/spacing.css";':
'import PFSpacing from "@patternfly/patternfly/utilities/Spacing/spacing.css?inline";',
'import PFSpinner from "@patternfly/patternfly/components/Spinner/spinner.css";':
'import PFSpinner from "@patternfly/patternfly/components/Spinner/spinner.css?inline";',
'import PFStack from "@patternfly/patternfly/layouts/Stack/stack.css";':
'import PFStack from "@patternfly/patternfly/layouts/Stack/stack.css?inline";',
'import PFSwitch from "@patternfly/patternfly/components/Switch/switch.css";':
'import PFSwitch from "@patternfly/patternfly/components/Switch/switch.css?inline";',
'import PFTable from "@patternfly/patternfly/components/Table/table.css";':
'import PFTable from "@patternfly/patternfly/components/Table/table.css?inline";',
'import PFTabs from "@patternfly/patternfly/components/Tabs/tabs.css";':
'import PFTabs from "@patternfly/patternfly/components/Tabs/tabs.css?inline";',
'import PFTitle from "@patternfly/patternfly/components/Title/title.css";':
'import PFTitle from "@patternfly/patternfly/components/Title/title.css?inline";',
'import PFToggleGroup from "@patternfly/patternfly/components/ToggleGroup/toggle-group.css";':
'import PFToggleGroup from "@patternfly/patternfly/components/ToggleGroup/toggle-group.css?inline";',
'import PFToolbar from "@patternfly/patternfly/components/Toolbar/toolbar.css";':
'import PFToolbar from "@patternfly/patternfly/components/Toolbar/toolbar.css?inline";',
'import PFTreeView from "@patternfly/patternfly/components/TreeView/tree-view.css";':
'import PFTreeView from "@patternfly/patternfly/components/TreeView/tree-view.css?inline";',
'import PFWizard from "@patternfly/patternfly/components/Wizard/wizard.css";':
'import PFWizard from "@patternfly/patternfly/components/Wizard/wizard.css?inline";',
'import ThemeDark from "@goauthentik/common/styles/theme-dark.css";':
'import ThemeDark from "@goauthentik/common/styles/theme-dark.css?inline";',
'import styles from "./LibraryPageImpl.css";':
'import styles from "./LibraryPageImpl.css?inline";',
};
const rawCssImportMaps = [
'import AKGlobal from "@goauthentik/common/styles/authentik.css";',
'import PFAlert from "@patternfly/patternfly/components/Alert/alert.css";',
'import PFAlertGroup from "@patternfly/patternfly/components/AlertGroup/alert-group.css";',
'import PFAvatar from "@patternfly/patternfly/components/Avatar/avatar.css";',
'import PFBackdrop from "@patternfly/patternfly/components/Backdrop/backdrop.css";',
'import PFBackgroundImage from "@patternfly/patternfly/components/BackgroundImage/background-image.css";',
'import PFBanner from "@patternfly/patternfly/components/Banner/banner.css";',
'import PFBase from "@patternfly/patternfly/patternfly-base.css";',
'import PFBrand from "@patternfly/patternfly/components/Brand/brand.css";',
'import PFBullseye from "@patternfly/patternfly/layouts/Bullseye/bullseye.css";',
'import PFButton from "@patternfly/patternfly/components/Button/button.css";',
'import PFCard from "@patternfly/patternfly/components/Card/card.css";',
'import PFCheck from "@patternfly/patternfly/components/Check/check.css";',
'import PFChip from "@patternfly/patternfly/components/Chip/chip.css";',
'import PFChipGroup from "@patternfly/patternfly/components/ChipGroup/chip-group.css";',
'import PFContent from "@patternfly/patternfly/components/Content/content.css";',
'import PFDataList from "@patternfly/patternfly/components/DataList/data-list.css";',
'import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";',
'import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css";',
'import PFDrawer from "@patternfly/patternfly/components/Drawer/drawer.css";',
'import PFDropdown from "@patternfly/patternfly/components/Dropdown/dropdown.css";',
'import PFEmptyState from "@patternfly/patternfly/components/EmptyState/empty-state.css";',
'import PFExpandableSection from "@patternfly/patternfly/components/ExpandableSection/expandable-section.css";',
'import PFFAIcons from "@patternfly/patternfly/base/patternfly-fa-icons.css";',
'import PFFlex from "@patternfly/patternfly/layouts/Flex/flex.css";',
'import PFForm from "@patternfly/patternfly/components/Form/form.css";',
'import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";',
'import PFGallery from "@patternfly/patternfly/layouts/Gallery/gallery.css";',
'import PFGlobal from "@patternfly/patternfly/patternfly-base.css";',
'import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css";',
'import PFHint from "@patternfly/patternfly/components/Hint/hint.css";',
'import PFInputGroup from "@patternfly/patternfly/components/InputGroup/input-group.css";',
'import PFLabel from "@patternfly/patternfly/components/Label/label.css";',
'import PFList from "@patternfly/patternfly/components/List/list.css";',
'import PFLogin from "@patternfly/patternfly/components/Login/login.css";',
'import PFModalBox from "@patternfly/patternfly/components/ModalBox/modal-box.css";',
'import PFNav from "@patternfly/patternfly/components/Nav/nav.css";',
'import PFNotificationBadge from "@patternfly/patternfly/components/NotificationBadge/notification-badge.css";',
'import PFNotificationDrawer from "@patternfly/patternfly/components/NotificationDrawer/notification-drawer.css";',
'import PFPage from "@patternfly/patternfly/components/Page/page.css";',
'import PFPagination from "@patternfly/patternfly/components/Pagination/pagination.css";',
'import PFProgressStepper from "@patternfly/patternfly/components/ProgressStepper/progress-stepper.css";',
'import PFRadio from "@patternfly/patternfly/components/Radio/radio.css";',
'import PFSelect from "@patternfly/patternfly/components/Select/select.css";',
'import PFSidebar from "@patternfly/patternfly/components/Sidebar/sidebar.css";',
'import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css";',
'import PFSpacing from "@patternfly/patternfly/utilities/Spacing/spacing.css";',
'import PFSpinner from "@patternfly/patternfly/components/Spinner/spinner.css";',
'import PFStack from "@patternfly/patternfly/layouts/Stack/stack.css";',
'import PFSwitch from "@patternfly/patternfly/components/Switch/switch.css";',
'import PFTable from "@patternfly/patternfly/components/Table/table.css";',
'import PFTabs from "@patternfly/patternfly/components/Tabs/tabs.css";',
'import PFTitle from "@patternfly/patternfly/components/Title/title.css";',
'import PFToggleGroup from "@patternfly/patternfly/components/ToggleGroup/toggle-group.css";',
'import PFToolbar from "@patternfly/patternfly/components/Toolbar/toolbar.css";',
'import PFTreeView from "@patternfly/patternfly/components/TreeView/tree-view.css";',
'import PFWizard from "@patternfly/patternfly/components/Wizard/wizard.css";',
'import ThemeDark from "@goauthentik/common/styles/theme-dark.css";',
'import styles from "./LibraryPageImpl.css";',
];
const cssImportMaps = rawCssImportMaps.reduce(
(acc, line) => ({ ...acc, [line]: line.replace(/\.css/, ".css?inline") }),
{},
);
export { cssImportMaps };
export default cssImportMaps;

View File

@ -39,7 +39,7 @@ function createOneImportLine(line: string) {
if (!importContent) {
throw new Error("How did an unmatchable line get here!?");
}
return `'${importContent}";': '${importContent}?inline";',`;
return ` '${importContent}";',`;
}
const isSourceFile = /\.ts$/;
@ -73,9 +73,15 @@ const outputFile = `
// Sometime around 2030 or so, the Javascript community may finally get its collective act together
// and we'll have one unified way of doing this. I can only hope.
export const cssImportMaps = {
const rawCssImportMaps = [
${importLines.map(createOneImportLine).join("\n")}
};
];
const cssImportMaps = rawCssImportMaps.reduce((acc, line) => (
{...acc, [line]: line.replace(/\\.css/, ".css?inline")}), {});
export { cssImportMaps };
export default cssImportMaps;
`;
fs.writeFileSync(path.join(__dirname, "..", ".storybook", "css-import-maps.ts"), outputFile, {

View File

@ -46,8 +46,8 @@ export class FlowSearch<T extends Flow> extends CustomListenerElement(AKElement)
*
* @attr
*/
@property({ attribute: false })
currentFlow: string | undefined;
@property({ type: String })
currentFlow?: string | undefined;
/**
* If true, it is not valid to leave the flow blank.

View File

@ -0,0 +1,136 @@
import "@goauthentik/admin/common/ak-flow-search/ak-flow-search";
import { AkFlowSearch } from "@goauthentik/admin/common/ak-flow-search/ak-flow-search";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { Meta } from "@storybook/web-components";
import { msg } from "@lit/localize";
import { TemplateResult, html } from "lit";
import { Flow, FlowsInstancesListDesignationEnum } from "@goauthentik/api";
const mockData = {
pagination: {
next: 0,
previous: 0,
count: 2,
current: 1,
total_pages: 1,
start_index: 1,
end_index: 2,
},
results: [
{
pk: "41468774-bef6-4ffb-b675-332d0d8c5d25",
policybindingmodel_ptr_id: "0fb5b872-2734-44bd-ac7e-f23051481a83",
name: "Authorize Application",
slug: "default-provider-authorization-explicit-consent",
title: "Redirecting to %(app)s",
designation: "authorization",
background: "/static/dist/assets/images/flow_background.jpg",
stages: ["8adcdc74-0d3d-48a8-b628-38e3da4081e5"],
policies: [],
cache_count: 0,
policy_engine_mode: "any",
compatibility_mode: false,
export_url:
"/api/v3/flows/instances/default-provider-authorization-explicit-consent/export/",
layout: "stacked",
denied_action: "message_continue",
authentication: "require_authenticated",
},
{
pk: "89f57fd8-fd1e-42be-a5fd-abc13b19529b",
policybindingmodel_ptr_id: "e8526408-c6ee-46e1-bbfe-a1d37c2c02c8",
name: "Authorize Application",
slug: "default-provider-authorization-implicit-consent",
title: "Redirecting to %(app)s",
designation: "authorization",
background: "/static/dist/assets/images/flow_background.jpg",
stages: [],
policies: [],
cache_count: 0,
policy_engine_mode: "any",
compatibility_mode: false,
export_url:
"/api/v3/flows/instances/default-provider-authorization-implicit-consent/export/",
layout: "stacked",
denied_action: "message_continue",
authentication: "require_authenticated",
},
],
};
const metadata: Meta<AkFlowSearch<Flow>> = {
title: "Elements / Select Search / Flow",
component: "ak-flow-search",
parameters: {
docs: {
description: {
component: "A Select Search for Authentication Flows",
},
},
mockData: [
{
url: `${window.location.origin}/api/v3/flows/instances/?designation=authorization&ordering=slug`,
method: "GET",
status: 200,
response: () => mockData,
},
],
},
};
export default metadata;
const container = (testItem: TemplateResult) => {
return html` <div style="background: #fff; padding: 1.0rem;">
<style>
li {
display: block;
}
p {
margin-top: 1em;
}
</style>
${testItem}
<ul id="message-pad" style="margin-top: 1em; min-height: 5em;"></ul>
</div>`;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const displayChange = (ev: any) => {
document.getElementById("message-pad")!.innerText = `Value selected: ${JSON.stringify(
ev.target.value,
null,
2,
)}`;
};
export const Default = () =>
container(
html` <ak-form-element-horizontal
label=${msg("Authorization flow")}
?required=${true}
name="authorizationFlow"
>
<ak-flow-search
flowType=${FlowsInstancesListDesignationEnum.Authorization}
@input=${displayChange}
></ak-flow-search
></ak-form-element-horizontal>`,
);
export const WithInitialValue = () =>
container(
html` <ak-form-element-horizontal
label=${msg("Authorization flow")}
?required=${true}
name="authorizationFlow"
>
<ak-flow-search
flowType=${FlowsInstancesListDesignationEnum.Authorization}
currentFlow="89f57fd8-fd1e-42be-a5fd-abc13b19529b"
@input=${displayChange}
></ak-flow-search
></ak-form-element-horizontal>`,
);

View File

@ -0,0 +1,145 @@
import { groupBy } from "@goauthentik/app/common/utils";
import { convertToSlug as slugify } from "@goauthentik/common/utils.js";
import "@goauthentik/elements/forms/SearchSelect/ak-search-select";
import { SearchSelect } from "@goauthentik/elements/forms/SearchSelect/ak-search-select";
import { Meta } from "@storybook/web-components";
import { TemplateResult, html } from "lit";
type RawSample = [string, string[]];
type Sample = { name: string; pk: string; season: string[] };
// prettier-ignore
const groupedSamples: RawSample[] = [
["Spring", [
"Apples", "Apricots", "Asparagus", "Avocados", "Bananas", "Broccoli",
"Cabbage", "Carrots", "Celery", "Collard Greens", "Garlic", "Herbs", "Kale", "Kiwifruit", "Lemons",
"Lettuce", "Limes", "Mushrooms", "Onions", "Peas", "Pineapples", "Radishes", "Rhubarb", "Spinach",
"Strawberries", "Swiss Chard", "Turnips"]],
["Summer", [
"Apples", "Apricots", "Avocados", "Bananas", "Beets", "Bell Peppers", "Blackberries", "Blueberries",
"Cantaloupe", "Carrots", "Celery", "Cherries", "Corn", "Cucumbers", "Eggplant", "Garlic",
"Green Beans", "Herbs", "Honeydew Melon", "Lemons", "Lima Beans", "Limes", "Mangos", "Okra", "Peaches",
"Plums", "Raspberries", "Strawberries", "Summer Squash", "Tomatillos", "Tomatoes", "Watermelon",
"Zucchini"]],
["Fall", [
"Apples", "Bananas", "Beets", "Bell Peppers", "Broccoli", "Brussels Sprouts", "Cabbage", "Carrots",
"Cauliflower", "Celery", "Collard Greens", "Cranberries", "Garlic", "Ginger", "Grapes", "Green Beans",
"Herbs", "Kale", "Kiwifruit", "Lemons", "Lettuce", "Limes", "Mangos", "Mushrooms", "Onions",
"Parsnips", "Pears", "Peas", "Pineapples", "Potatoes", "Pumpkin", "Radishes", "Raspberries",
"Rutabagas", "Spinach", "Sweet Potatoes", "Swiss Chard", "Turnips", "Winter Squash"]],
["Winter", [
"Apples", "Avocados", "Bananas", "Beets", "Brussels Sprouts", "Cabbage", "Carrots", "Celery",
"Collard Greens", "Grapefruit", "Herbs", "Kale", "Kiwifruit", "Leeks", "Lemons", "Limes", "Onions",
"Oranges", "Parsnips", "Pears", "Pineapples", "Potatoes", "Pumpkin", "Rutabagas",
"Sweet Potatoes", "Swiss Chard", "Turnips", "Winter Squash"]]
];
// WAAAAY too many lines to turn the arrays above into a Sample of
// { name: "Apricots", pk: "apple", season: ["Spring", "Summer"] }
// but it does the job.
const samples = Array.from(
groupedSamples
.reduce((acc, sample) => {
sample[1].forEach((item) => {
const update = (thing: Sample) => ({
...thing,
season: [...thing.season, sample[0]],
});
acc.set(
item,
update(acc.get(item) || { name: item, pk: slugify(item), season: [] }),
);
return acc;
}, acc);
return acc;
}, new Map<string, Sample>())
.values(),
);
samples.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
// All we need is a promise to return our dataset. It doesn't have to be a class-based method a'la
// the authentik API.
const getSamples = (query = "") =>
Promise.resolve(
samples.filter((s) =>
query !== "" ? s.name.toLowerCase().includes(query.toLowerCase()) : true,
),
);
const metadata: Meta<SearchSelect<Sample>> = {
title: "Elements / Search Select ",
component: "ak-search-select",
parameters: {
docs: {
description: {
component: "An implementation of the Patternfly search select pattern",
},
},
},
};
export default metadata;
const container = (testItem: TemplateResult) =>
html` <div style="background: #fff; padding: 2em">
<style>
li {
display: block;
}
p {
margin-top: 1em;
}
</style>
${testItem}
<ul id="message-pad" style="margin-top: 1em"></ul>
</div>`;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const displayChange = (ev: any) => {
document.getElementById("message-pad")!.innerText = `Value selected: ${JSON.stringify(
ev.detail.value,
null,
2,
)}`;
};
export const Default = () => {
return container(
html`<ak-search-select
.fetchObjects=${getSamples}
.renderElement=${(sample: Sample) => sample.name}
.value=${(sample: Sample) => sample.pk}
@ak-change=${displayChange}
></ak-search-select>`,
);
};
export const Grouped = () => {
return container(
html`<ak-search-select
.fetchObjects=${getSamples}
.renderElement=${(sample: Sample) => sample.name}
.value=${(sample: Sample) => sample.pk}
.groupBy=${(samples: Sample[]) =>
groupBy(samples, (sample: Sample) => sample.season[0] ?? "")}
@ak-change=${displayChange}
></ak-search-select>`,
);
};
export const Selected = () => {
return container(
html`<ak-search-select
.fetchObjects=${getSamples}
.renderElement=${(sample: Sample) => sample.name}
.value=${(sample: Sample) => sample.pk}
.selected=${(sample: Sample) => sample.pk === "herbs"}
@ak-change=${displayChange}
></ak-search-select>`,
);
};

View File

@ -3,6 +3,7 @@ import { PreventFormSubmit } from "@goauthentik/app/elements/forms/helpers";
import { EVENT_REFRESH } from "@goauthentik/common/constants";
import { ascii_letters, digits, groupBy, randomString } from "@goauthentik/common/utils";
import { AKElement } from "@goauthentik/elements/Base";
import { ensureCSSStyleSheet } from "@goauthentik/elements/utils/ensureCSSStyleSheet";
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
import { msg, str } from "@lit/localize";
@ -105,12 +106,17 @@ export class SearchSelect<T> extends CustomEmitterElement(AKElement) {
@state()
error?: APIErrorTypes;
static styles = [PFBase, PFForm, PFFormControl, PFSelect];
static get styles() {
return [PFBase, PFForm, PFFormControl, PFSelect];
}
constructor() {
super();
if (!document.adoptedStyleSheets.includes(PFDropdown)) {
document.adoptedStyleSheets = [...document.adoptedStyleSheets, PFDropdown];
document.adoptedStyleSheets = [
...document.adoptedStyleSheets,
ensureCSSStyleSheet(PFDropdown),
];
}
this.dropdownContainer = document.createElement("div");
this.observer = new IntersectionObserver(() => {
@ -150,6 +156,7 @@ export class SearchSelect<T> extends CustomEmitterElement(AKElement) {
objects.forEach((obj) => {
if (this.selected && this.selected(obj, objects || [])) {
this.selectedObject = obj;
this.dispatchCustomEvent("ak-change", { value: this.selectedObject });
}
});
this.objects = objects;