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:
@ -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"
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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, {
|
||||
|
@ -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.
|
||||
|
136
web/src/admin/common/ak-flow-search/ak-flow-search.stories.ts
Normal file
136
web/src/admin/common/ak-flow-search/ak-flow-search.stories.ts
Normal 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>`,
|
||||
);
|
145
web/src/components/stories/ak-search-select.stories.ts
Normal file
145
web/src/components/stories/ak-search-select.stories.ts
Normal 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>`,
|
||||
);
|
||||
};
|
@ -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;
|
||||
|
Reference in New Issue
Block a user