Refactored ObjectFilterDropdown into ViewBarFilterDropdown (#11794)

This PR refactors the non-generic part around ObjectFilterDropdown which
has been left in statu quo for months.

It also removes unused components. 

Overall this PR is doing renaming and it re-organizes files into their
relevant modules.

This clarifies a lot what's at the intersection between
object-filter-dropdown and views modules.

This PR was originally about removing any remaining useEffect around
ObjectFilterDropdown but there wasn't any.

## Details

### Removed unused files

- GenericEntityFilterChip
- SingleEntityObjectFilterDropdownButton (was used for the Task/Note
standalone page which doesn't exist anymore)

### Re-organized non-generic components into ViewBarFilterDropdown

- Use VIEW_BAR_FILTER_DROPDOWN_ID instead of OBJECT_FILTER_DROPDOWN_ID
- Use FILTER_FIELD_LIST_ID for selectable list
- Refactored ObjectFilterDropdownButton into a simple
ViewBarFilterDropdown
- Renamed MultipleFiltersDropdownContent to ViewBarFilterDropdownContent
- Renamed MultipleFiltersButton to ViewBarFilterButton
- Integrated MultipleFiltersDropdownButton to ViewBarFilterDropdown
- Renamed AdvancedFilterButton to ViewBarDetailsAddFilterButton

### Tests 

Fixed storybook test for ViewBarFilterDrodpown
This commit is contained in:
Lucas Bordeau
2025-04-29 18:05:12 +02:00
committed by GitHub
parent d8b2e1fb34
commit d52cb26599
19 changed files with 108 additions and 247 deletions

View File

@ -1,7 +1,6 @@
import { ReactNode } from 'react';
import { useParams } from 'react-router-dom';
import { ObjectFilterDropdownButton } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownButton';
import { ObjectSortDropdownButton } from '@/object-record/object-sort-dropdown/components/ObjectSortDropdownButton';
import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading';
@ -14,12 +13,15 @@ import { ViewPickerDropdown } from '@/views/view-picker/components/ViewPickerDro
import { ViewsHotkeyScope } from '../types/ViewsHotkeyScope';
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
import { VIEW_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/constants/ViewSortDropdownId';
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
import { ViewBarFilterDropdown } from '@/views/components/ViewBarFilterDropdown';
import { ViewBarRecordFilterEffect } from '@/views/components/ViewBarRecordFilterEffect';
import { ViewBarRecordFilterGroupEffect } from '@/views/components/ViewBarRecordFilterGroupEffect';
import { ViewBarRecordSortEffect } from '@/views/components/ViewBarRecordSortEffect';
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
import { UpdateViewButtonGroup } from './UpdateViewButtonGroup';
import { ViewBarDetails } from './ViewBarDetails';
@ -61,12 +63,15 @@ export const ViewBar = ({
}
rightComponent={
<>
<ObjectFilterDropdownButton
filterDropdownId={filterDropdownId}
hotkeyScope={{
scope: FiltersHotkeyScope.ObjectFilterDropdownButton,
}}
/>
<ObjectFilterDropdownComponentInstanceContext.Provider
value={{ instanceId: VIEW_BAR_FILTER_DROPDOWN_ID }}
>
<ViewBarFilterDropdown
hotkeyScope={{
scope: FiltersHotkeyScope.ObjectFilterDropdownButton,
}}
/>
</ObjectFilterDropdownComponentInstanceContext.Provider>
<ObjectSortDropdownButton
hotkeyScope={{
scope: FiltersHotkeyScope.ObjectSortDropdownButton,
@ -77,7 +82,6 @@ export const ViewBar = ({
}
bottomComponent={
<ViewBarDetails
filterDropdownId={filterDropdownId}
hasFilterButton
viewBarId={viewBarId}
objectNamePlural={objectNamePlural}

View File

@ -2,7 +2,6 @@ import styled from '@emotion/styled';
import { ReactNode, useMemo } from 'react';
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
import { AddObjectFilterFromDetailsButton } from '@/object-record/object-filter-dropdown/components/AddObjectFilterFromDetailsButton';
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
@ -10,6 +9,7 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
import { AdvancedFilterDropdownButton } from '@/views/components/AdvancedFilterDropdownButton';
import { EditableFilterDropdownButton } from '@/views/components/EditableFilterDropdownButton';
import { EditableSortChip } from '@/views/components/EditableSortChip';
import { ViewBarDetailsAddFilterButton } from '@/views/components/ViewBarDetailsAddFilterButton';
import { useViewFromQueryParams } from '@/views/hooks/internal/useViewFromQueryParams';
import { useCheckIsSoftDeleteFilter } from '@/object-record/record-filter/hooks/useCheckIsSoftDeleteFilter';
@ -34,7 +34,6 @@ import { LightButton } from 'twenty-ui/input';
export type ViewBarDetailsProps = {
hasFilterButton?: boolean;
rightComponent?: ReactNode;
filterDropdownId?: string;
viewBarId: string;
objectNamePlural: string;
};
@ -99,7 +98,6 @@ const StyledAddFilterContainer = styled.div`
export const ViewBarDetails = ({
hasFilterButton = false,
rightComponent,
filterDropdownId,
viewBarId,
objectNamePlural,
}: ViewBarDetailsProps) => {
@ -244,9 +242,7 @@ export const ViewBarDetails = ({
</ScrollWrapper>
{hasFilterButton && (
<StyledAddFilterContainer>
<AddObjectFilterFromDetailsButton
filterDropdownId={filterDropdownId}
/>
<ViewBarDetailsAddFilterButton />
</StyledAddFilterContainer>
)}
</StyledFilterContainer>

View File

@ -0,0 +1,29 @@
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
import { useResetFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useResetFilterDropdown';
import { t } from '@lingui/core/macro';
import { IconPlus } from 'twenty-ui/display';
import { LightButton } from 'twenty-ui/input';
export const ViewBarDetailsAddFilterButton = () => {
const { toggleDropdown } = useDropdown(VIEW_BAR_FILTER_DROPDOWN_ID);
const { resetFilterDropdown } = useResetFilterDropdown(
VIEW_BAR_FILTER_DROPDOWN_ID,
);
const handleClick = () => {
resetFilterDropdown();
toggleDropdown();
};
return (
<LightButton
onClick={handleClick}
Icon={IconPlus}
title={t`Add filter`}
accent="tertiary"
/>
);
};

View File

@ -0,0 +1,27 @@
import { useResetFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useResetFilterDropdown';
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
import { Trans } from '@lingui/react/macro';
export const ViewBarFilterButton = () => {
const { resetFilterDropdown } = useResetFilterDropdown();
const { toggleDropdown, isDropdownOpen } = useDropdown(
VIEW_BAR_FILTER_DROPDOWN_ID,
);
const handleClick = () => {
toggleDropdown();
resetFilterDropdown();
};
return (
<StyledHeaderDropdownButton
onClick={handleClick}
isUnfolded={isDropdownOpen}
>
<Trans>Filter</Trans>
</StyledHeaderDropdownButton>
);
};

View File

@ -0,0 +1,54 @@
import { useResetFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useResetFilterDropdown';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
import { isRecordFilterConsideredEmpty } from '@/object-record/record-filter/utils/isRecordFilterConsideredEmpty';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { ViewBarFilterDropdownContent } from '@/views/components/ViewBarFilterDropdownContent';
import { isDefined } from 'twenty-shared/utils';
import { ViewBarFilterButton } from './ViewBarFilterButton';
type ViewBarFilterDropdownProps = {
hotkeyScope: HotkeyScope;
};
export const ViewBarFilterDropdown = ({
hotkeyScope,
}: ViewBarFilterDropdownProps) => {
const { resetFilterDropdown } = useResetFilterDropdown();
const { removeRecordFilter } = useRemoveRecordFilter();
const selectedFilter = useRecoilComponentValueV2(
selectedFilterComponentState,
);
const handleDropdownClickOutside = () => {
const recordFilterIsEmpty =
isDefined(selectedFilter) &&
isRecordFilterConsideredEmpty(selectedFilter);
if (recordFilterIsEmpty) {
removeRecordFilter({ recordFilterId: selectedFilter.id });
}
};
const handleDropdownClose = () => {
resetFilterDropdown();
};
return (
<Dropdown
dropdownId={VIEW_BAR_FILTER_DROPDOWN_ID}
onClose={handleDropdownClose}
clickableComponent={<ViewBarFilterButton />}
dropdownComponents={<ViewBarFilterDropdownContent />}
dropdownHotkeyScope={hotkeyScope}
dropdownOffset={{ y: 8 }}
onClickOutside={handleDropdownClickOutside}
/>
);
};

View File

@ -0,0 +1,142 @@
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
import { useUpsertRecordFilterGroup } from '@/object-record/record-filter-group/hooks/useUpsertRecordFilterGroup';
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
import { useSetRecordFilterUsedInAdvancedFilterDropdownRow } from '@/object-record/advanced-filter/hooks/useSetRecordFilterUsedInAdvancedFilterDropdownRow';
import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
import { useCreateEmptyRecordFilterFromFieldMetadataItem } from '@/object-record/record-filter/hooks/useCreateEmptyRecordFilterFromFieldMetadataItem';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { ADVANCED_FILTER_DROPDOWN_ID } from '@/views/constants/AdvancedFilterDropdownId';
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { Pill } from 'twenty-ui/components';
import { IconFilter } from 'twenty-ui/display';
import { MenuItemLeftContent, StyledMenuItemBase } from 'twenty-ui/navigation';
import { v4 } from 'uuid';
export const StyledContainer = styled.div`
align-items: center;
display: flex;
justify-content: space-between;
padding: ${({ theme }) => theme.spacing(1)};
border-top: 1px solid ${({ theme }) => theme.border.color.light};
`;
export const StyledMenuItemSelect = styled(StyledMenuItemBase)`
&:hover {
background: ${({ theme }) => theme.background.transparent.light};
}
`;
export const StyledPill = styled(Pill)`
background: ${({ theme }) => theme.color.blueAccent10};
color: ${({ theme }) => theme.color.blue};
`;
export const ViewBarFilterDropdownAdvancedFilterButton = () => {
const advancedFilterQuerySubFilterCount = 0; // TODO
const { t } = useLingui();
const { openDropdown: openAdvancedFilterDropdown } = useDropdown(
ADVANCED_FILTER_DROPDOWN_ID,
);
const { closeDropdown: closeObjectFilterDropdown } = useDropdown(
VIEW_BAR_FILTER_DROPDOWN_ID,
);
const { currentView } = useGetCurrentViewOnly();
const { upsertRecordFilterGroup } = useUpsertRecordFilterGroup();
const { upsertRecordFilter } = useUpsertRecordFilter();
const objectMetadataId = currentView?.objectMetadataId;
if (!objectMetadataId) {
throw new Error('Object metadata id is missing from current view');
}
const { objectMetadataItem } = useObjectMetadataItemById({
objectId: objectMetadataId ?? null,
});
const availableFieldMetadataItemsForFilter = useRecoilValue(
availableFieldMetadataItemsForFilterFamilySelector({
objectMetadataItemId: objectMetadataItem.id,
}),
);
const currentRecordFilterGroups = useRecoilComponentValueV2(
currentRecordFilterGroupsComponentState,
);
const { setRecordFilterUsedInAdvancedFilterDropdownRow } =
useSetRecordFilterUsedInAdvancedFilterDropdownRow();
const { createEmptyRecordFilterFromFieldMetadataItem } =
useCreateEmptyRecordFilterFromFieldMetadataItem();
const handleClick = () => {
if (!isDefined(currentView)) {
throw new Error('Missing current view id');
}
const alreadyHasAdvancedFilterGroup = currentRecordFilterGroups.length > 0;
if (!alreadyHasAdvancedFilterGroup) {
const newRecordFilterGroup = {
id: v4(),
viewId: currentView.id,
logicalOperator: RecordFilterGroupLogicalOperator.AND,
};
upsertRecordFilterGroup(newRecordFilterGroup);
const defaultFieldMetadataItem =
availableFieldMetadataItemsForFilter.find(
(fieldMetadataItem) =>
fieldMetadataItem.id ===
objectMetadataItem?.labelIdentifierFieldMetadataId,
) ?? availableFieldMetadataItemsForFilter[0];
if (!isDefined(defaultFieldMetadataItem)) {
throw new Error('Missing default filter definition');
}
const { newRecordFilter } = createEmptyRecordFilterFromFieldMetadataItem(
defaultFieldMetadataItem,
);
newRecordFilter.recordFilterGroupId = newRecordFilterGroup.id;
upsertRecordFilter(newRecordFilter);
setRecordFilterUsedInAdvancedFilterDropdownRow(newRecordFilter);
}
closeObjectFilterDropdown();
openAdvancedFilterDropdown({
scope: ADVANCED_FILTER_DROPDOWN_ID,
});
};
return (
<StyledContainer>
<StyledMenuItemSelect onClick={handleClick}>
<MenuItemLeftContent LeftIcon={IconFilter} text={t`Advanced filter`} />
{advancedFilterQuerySubFilterCount > 0 && (
<StyledPill label={advancedFilterQuerySubFilterCount.toString()} />
)}
</StyledMenuItemSelect>
</StyledContainer>
);
};

View File

@ -0,0 +1,43 @@
import { ObjectFilterDropdownSubFieldSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSubFieldSelect';
import { ObjectFilterOperandSelectAndInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterOperandSelectAndInput';
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
import { ViewBarFilterDropdownAdvancedFilterButton } from '@/views/components/ViewBarFilterDropdownAdvancedFilterButton';
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
import { ObjectFilterDropdownFieldSelect } from '../../object-record/object-filter-dropdown/components/ObjectFilterDropdownFieldSelect';
export const ViewBarFilterDropdownContent = () => {
const [objectFilterDropdownIsSelectingCompositeField] =
useRecoilComponentStateV2(
objectFilterDropdownIsSelectingCompositeFieldComponentState,
VIEW_BAR_FILTER_DROPDOWN_ID,
);
const [objectFilterDropdownFilterIsSelected] = useRecoilComponentStateV2(
objectFilterDropdownFilterIsSelectedComponentState,
VIEW_BAR_FILTER_DROPDOWN_ID,
);
const shouldShowCompositeSelectionSubMenu =
objectFilterDropdownIsSelectingCompositeField;
const shouldShowFilterInput = objectFilterDropdownFilterIsSelected;
return (
<>
{shouldShowFilterInput ? (
<ObjectFilterOperandSelectAndInput
filterDropdownId={VIEW_BAR_FILTER_DROPDOWN_ID}
/>
) : shouldShowCompositeSelectionSubMenu ? (
<ObjectFilterDropdownSubFieldSelect />
) : (
<>
<ObjectFilterDropdownFieldSelect />
<ViewBarFilterDropdownAdvancedFilterButton />
</>
)}
</>
);
};

View File

@ -0,0 +1,204 @@
import { Meta, StoryObj } from '@storybook/react';
import { TaskGroups } from '@/activities/tasks/components/TaskGroups';
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlural';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext';
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/AggregateOperations';
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { ViewBarFilterDropdown } from '@/views/components/ViewBarFilterDropdown';
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
import { ViewType } from '@/views/types/ViewType';
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
import { View } from '@/views/types/View';
import { within } from '@storybook/test';
import { useSetRecoilState } from 'recoil';
import {
ComponentDecorator,
getCanvasElementForDropdownTesting,
} from 'twenty-ui/testing';
import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
const meta: Meta<typeof ViewBarFilterDropdown> = {
title: 'Modules/Views/ViewBarFilterDropdown',
component: ViewBarFilterDropdown,
decorators: [
(Story) => {
const companyObjectMetadataItem = generatedMockObjectMetadataItems.find(
(item) => item.nameSingular === CoreObjectNameSingular.Company,
)!;
const instanceId = companyObjectMetadataItem.id;
const setTableColumns = useSetRecoilComponentStateV2(
tableColumnsComponentState,
instanceId,
);
const setPrefetchViews = useSetRecoilState(prefetchViewsState);
const mockView: View = {
id: 'view-1',
name: 'Test View',
objectMetadataId: companyObjectMetadataItem.id,
viewFilters: [],
viewFilterGroups: [],
type: ViewType.Table,
key: null,
isCompact: false,
openRecordIn: ViewOpenRecordInType.SIDE_PANEL,
viewFields: [],
viewGroups: [],
viewSorts: [],
kanbanFieldMetadataId: '',
kanbanAggregateOperation: AGGREGATE_OPERATIONS.count,
icon: '',
kanbanAggregateOperationFieldMetadataId: '',
position: 0,
__typename: 'View',
};
setPrefetchViews([mockView]);
const setCurrentViewId = useSetRecoilComponentStateV2(
contextStoreCurrentViewIdComponentState,
MAIN_CONTEXT_STORE_INSTANCE_ID,
);
setCurrentViewId('view-1');
const columns = companyObjectMetadataItem.fields.map(
(fieldMetadataItem, index) =>
formatFieldMetadataItemAsColumnDefinition({
field: fieldMetadataItem,
objectMetadataItem: companyObjectMetadataItem,
position: index,
}),
);
setTableColumns(columns);
return (
<RecordIndexContextProvider
value={{
indexIdentifierUrl: () => '',
onIndexRecordsLoaded: () => {},
objectNamePlural: CoreObjectNamePlural.Company,
objectNameSingular: CoreObjectNameSingular.Company,
objectMetadataItem: companyObjectMetadataItem,
recordIndexId: instanceId,
}}
>
<RecordFilterGroupsComponentInstanceContext.Provider
value={{ instanceId }}
>
<RecordFiltersComponentInstanceContext.Provider
value={{ instanceId }}
>
<RecordSortsComponentInstanceContext.Provider
value={{ instanceId }}
>
<ObjectFilterDropdownComponentInstanceContext.Provider
value={{ instanceId: VIEW_BAR_FILTER_DROPDOWN_ID }}
>
<RecordTableComponentInstanceContext.Provider
value={{
instanceId: instanceId,
onColumnsChange: () => {},
}}
>
<ViewComponentInstanceContext.Provider
value={{ instanceId }}
>
<Story />
</ViewComponentInstanceContext.Provider>
</RecordTableComponentInstanceContext.Provider>
</ObjectFilterDropdownComponentInstanceContext.Provider>
</RecordSortsComponentInstanceContext.Provider>
</RecordFiltersComponentInstanceContext.Provider>
</RecordFilterGroupsComponentInstanceContext.Provider>
</RecordIndexContextProvider>
);
},
ContextStoreDecorator,
ObjectMetadataItemsDecorator,
SnackBarDecorator,
ComponentDecorator,
IconsProviderDecorator,
I18nFrontDecorator,
],
args: {
hotkeyScope: {
scope: 'view-bar-filter-dropdown',
},
},
};
export default meta;
type Story = StoryObj<typeof TaskGroups>;
export const Default: Story = {
play: async () => {
const canvas = within(getCanvasElementForDropdownTesting());
const filterButton = await canvas.findByText('Filter');
filterButton.click();
const textFilter = await canvas.findByText('Tagline');
textFilter.click();
const operatorDropdown = await canvas.findByText('Contains');
operatorDropdown.click();
const containsOption = await canvas.findByText("Doesn't contain");
containsOption.click();
},
};
export const Date: Story = {
play: async () => {
const canvas = within(getCanvasElementForDropdownTesting());
const filterButton = await canvas.findByText('Filter');
filterButton.click();
const dateFilter = await canvas.findByText('Last update');
dateFilter.click();
},
};
export const Number: Story = {
play: async () => {
const canvas = within(getCanvasElementForDropdownTesting());
const filterButton = await canvas.findByText('Filter');
filterButton.click();
const dateFilter = await canvas.findByText('Employees');
dateFilter.click();
},
};

View File

@ -0,0 +1 @@
export const VIEW_BAR_FILTER_DROPDOWN_ID = 'view-bar-filter-dropdown';