Refator/sorts dropdown (#1568)
* WIP * Fixed lint * Ok for sorts * Fixed on dropdown toggle * Fix lint
This commit is contained in:
@ -18,8 +18,6 @@ type CompanyBoardProps = Pick<
|
|||||||
|
|
||||||
export const CompanyBoard = ({ ...props }: CompanyBoardProps) => {
|
export const CompanyBoard = ({ ...props }: CompanyBoardProps) => {
|
||||||
const { handleViewsChange, handleViewSubmit } = useBoardViews({
|
const { handleViewsChange, handleViewSubmit } = useBoardViews({
|
||||||
availableFilters: opportunitiesBoardOptions.filters,
|
|
||||||
availableSorts: opportunitiesBoardOptions.sorts,
|
|
||||||
objectId: 'company',
|
objectId: 'company',
|
||||||
scopeContext: CompanyBoardRecoilScopeContext,
|
scopeContext: CompanyBoardRecoilScopeContext,
|
||||||
fieldDefinitions: pipelineAvailableFieldDefinitions,
|
fieldDefinitions: pipelineAvailableFieldDefinitions,
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { isBoardLoadedState } from '@/ui/board/states/isBoardLoadedState';
|
|||||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||||
import { availableFiltersScopedState } from '@/ui/view-bar/states/availableFiltersScopedState';
|
import { availableFiltersScopedState } from '@/ui/view-bar/states/availableFiltersScopedState';
|
||||||
|
import { availableSortsScopedState } from '@/ui/view-bar/states/availableSortsScopedState';
|
||||||
import { filtersScopedState } from '@/ui/view-bar/states/filtersScopedState';
|
import { filtersScopedState } from '@/ui/view-bar/states/filtersScopedState';
|
||||||
import { sortsOrderByScopedSelector } from '@/ui/view-bar/states/selectors/sortsOrderByScopedSelector';
|
import { sortsOrderByScopedSelector } from '@/ui/view-bar/states/selectors/sortsOrderByScopedSelector';
|
||||||
import { turnFilterIntoWhereClause } from '@/ui/view-bar/utils/turnFilterIntoWhereClause';
|
import { turnFilterIntoWhereClause } from '@/ui/view-bar/utils/turnFilterIntoWhereClause';
|
||||||
@ -29,8 +30,14 @@ export function HooksCompanyBoard() {
|
|||||||
CompanyBoardRecoilScopeContext,
|
CompanyBoardRecoilScopeContext,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [, setAvailableSorts] = useRecoilScopedState(
|
||||||
|
availableSortsScopedState,
|
||||||
|
CompanyBoardRecoilScopeContext,
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setAvailableFilters(opportunitiesBoardOptions.filters);
|
setAvailableFilters(opportunitiesBoardOptions.filters);
|
||||||
|
setAvailableSorts(opportunitiesBoardOptions.sorts);
|
||||||
});
|
});
|
||||||
|
|
||||||
const [, setIsBoardLoaded] = useRecoilState(isBoardLoadedState);
|
const [, setIsBoardLoaded] = useRecoilState(isBoardLoadedState);
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { useCompanyTableActionBarEntries } from '@/companies/hooks/useCompanyTab
|
|||||||
import { useCompanyTableContextMenuEntries } from '@/companies/hooks/useCompanyTableContextMenuEntries';
|
import { useCompanyTableContextMenuEntries } from '@/companies/hooks/useCompanyTableContextMenuEntries';
|
||||||
import { useSpreadsheetCompanyImport } from '@/companies/hooks/useSpreadsheetCompanyImport';
|
import { useSpreadsheetCompanyImport } from '@/companies/hooks/useSpreadsheetCompanyImport';
|
||||||
import { EntityTable } from '@/ui/table/components/EntityTable';
|
import { EntityTable } from '@/ui/table/components/EntityTable';
|
||||||
import { GenericEntityTableData } from '@/ui/table/components/GenericEntityTableData';
|
import { EntityTableEffect } from '@/ui/table/components/EntityTableEffect';
|
||||||
import { useUpsertEntityTableItem } from '@/ui/table/hooks/useUpsertEntityTableItem';
|
import { useUpsertEntityTableItem } from '@/ui/table/hooks/useUpsertEntityTableItem';
|
||||||
import { TableRecoilScopeContext } from '@/ui/table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
import { TableRecoilScopeContext } from '@/ui/table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||||
@ -17,7 +17,7 @@ import {
|
|||||||
useUpdateOneCompanyMutation,
|
useUpdateOneCompanyMutation,
|
||||||
} from '~/generated/graphql';
|
} from '~/generated/graphql';
|
||||||
import { companiesFilters } from '~/pages/companies/companies-filters';
|
import { companiesFilters } from '~/pages/companies/companies-filters';
|
||||||
import { availableSorts } from '~/pages/companies/companies-sorts';
|
import { companyAvailableSorts } from '~/pages/companies/companies-sorts';
|
||||||
|
|
||||||
export function CompanyTable() {
|
export function CompanyTable() {
|
||||||
const sortsOrderBy = useRecoilScopedValue(
|
const sortsOrderBy = useRecoilScopedValue(
|
||||||
@ -33,8 +33,6 @@ export function CompanyTable() {
|
|||||||
const upsertEntityTableItem = useUpsertEntityTableItem();
|
const upsertEntityTableItem = useUpsertEntityTableItem();
|
||||||
|
|
||||||
const { handleViewsChange, handleViewSubmit } = useTableViews({
|
const { handleViewsChange, handleViewSubmit } = useTableViews({
|
||||||
availableFilters: companiesFilters,
|
|
||||||
availableSorts,
|
|
||||||
objectId: 'company',
|
objectId: 'company',
|
||||||
columnDefinitions: companiesAvailableColumnDefinitions,
|
columnDefinitions: companiesAvailableColumnDefinitions,
|
||||||
});
|
});
|
||||||
@ -50,7 +48,7 @@ export function CompanyTable() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<GenericEntityTableData
|
<EntityTableEffect
|
||||||
getRequestResultKey="companies"
|
getRequestResultKey="companies"
|
||||||
useGetRequest={useGetCompaniesQuery}
|
useGetRequest={useGetCompaniesQuery}
|
||||||
getRequestOptimisticEffectDefinition={
|
getRequestOptimisticEffectDefinition={
|
||||||
@ -59,12 +57,12 @@ export function CompanyTable() {
|
|||||||
orderBy={sortsOrderBy}
|
orderBy={sortsOrderBy}
|
||||||
whereFilters={filtersWhere}
|
whereFilters={filtersWhere}
|
||||||
filterDefinitionArray={companiesFilters}
|
filterDefinitionArray={companiesFilters}
|
||||||
|
sortDefinitionArray={companyAvailableSorts}
|
||||||
setContextMenuEntries={setContextMenuEntries}
|
setContextMenuEntries={setContextMenuEntries}
|
||||||
setActionBarEntries={setActionBarEntries}
|
setActionBarEntries={setActionBarEntries}
|
||||||
/>
|
/>
|
||||||
<EntityTable
|
<EntityTable
|
||||||
defaultViewName="All Companies"
|
defaultViewName="All Companies"
|
||||||
availableSorts={availableSorts}
|
|
||||||
onViewsChange={handleViewsChange}
|
onViewsChange={handleViewsChange}
|
||||||
onViewSubmit={handleViewSubmit}
|
onViewSubmit={handleViewSubmit}
|
||||||
onImport={handleImport}
|
onImport={handleImport}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ export function CompanyTableMockData() {
|
|||||||
const setEntityTableData = useSetEntityTableData();
|
const setEntityTableData = useSetEntityTableData();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setEntityTableData(mockedCompaniesData, []);
|
setEntityTableData(mockedCompaniesData, [], []);
|
||||||
|
|
||||||
setTableColumns(companiesAvailableColumnDefinitions);
|
setTableColumns(companiesAvailableColumnDefinitions);
|
||||||
}, [setEntityTableData, setTableColumns]);
|
}, [setEntityTableData, setTableColumns]);
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import { EntityTable } from '@/ui/table/components/EntityTable';
|
import { EntityTable } from '@/ui/table/components/EntityTable';
|
||||||
import { useUpdateOneCompanyMutation } from '~/generated/graphql';
|
import { useUpdateOneCompanyMutation } from '~/generated/graphql';
|
||||||
import { availableSorts } from '~/pages/companies/companies-sorts';
|
|
||||||
|
|
||||||
import { CompanyTableMockData } from './CompanyTableMockData';
|
import { CompanyTableMockData } from './CompanyTableMockData';
|
||||||
|
|
||||||
@ -10,7 +9,6 @@ export function CompanyTableMockMode() {
|
|||||||
<CompanyTableMockData />
|
<CompanyTableMockData />
|
||||||
<EntityTable
|
<EntityTable
|
||||||
defaultViewName="All Companies"
|
defaultViewName="All Companies"
|
||||||
availableSorts={availableSorts}
|
|
||||||
updateEntityMutation={[useUpdateOneCompanyMutation()]}
|
updateEntityMutation={[useUpdateOneCompanyMutation()]}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { usePersonTableContextMenuEntries } from '@/people/hooks/usePeopleTableC
|
|||||||
import { usePersonTableActionBarEntries } from '@/people/hooks/usePersonTableActionBarEntries';
|
import { usePersonTableActionBarEntries } from '@/people/hooks/usePersonTableActionBarEntries';
|
||||||
import { useSpreadsheetPersonImport } from '@/people/hooks/useSpreadsheetPersonImport';
|
import { useSpreadsheetPersonImport } from '@/people/hooks/useSpreadsheetPersonImport';
|
||||||
import { EntityTable } from '@/ui/table/components/EntityTable';
|
import { EntityTable } from '@/ui/table/components/EntityTable';
|
||||||
import { GenericEntityTableData } from '@/ui/table/components/GenericEntityTableData';
|
import { EntityTableEffect } from '@/ui/table/components/EntityTableEffect';
|
||||||
import { useUpsertEntityTableItem } from '@/ui/table/hooks/useUpsertEntityTableItem';
|
import { useUpsertEntityTableItem } from '@/ui/table/hooks/useUpsertEntityTableItem';
|
||||||
import { TableRecoilScopeContext } from '@/ui/table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
import { TableRecoilScopeContext } from '@/ui/table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||||
@ -17,7 +17,7 @@ import {
|
|||||||
useUpdateOnePersonMutation,
|
useUpdateOnePersonMutation,
|
||||||
} from '~/generated/graphql';
|
} from '~/generated/graphql';
|
||||||
import { peopleFilters } from '~/pages/people/people-filters';
|
import { peopleFilters } from '~/pages/people/people-filters';
|
||||||
import { availableSorts } from '~/pages/people/people-sorts';
|
import { peopleAvailableSorts } from '~/pages/people/people-sorts';
|
||||||
|
|
||||||
export function PeopleTable() {
|
export function PeopleTable() {
|
||||||
const sortsOrderBy = useRecoilScopedValue(
|
const sortsOrderBy = useRecoilScopedValue(
|
||||||
@ -34,8 +34,6 @@ export function PeopleTable() {
|
|||||||
const { openPersonSpreadsheetImport } = useSpreadsheetPersonImport();
|
const { openPersonSpreadsheetImport } = useSpreadsheetPersonImport();
|
||||||
|
|
||||||
const { handleViewsChange, handleViewSubmit } = useTableViews({
|
const { handleViewsChange, handleViewSubmit } = useTableViews({
|
||||||
availableFilters: peopleFilters,
|
|
||||||
availableSorts,
|
|
||||||
objectId: 'person',
|
objectId: 'person',
|
||||||
columnDefinitions: peopleAvailableColumnDefinitions,
|
columnDefinitions: peopleAvailableColumnDefinitions,
|
||||||
});
|
});
|
||||||
@ -49,7 +47,7 @@ export function PeopleTable() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<GenericEntityTableData
|
<EntityTableEffect
|
||||||
getRequestResultKey="people"
|
getRequestResultKey="people"
|
||||||
useGetRequest={useGetPeopleQuery}
|
useGetRequest={useGetPeopleQuery}
|
||||||
getRequestOptimisticEffectDefinition={
|
getRequestOptimisticEffectDefinition={
|
||||||
@ -60,10 +58,10 @@ export function PeopleTable() {
|
|||||||
filterDefinitionArray={peopleFilters}
|
filterDefinitionArray={peopleFilters}
|
||||||
setContextMenuEntries={setContextMenuEntries}
|
setContextMenuEntries={setContextMenuEntries}
|
||||||
setActionBarEntries={setActionBarEntries}
|
setActionBarEntries={setActionBarEntries}
|
||||||
|
sortDefinitionArray={peopleAvailableSorts}
|
||||||
/>
|
/>
|
||||||
<EntityTable
|
<EntityTable
|
||||||
defaultViewName="All People"
|
defaultViewName="All People"
|
||||||
availableSorts={availableSorts}
|
|
||||||
onViewsChange={handleViewsChange}
|
onViewsChange={handleViewsChange}
|
||||||
onViewSubmit={handleViewSubmit}
|
onViewSubmit={handleViewSubmit}
|
||||||
onImport={handleImport}
|
onImport={handleImport}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ export function PipelineAddButton() {
|
|||||||
const { enqueueSnackBar } = useSnackBar();
|
const { enqueueSnackBar } = useSnackBar();
|
||||||
|
|
||||||
const { closeDropdownButton, toggleDropdownButton } = useDropdownButton({
|
const { closeDropdownButton, toggleDropdownButton } = useDropdownButton({
|
||||||
key: 'add-pipeline-progress',
|
dropdownId: 'add-pipeline-progress',
|
||||||
});
|
});
|
||||||
|
|
||||||
const createCompanyProgress = useCreateCompanyProgress();
|
const createCompanyProgress = useCreateCompanyProgress();
|
||||||
@ -53,7 +53,7 @@ export function PipelineAddButton() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
dropdownKey="add-pipeline-progress"
|
dropdownId="add-pipeline-progress"
|
||||||
buttonComponents={
|
buttonComponents={
|
||||||
<IconButton
|
<IconButton
|
||||||
Icon={IconPlus}
|
Icon={IconPlus}
|
||||||
|
|||||||
@ -10,29 +10,23 @@ import { BoardOptionsHotkeyScope } from '../types/BoardOptionsHotkeyScope';
|
|||||||
|
|
||||||
import { BoardOptionsDropdown } from './BoardOptionsDropdown';
|
import { BoardOptionsDropdown } from './BoardOptionsDropdown';
|
||||||
|
|
||||||
export type BoardHeaderProps<SortField> = ComponentProps<'div'> & {
|
export type BoardHeaderProps = ComponentProps<'div'> & {
|
||||||
onStageAdd?: (boardColumn: BoardColumnDefinition) => void;
|
onStageAdd?: (boardColumn: BoardColumnDefinition) => void;
|
||||||
} & Pick<
|
} & Pick<
|
||||||
ViewBarProps<SortField>,
|
ViewBarProps,
|
||||||
| 'availableSorts'
|
'defaultViewName' | 'onViewsChange' | 'onViewSubmit' | 'scopeContext'
|
||||||
| 'defaultViewName'
|
|
||||||
| 'onViewsChange'
|
|
||||||
| 'onViewSubmit'
|
|
||||||
| 'scopeContext'
|
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export function BoardHeader<SortField>({
|
export function BoardHeader({
|
||||||
onStageAdd,
|
onStageAdd,
|
||||||
onViewsChange,
|
onViewsChange,
|
||||||
onViewSubmit,
|
onViewSubmit,
|
||||||
scopeContext,
|
scopeContext,
|
||||||
availableSorts,
|
|
||||||
defaultViewName,
|
defaultViewName,
|
||||||
}: BoardHeaderProps<SortField>) {
|
}: BoardHeaderProps) {
|
||||||
return (
|
return (
|
||||||
<RecoilScope SpecificContext={DropdownRecoilScopeContext}>
|
<RecoilScope SpecificContext={DropdownRecoilScopeContext}>
|
||||||
<ViewBar
|
<ViewBar
|
||||||
availableSorts={availableSorts}
|
|
||||||
defaultViewName={defaultViewName}
|
defaultViewName={defaultViewName}
|
||||||
onViewsChange={onViewsChange}
|
onViewsChange={onViewsChange}
|
||||||
onViewSubmit={onViewSubmit}
|
onViewSubmit={onViewSubmit}
|
||||||
|
|||||||
@ -27,7 +27,7 @@ export function BoardOptionsDropdown({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={customHotkeyScope}
|
dropdownHotkeyScope={customHotkeyScope}
|
||||||
dropdownKey={BoardOptionsDropdownKey}
|
dropdownId={BoardOptionsDropdownKey}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { BoardOptionsDropdownKey } from '../types/BoardOptionsDropdownKey';
|
|||||||
|
|
||||||
export function BoardOptionsDropdownButton() {
|
export function BoardOptionsDropdownButton() {
|
||||||
const { isDropdownButtonOpen, toggleDropdownButton } = useDropdownButton({
|
const { isDropdownButtonOpen, toggleDropdownButton } = useDropdownButton({
|
||||||
key: BoardOptionsDropdownKey,
|
dropdownId: BoardOptionsDropdownKey,
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleClick() {
|
function handleClick() {
|
||||||
|
|||||||
@ -126,7 +126,7 @@ export function BoardOptionsDropdownContent({
|
|||||||
const { handleFieldVisibilityChange } = useBoardCardFields({ scopeContext });
|
const { handleFieldVisibilityChange } = useBoardCardFields({ scopeContext });
|
||||||
|
|
||||||
const { closeDropdownButton } = useDropdownButton({
|
const { closeDropdownButton } = useDropdownButton({
|
||||||
key: BoardOptionsDropdownKey,
|
dropdownId: BoardOptionsDropdownKey,
|
||||||
});
|
});
|
||||||
|
|
||||||
useScopedHotkeys(
|
useScopedHotkeys(
|
||||||
|
|||||||
@ -22,7 +22,6 @@ import {
|
|||||||
PipelineStage,
|
PipelineStage,
|
||||||
useUpdateOnePipelineProgressStageMutation,
|
useUpdateOnePipelineProgressStageMutation,
|
||||||
} from '~/generated/graphql';
|
} from '~/generated/graphql';
|
||||||
import { PipelineProgressOrderByWithRelationInput as PipelineProgresses_Order_By } from '~/generated/graphql';
|
|
||||||
|
|
||||||
import { useCurrentCardSelected } from '../hooks/useCurrentCardSelected';
|
import { useCurrentCardSelected } from '../hooks/useCurrentCardSelected';
|
||||||
import { useSetCardSelected } from '../hooks/useSetCardSelected';
|
import { useSetCardSelected } from '../hooks/useSetCardSelected';
|
||||||
@ -41,7 +40,7 @@ export type EntityBoardProps = {
|
|||||||
onEditColumnTitle: (columnId: string, title: string, color: string) => void;
|
onEditColumnTitle: (columnId: string, title: string, color: string) => void;
|
||||||
scopeContext: Context<string | null>;
|
scopeContext: Context<string | null>;
|
||||||
} & Pick<
|
} & Pick<
|
||||||
BoardHeaderProps<PipelineProgresses_Order_By>,
|
BoardHeaderProps,
|
||||||
'defaultViewName' | 'onViewsChange' | 'onViewSubmit'
|
'defaultViewName' | 'onViewsChange' | 'onViewSubmit'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
@ -142,7 +141,6 @@ export function EntityBoard({
|
|||||||
<StyledWrapper>
|
<StyledWrapper>
|
||||||
<StyledBoardHeader
|
<StyledBoardHeader
|
||||||
defaultViewName={defaultViewName}
|
defaultViewName={defaultViewName}
|
||||||
availableSorts={boardOptions.sorts}
|
|
||||||
onStageAdd={onColumnAdd}
|
onStageAdd={onColumnAdd}
|
||||||
onViewsChange={onViewsChange}
|
onViewsChange={onViewsChange}
|
||||||
onViewSubmit={onViewSubmit}
|
onViewSubmit={onViewSubmit}
|
||||||
|
|||||||
@ -1,13 +1,12 @@
|
|||||||
import type { ComponentType, Context } from 'react';
|
import type { ComponentType, Context } from 'react';
|
||||||
|
|
||||||
import { FilterDefinitionByEntity } from '@/ui/view-bar/types/FilterDefinitionByEntity';
|
import { FilterDefinitionByEntity } from '@/ui/view-bar/types/FilterDefinitionByEntity';
|
||||||
import { SortType } from '@/ui/view-bar/types/interface';
|
import { SortDefinition } from '@/ui/view-bar/types/SortDefinition';
|
||||||
import { PipelineProgress } from '~/generated/graphql';
|
import { PipelineProgress } from '~/generated/graphql';
|
||||||
import { PipelineProgressOrderByWithRelationInput as PipelineProgresses_Order_By } from '~/generated/graphql';
|
|
||||||
|
|
||||||
export type BoardOptions = {
|
export type BoardOptions = {
|
||||||
newCardComponent: React.ReactNode;
|
newCardComponent: React.ReactNode;
|
||||||
CardComponent: ComponentType<{ scopeContext: Context<string | null> }>;
|
CardComponent: ComponentType<{ scopeContext: Context<string | null> }>;
|
||||||
filters: FilterDefinitionByEntity<PipelineProgress>[];
|
filters: FilterDefinitionByEntity<PipelineProgress>[];
|
||||||
sorts: Array<SortType<PipelineProgresses_Order_By>>;
|
sorts: SortDefinition[];
|
||||||
};
|
};
|
||||||
|
|||||||
@ -15,31 +15,28 @@ import { DropdownRecoilScopeContext } from '../states/recoil-scope-contexts/Drop
|
|||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
buttonComponents: JSX.Element | JSX.Element[];
|
buttonComponents: JSX.Element | JSX.Element[];
|
||||||
dropdownComponents: JSX.Element | JSX.Element[];
|
dropdownComponents: JSX.Element | JSX.Element[];
|
||||||
dropdownKey: string;
|
dropdownId: string;
|
||||||
hotkey?: {
|
hotkey?: {
|
||||||
key: Keys;
|
key: Keys;
|
||||||
scope: string;
|
scope: string;
|
||||||
};
|
};
|
||||||
dropdownHotkeyScope?: HotkeyScope;
|
dropdownHotkeyScope?: HotkeyScope;
|
||||||
dropdownPlacement?: Placement;
|
dropdownPlacement?: Placement;
|
||||||
onDropdownToggle?: (isDropdownOpen: boolean) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function DropdownButton({
|
export function DropdownButton({
|
||||||
buttonComponents,
|
buttonComponents,
|
||||||
dropdownComponents,
|
dropdownComponents,
|
||||||
dropdownKey,
|
dropdownId,
|
||||||
hotkey,
|
hotkey,
|
||||||
dropdownHotkeyScope,
|
dropdownHotkeyScope,
|
||||||
dropdownPlacement = 'bottom-end',
|
dropdownPlacement = 'bottom-end',
|
||||||
onDropdownToggle,
|
|
||||||
}: OwnProps) {
|
}: OwnProps) {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const { isDropdownButtonOpen, toggleDropdownButton, closeDropdownButton } =
|
const { isDropdownButtonOpen, toggleDropdownButton, closeDropdownButton } =
|
||||||
useDropdownButton({
|
useDropdownButton({
|
||||||
key: dropdownKey,
|
dropdownId,
|
||||||
onDropdownToggle,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const { refs, floatingStyles } = useFloating({
|
const { refs, floatingStyles } = useFloating({
|
||||||
@ -63,7 +60,7 @@ export function DropdownButton({
|
|||||||
const [dropdownButtonCustomHotkeyScope, setDropdownButtonCustomHotkeyScope] =
|
const [dropdownButtonCustomHotkeyScope, setDropdownButtonCustomHotkeyScope] =
|
||||||
useRecoilScopedFamilyState(
|
useRecoilScopedFamilyState(
|
||||||
dropdownButtonCustomHotkeyScopeScopedFamilyState,
|
dropdownButtonCustomHotkeyScopeScopedFamilyState,
|
||||||
dropdownKey,
|
dropdownId,
|
||||||
DropdownRecoilScopeContext,
|
DropdownRecoilScopeContext,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -5,14 +5,7 @@ import { dropdownButtonCustomHotkeyScopeScopedFamilyState } from '../states/drop
|
|||||||
import { isDropdownButtonOpenScopedFamilyState } from '../states/isDropdownButtonOpenScopedFamilyState';
|
import { isDropdownButtonOpenScopedFamilyState } from '../states/isDropdownButtonOpenScopedFamilyState';
|
||||||
import { DropdownRecoilScopeContext } from '../states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
import { DropdownRecoilScopeContext } from '../states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
||||||
|
|
||||||
// TODO: have a more explicit name than key
|
export function useDropdownButton({ dropdownId }: { dropdownId: string }) {
|
||||||
export function useDropdownButton({
|
|
||||||
key,
|
|
||||||
onDropdownToggle,
|
|
||||||
}: {
|
|
||||||
key: string;
|
|
||||||
onDropdownToggle?: (isDropdownButtonOpen: boolean) => void;
|
|
||||||
}) {
|
|
||||||
const {
|
const {
|
||||||
setHotkeyScopeAndMemorizePreviousScope,
|
setHotkeyScopeAndMemorizePreviousScope,
|
||||||
goBackToPreviousHotkeyScope,
|
goBackToPreviousHotkeyScope,
|
||||||
@ -21,20 +14,19 @@ export function useDropdownButton({
|
|||||||
const [isDropdownButtonOpen, setIsDropdownButtonOpen] =
|
const [isDropdownButtonOpen, setIsDropdownButtonOpen] =
|
||||||
useRecoilScopedFamilyState(
|
useRecoilScopedFamilyState(
|
||||||
isDropdownButtonOpenScopedFamilyState,
|
isDropdownButtonOpenScopedFamilyState,
|
||||||
key,
|
dropdownId,
|
||||||
DropdownRecoilScopeContext,
|
DropdownRecoilScopeContext,
|
||||||
);
|
);
|
||||||
|
|
||||||
const [dropdownButtonCustomHotkeyScope] = useRecoilScopedFamilyState(
|
const [dropdownButtonCustomHotkeyScope] = useRecoilScopedFamilyState(
|
||||||
dropdownButtonCustomHotkeyScopeScopedFamilyState,
|
dropdownButtonCustomHotkeyScopeScopedFamilyState,
|
||||||
key,
|
dropdownId,
|
||||||
DropdownRecoilScopeContext,
|
DropdownRecoilScopeContext,
|
||||||
);
|
);
|
||||||
|
|
||||||
function closeDropdownButton() {
|
function closeDropdownButton() {
|
||||||
goBackToPreviousHotkeyScope();
|
goBackToPreviousHotkeyScope();
|
||||||
setIsDropdownButtonOpen(false);
|
setIsDropdownButtonOpen(false);
|
||||||
onDropdownToggle?.(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function openDropdownButton() {
|
function openDropdownButton() {
|
||||||
@ -46,7 +38,6 @@ export function useDropdownButton({
|
|||||||
dropdownButtonCustomHotkeyScope.customScopes,
|
dropdownButtonCustomHotkeyScope.customScopes,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
onDropdownToggle?.(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleDropdownButton() {
|
function toggleDropdownButton() {
|
||||||
@ -55,7 +46,6 @@ export function useDropdownButton({
|
|||||||
} else {
|
} else {
|
||||||
openDropdownButton();
|
openDropdownButton();
|
||||||
}
|
}
|
||||||
onDropdownToggle?.(isDropdownButtonOpen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -22,7 +22,7 @@ export function ShowPageAddButton({
|
|||||||
entity: ActivityTargetableEntity;
|
entity: ActivityTargetableEntity;
|
||||||
}) {
|
}) {
|
||||||
const { closeDropdownButton, toggleDropdownButton } = useDropdownButton({
|
const { closeDropdownButton, toggleDropdownButton } = useDropdownButton({
|
||||||
key: 'add-show-page',
|
dropdownId: 'add-show-page',
|
||||||
});
|
});
|
||||||
const openCreateActivity = useOpenCreateActivityDrawer();
|
const openCreateActivity = useOpenCreateActivityDrawer();
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ export function ShowPageAddButton({
|
|||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
dropdownKey="add-show-page"
|
dropdownId="add-show-page"
|
||||||
buttonComponents={
|
buttonComponents={
|
||||||
<IconButton
|
<IconButton
|
||||||
Icon={IconPlus}
|
Icon={IconPlus}
|
||||||
|
|||||||
@ -85,25 +85,20 @@ const StyledTableContainer = styled.div`
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type OwnProps<SortField> = {
|
type OwnProps = {
|
||||||
updateEntityMutation: any;
|
updateEntityMutation: any;
|
||||||
} & Pick<
|
} & Pick<
|
||||||
TableHeaderProps<SortField>,
|
TableHeaderProps,
|
||||||
| 'availableSorts'
|
'defaultViewName' | 'onImport' | 'onViewsChange' | 'onViewSubmit'
|
||||||
| 'defaultViewName'
|
|
||||||
| 'onImport'
|
|
||||||
| 'onViewsChange'
|
|
||||||
| 'onViewSubmit'
|
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export function EntityTable<SortField>({
|
export function EntityTable({
|
||||||
availableSorts,
|
|
||||||
defaultViewName,
|
defaultViewName,
|
||||||
onImport,
|
onImport,
|
||||||
onViewsChange,
|
onViewsChange,
|
||||||
onViewSubmit,
|
onViewSubmit,
|
||||||
updateEntityMutation,
|
updateEntityMutation,
|
||||||
}: OwnProps<SortField>) {
|
}: OwnProps) {
|
||||||
const tableBodyRef = useRef<HTMLDivElement>(null);
|
const tableBodyRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const setRowSelectedState = useSetRowSelectedState();
|
const setRowSelectedState = useSetRowSelectedState();
|
||||||
@ -141,7 +136,6 @@ export function EntityTable<SortField>({
|
|||||||
<StyledTableWithHeader>
|
<StyledTableWithHeader>
|
||||||
<StyledTableContainer ref={tableBodyRef}>
|
<StyledTableContainer ref={tableBodyRef}>
|
||||||
<TableHeader
|
<TableHeader
|
||||||
availableSorts={availableSorts ?? []}
|
|
||||||
defaultViewName={defaultViewName}
|
defaultViewName={defaultViewName}
|
||||||
onImport={onImport}
|
onImport={onImport}
|
||||||
onViewsChange={onViewsChange}
|
onViewsChange={onViewsChange}
|
||||||
|
|||||||
@ -4,9 +4,10 @@ import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimis
|
|||||||
import { OptimisticEffectDefinition } from '@/apollo/optimistic-effect/types/OptimisticEffectDefinition';
|
import { OptimisticEffectDefinition } from '@/apollo/optimistic-effect/types/OptimisticEffectDefinition';
|
||||||
import { useSetEntityTableData } from '@/ui/table/hooks/useSetEntityTableData';
|
import { useSetEntityTableData } from '@/ui/table/hooks/useSetEntityTableData';
|
||||||
import { FilterDefinition } from '@/ui/view-bar/types/FilterDefinition';
|
import { FilterDefinition } from '@/ui/view-bar/types/FilterDefinition';
|
||||||
|
import { SortDefinition } from '@/ui/view-bar/types/SortDefinition';
|
||||||
import { SortOrder } from '~/generated/graphql';
|
import { SortOrder } from '~/generated/graphql';
|
||||||
|
|
||||||
export function GenericEntityTableData({
|
export function EntityTableEffect({
|
||||||
useGetRequest,
|
useGetRequest,
|
||||||
getRequestResultKey,
|
getRequestResultKey,
|
||||||
getRequestOptimisticEffectDefinition,
|
getRequestOptimisticEffectDefinition,
|
||||||
@ -19,13 +20,18 @@ export function GenericEntityTableData({
|
|||||||
filterDefinitionArray,
|
filterDefinitionArray,
|
||||||
setActionBarEntries,
|
setActionBarEntries,
|
||||||
setContextMenuEntries,
|
setContextMenuEntries,
|
||||||
|
sortDefinitionArray,
|
||||||
}: {
|
}: {
|
||||||
|
// TODO: type this
|
||||||
useGetRequest: any;
|
useGetRequest: any;
|
||||||
getRequestResultKey: string;
|
getRequestResultKey: string;
|
||||||
getRequestOptimisticEffectDefinition: OptimisticEffectDefinition<any>;
|
getRequestOptimisticEffectDefinition: OptimisticEffectDefinition<any>;
|
||||||
|
// TODO: type this and replace with defaultSorts reduce should be applied to defaultSorts in this component not before
|
||||||
orderBy?: any;
|
orderBy?: any;
|
||||||
|
// TODO: type this and replace with defaultFilters reduce should be applied to defaultFilters in this component not before
|
||||||
whereFilters?: any;
|
whereFilters?: any;
|
||||||
filterDefinitionArray: FilterDefinition[];
|
filterDefinitionArray: FilterDefinition[];
|
||||||
|
sortDefinitionArray: SortDefinition[];
|
||||||
setActionBarEntries?: () => void;
|
setActionBarEntries?: () => void;
|
||||||
setContextMenuEntries?: () => void;
|
setContextMenuEntries?: () => void;
|
||||||
}) {
|
}) {
|
||||||
@ -36,7 +42,9 @@ export function GenericEntityTableData({
|
|||||||
variables: { orderBy, where: whereFilters },
|
variables: { orderBy, where: whereFilters },
|
||||||
onCompleted: (data: any) => {
|
onCompleted: (data: any) => {
|
||||||
const entities = data[getRequestResultKey] ?? [];
|
const entities = data[getRequestResultKey] ?? [];
|
||||||
setEntityTableData(entities, filterDefinitionArray);
|
|
||||||
|
setEntityTableData(entities, filterDefinitionArray, sortDefinitionArray);
|
||||||
|
|
||||||
registerOptimisticEffect({
|
registerOptimisticEffect({
|
||||||
variables: { orderBy, where: whereFilters },
|
variables: { orderBy, where: whereFilters },
|
||||||
definition: getRequestOptimisticEffectDefinition,
|
definition: getRequestOptimisticEffectDefinition,
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
// We should either apply the constant all caps case or maybe define a more general enum to store those ids ?
|
||||||
|
export const TableOptionsDropdownId = 'table-options';
|
||||||
@ -6,7 +6,9 @@ import { tableEntitiesFamilyState } from '@/ui/table/states/tableEntitiesFamilyS
|
|||||||
import { tableRowIdsState } from '@/ui/table/states/tableRowIdsState';
|
import { tableRowIdsState } from '@/ui/table/states/tableRowIdsState';
|
||||||
import { useContextScopeId } from '@/ui/utilities/recoil-scope/hooks/useContextScopeId';
|
import { useContextScopeId } from '@/ui/utilities/recoil-scope/hooks/useContextScopeId';
|
||||||
import { availableFiltersScopedState } from '@/ui/view-bar/states/availableFiltersScopedState';
|
import { availableFiltersScopedState } from '@/ui/view-bar/states/availableFiltersScopedState';
|
||||||
|
import { availableSortsScopedState } from '@/ui/view-bar/states/availableSortsScopedState';
|
||||||
import { FilterDefinition } from '@/ui/view-bar/types/FilterDefinition';
|
import { FilterDefinition } from '@/ui/view-bar/types/FilterDefinition';
|
||||||
|
import { SortDefinition } from '@/ui/view-bar/types/SortDefinition';
|
||||||
|
|
||||||
import { isFetchingEntityTableDataState } from '../states/isFetchingEntityTableDataState';
|
import { isFetchingEntityTableDataState } from '../states/isFetchingEntityTableDataState';
|
||||||
import { numberOfTableRowsState } from '../states/numberOfTableRowsState';
|
import { numberOfTableRowsState } from '../states/numberOfTableRowsState';
|
||||||
@ -20,7 +22,8 @@ export function useSetEntityTableData() {
|
|||||||
({ set, snapshot }) =>
|
({ set, snapshot }) =>
|
||||||
<T extends { id: string }>(
|
<T extends { id: string }>(
|
||||||
newEntityArray: T[],
|
newEntityArray: T[],
|
||||||
filters: FilterDefinition[],
|
filterDefinitionArray: FilterDefinition[],
|
||||||
|
sortDefinitionArray: SortDefinition[],
|
||||||
) => {
|
) => {
|
||||||
for (const entity of newEntityArray) {
|
for (const entity of newEntityArray) {
|
||||||
const currentEntity = snapshot
|
const currentEntity = snapshot
|
||||||
@ -46,7 +49,14 @@ export function useSetEntityTableData() {
|
|||||||
|
|
||||||
set(numberOfTableRowsState, entityIds.length);
|
set(numberOfTableRowsState, entityIds.length);
|
||||||
|
|
||||||
set(availableFiltersScopedState(tableContextScopeId), filters);
|
set(
|
||||||
|
availableFiltersScopedState(tableContextScopeId),
|
||||||
|
filterDefinitionArray,
|
||||||
|
);
|
||||||
|
set(
|
||||||
|
availableSortsScopedState(tableContextScopeId),
|
||||||
|
sortDefinitionArray,
|
||||||
|
);
|
||||||
|
|
||||||
set(isFetchingEntityTableDataState, false);
|
set(isFetchingEntityTableDataState, false);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { DropdownButton } from '@/ui/dropdown/components/DropdownButton';
|
|||||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
import type { View } from '@/ui/view-bar/types/View';
|
import type { View } from '@/ui/view-bar/types/View';
|
||||||
|
|
||||||
import { TableOptionsDropdownKey } from '../../types/TableOptionsDropdownKey';
|
import { TableOptionsDropdownId } from '../../constants/TableOptionsDropdownId';
|
||||||
|
|
||||||
import { TableOptionsDropdownButton } from './TableOptionsDropdownButton';
|
import { TableOptionsDropdownButton } from './TableOptionsDropdownButton';
|
||||||
import { TableOptionsDropdownContent } from './TableOptionsDropdownContent';
|
import { TableOptionsDropdownContent } from './TableOptionsDropdownContent';
|
||||||
@ -22,7 +22,7 @@ export function TableOptionsDropdown({
|
|||||||
<DropdownButton
|
<DropdownButton
|
||||||
buttonComponents={<TableOptionsDropdownButton />}
|
buttonComponents={<TableOptionsDropdownButton />}
|
||||||
dropdownHotkeyScope={customHotkeyScope}
|
dropdownHotkeyScope={customHotkeyScope}
|
||||||
dropdownKey={TableOptionsDropdownKey}
|
dropdownId={TableOptionsDropdownId}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<TableOptionsDropdownContent
|
<TableOptionsDropdownContent
|
||||||
onImport={onImport}
|
onImport={onImport}
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { StyledHeaderDropdownButton } from '@/ui/dropdown/components/StyledHeaderDropdownButton';
|
import { StyledHeaderDropdownButton } from '@/ui/dropdown/components/StyledHeaderDropdownButton';
|
||||||
import { useDropdownButton } from '@/ui/dropdown/hooks/useDropdownButton';
|
import { useDropdownButton } from '@/ui/dropdown/hooks/useDropdownButton';
|
||||||
|
|
||||||
import { TableOptionsDropdownKey } from '../../types/TableOptionsDropdownKey';
|
import { TableOptionsDropdownId } from '../../constants/TableOptionsDropdownId';
|
||||||
|
|
||||||
export function TableOptionsDropdownButton() {
|
export function TableOptionsDropdownButton() {
|
||||||
const { isDropdownButtonOpen, toggleDropdownButton } = useDropdownButton({
|
const { isDropdownButtonOpen, toggleDropdownButton } = useDropdownButton({
|
||||||
key: TableOptionsDropdownKey,
|
dropdownId: TableOptionsDropdownId,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -18,11 +18,11 @@ import { viewsByIdScopedSelector } from '@/ui/view-bar/states/selectors/viewsByI
|
|||||||
import { viewEditModeState } from '@/ui/view-bar/states/viewEditModeState';
|
import { viewEditModeState } from '@/ui/view-bar/states/viewEditModeState';
|
||||||
import type { View } from '@/ui/view-bar/types/View';
|
import type { View } from '@/ui/view-bar/types/View';
|
||||||
|
|
||||||
|
import { TableOptionsDropdownId } from '../../constants/TableOptionsDropdownId';
|
||||||
import { useTableColumns } from '../../hooks/useTableColumns';
|
import { useTableColumns } from '../../hooks/useTableColumns';
|
||||||
import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
|
import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||||
import { hiddenTableColumnsScopedSelector } from '../../states/selectors/hiddenTableColumnsScopedSelector';
|
import { hiddenTableColumnsScopedSelector } from '../../states/selectors/hiddenTableColumnsScopedSelector';
|
||||||
import { visibleTableColumnsScopedSelector } from '../../states/selectors/visibleTableColumnsScopedSelector';
|
import { visibleTableColumnsScopedSelector } from '../../states/selectors/visibleTableColumnsScopedSelector';
|
||||||
import { TableOptionsDropdownKey } from '../../types/TableOptionsDropdownKey';
|
|
||||||
import { TableOptionsHotkeyScope } from '../../types/TableOptionsHotkeyScope';
|
import { TableOptionsHotkeyScope } from '../../types/TableOptionsHotkeyScope';
|
||||||
|
|
||||||
type TableOptionsDropdownButtonProps = {
|
type TableOptionsDropdownButtonProps = {
|
||||||
@ -37,7 +37,7 @@ export function TableOptionsDropdownContent({
|
|||||||
onImport,
|
onImport,
|
||||||
}: TableOptionsDropdownButtonProps) {
|
}: TableOptionsDropdownButtonProps) {
|
||||||
const { closeDropdownButton } = useDropdownButton({
|
const { closeDropdownButton } = useDropdownButton({
|
||||||
key: TableOptionsDropdownKey,
|
dropdownId: TableOptionsDropdownId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [currentMenu, setCurrentMenu] = useState<TableOptionsMenu | undefined>(
|
const [currentMenu, setCurrentMenu] = useState<TableOptionsMenu | undefined>(
|
||||||
|
|||||||
@ -8,27 +8,24 @@ import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoi
|
|||||||
import { ViewBar, ViewBarProps } from '@/ui/view-bar/components/ViewBar';
|
import { ViewBar, ViewBarProps } from '@/ui/view-bar/components/ViewBar';
|
||||||
import { currentViewIdScopedState } from '@/ui/view-bar/states/currentViewIdScopedState';
|
import { currentViewIdScopedState } from '@/ui/view-bar/states/currentViewIdScopedState';
|
||||||
|
|
||||||
|
import { TableOptionsDropdownId } from '../../constants/TableOptionsDropdownId';
|
||||||
import { TableOptionsDropdown } from '../../options/components/TableOptionsDropdown';
|
import { TableOptionsDropdown } from '../../options/components/TableOptionsDropdown';
|
||||||
import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
|
import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||||
import { savedTableColumnsFamilyState } from '../../states/savedTableColumnsFamilyState';
|
import { savedTableColumnsFamilyState } from '../../states/savedTableColumnsFamilyState';
|
||||||
import { canPersistTableColumnsScopedFamilySelector } from '../../states/selectors/canPersistTableColumnsScopedFamilySelector';
|
import { canPersistTableColumnsScopedFamilySelector } from '../../states/selectors/canPersistTableColumnsScopedFamilySelector';
|
||||||
import { tableColumnsScopedState } from '../../states/tableColumnsScopedState';
|
import { tableColumnsScopedState } from '../../states/tableColumnsScopedState';
|
||||||
import { TableOptionsDropdownKey } from '../../types/TableOptionsDropdownKey';
|
|
||||||
import { TableOptionsHotkeyScope } from '../../types/TableOptionsHotkeyScope';
|
import { TableOptionsHotkeyScope } from '../../types/TableOptionsHotkeyScope';
|
||||||
|
|
||||||
export type TableHeaderProps<SortField> = {
|
export type TableHeaderProps = {
|
||||||
onImport?: () => void;
|
onImport?: () => void;
|
||||||
} & Pick<
|
} & Pick<ViewBarProps, 'defaultViewName' | 'onViewsChange' | 'onViewSubmit'>;
|
||||||
ViewBarProps<SortField>,
|
|
||||||
'availableSorts' | 'defaultViewName' | 'onViewsChange' | 'onViewSubmit'
|
|
||||||
>;
|
|
||||||
|
|
||||||
export function TableHeader<SortField>({
|
export function TableHeader({
|
||||||
onImport,
|
onImport,
|
||||||
onViewsChange,
|
onViewsChange,
|
||||||
onViewSubmit,
|
onViewSubmit,
|
||||||
...props
|
...props
|
||||||
}: TableHeaderProps<SortField>) {
|
}: TableHeaderProps) {
|
||||||
const tableScopeId = useContextScopeId(TableRecoilScopeContext);
|
const tableScopeId = useContextScopeId(TableRecoilScopeContext);
|
||||||
|
|
||||||
const currentViewId = useRecoilScopedValue(
|
const currentViewId = useRecoilScopedValue(
|
||||||
@ -84,7 +81,7 @@ export function TableHeader<SortField>({
|
|||||||
customHotkeyScope={{ scope: TableOptionsHotkeyScope.Dropdown }}
|
customHotkeyScope={{ scope: TableOptionsHotkeyScope.Dropdown }}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
optionsDropdownKey={TableOptionsDropdownKey}
|
optionsDropdownKey={TableOptionsDropdownId}
|
||||||
scopeContext={TableRecoilScopeContext}
|
scopeContext={TableRecoilScopeContext}
|
||||||
/>
|
/>
|
||||||
</RecoilScope>
|
</RecoilScope>
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
export const TableOptionsDropdownKey = 'table-options';
|
|
||||||
@ -2,11 +2,11 @@ import { LightButton } from '@/ui/button/components/LightButton';
|
|||||||
import { useDropdownButton } from '@/ui/dropdown/hooks/useDropdownButton';
|
import { useDropdownButton } from '@/ui/dropdown/hooks/useDropdownButton';
|
||||||
import { IconPlus } from '@/ui/icon';
|
import { IconPlus } from '@/ui/icon';
|
||||||
|
|
||||||
import { FilterDropdownKey } from '../types/FilterDropdownKey';
|
import { FilterDropdownId } from '../constants/FilterDropdownId';
|
||||||
|
|
||||||
export function AddFilterFromDropdownButton() {
|
export function AddFilterFromDropdownButton() {
|
||||||
const { toggleDropdownButton } = useDropdownButton({
|
const { toggleDropdownButton } = useDropdownButton({
|
||||||
key: FilterDropdownKey,
|
dropdownId: FilterDropdownId,
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleClick() {
|
function handleClick() {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { Context } from 'react';
|
import { Context } from 'react';
|
||||||
|
|
||||||
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||||
|
|
||||||
import { availableFiltersScopedState } from '../states/availableFiltersScopedState';
|
import { availableFiltersScopedState } from '../states/availableFiltersScopedState';
|
||||||
@ -9,12 +10,12 @@ import { SingleEntityFilterDropdownButton } from './SingleEntityFilterDropdownBu
|
|||||||
|
|
||||||
type FilterDropdownButtonProps = {
|
type FilterDropdownButtonProps = {
|
||||||
context: Context<string | null>;
|
context: Context<string | null>;
|
||||||
hotkeyScope: string;
|
hotkeyScope: HotkeyScope;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function FilterDropdownButton({
|
export function FilterDropdownButton({
|
||||||
context,
|
|
||||||
hotkeyScope,
|
hotkeyScope,
|
||||||
|
context,
|
||||||
}: FilterDropdownButtonProps) {
|
}: FilterDropdownButtonProps) {
|
||||||
const [availableFilters] = useRecoilScopedState(
|
const [availableFilters] = useRecoilScopedState(
|
||||||
availableFiltersScopedState,
|
availableFiltersScopedState,
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { StyledHeaderDropdownButton } from '@/ui/dropdown/components/StyledHeaderDropdownButton';
|
import { StyledHeaderDropdownButton } from '@/ui/dropdown/components/StyledHeaderDropdownButton';
|
||||||
import { useDropdownButton } from '@/ui/dropdown/hooks/useDropdownButton';
|
import { useDropdownButton } from '@/ui/dropdown/hooks/useDropdownButton';
|
||||||
|
|
||||||
import { FilterDropdownKey } from '../types/FilterDropdownKey';
|
import { FilterDropdownId } from '../constants/FilterDropdownId';
|
||||||
|
|
||||||
export function MultipleFiltersButton() {
|
export function MultipleFiltersButton() {
|
||||||
const { isDropdownButtonOpen, toggleDropdownButton } = useDropdownButton({
|
const { isDropdownButtonOpen, toggleDropdownButton } = useDropdownButton({
|
||||||
key: FilterDropdownKey,
|
dropdownId: FilterDropdownId,
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleClick() {
|
function handleClick() {
|
||||||
|
|||||||
@ -1,24 +1,27 @@
|
|||||||
import { Context, useCallback } from 'react';
|
import { Context, useCallback, useEffect } from 'react';
|
||||||
|
|
||||||
import { DropdownButton } from '@/ui/dropdown/components/DropdownButton';
|
import { DropdownButton } from '@/ui/dropdown/components/DropdownButton';
|
||||||
|
import { useDropdownButton } from '@/ui/dropdown/hooks/useDropdownButton';
|
||||||
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||||
|
|
||||||
|
import { FilterDropdownId } from '../constants/FilterDropdownId';
|
||||||
import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState';
|
import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState';
|
||||||
import { filterDropdownSearchInputScopedState } from '../states/filterDropdownSearchInputScopedState';
|
import { filterDropdownSearchInputScopedState } from '../states/filterDropdownSearchInputScopedState';
|
||||||
import { isFilterDropdownOperandSelectUnfoldedScopedState } from '../states/isFilterDropdownOperandSelectUnfoldedScopedState';
|
import { isFilterDropdownOperandSelectUnfoldedScopedState } from '../states/isFilterDropdownOperandSelectUnfoldedScopedState';
|
||||||
import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState';
|
import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState';
|
||||||
import { FilterDropdownKey } from '../types/FilterDropdownKey';
|
|
||||||
|
|
||||||
import { MultipleFiltersButton } from './MultipleFiltersButton';
|
import { MultipleFiltersButton } from './MultipleFiltersButton';
|
||||||
import { MultipleFiltersDropdownContent } from './MultipleFiltersDropdownContent';
|
import { MultipleFiltersDropdownContent } from './MultipleFiltersDropdownContent';
|
||||||
|
|
||||||
type MultipleFiltersDropdownButtonProps = {
|
type MultipleFiltersDropdownButtonProps = {
|
||||||
context: Context<string | null>;
|
context: Context<string | null>;
|
||||||
hotkeyScope: string;
|
hotkeyScope: HotkeyScope;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function MultipleFiltersDropdownButton({
|
export function MultipleFiltersDropdownButton({
|
||||||
context,
|
context,
|
||||||
|
hotkeyScope,
|
||||||
}: MultipleFiltersDropdownButtonProps) {
|
}: MultipleFiltersDropdownButtonProps) {
|
||||||
const [, setIsFilterDropdownOperandSelectUnfolded] = useRecoilScopedState(
|
const [, setIsFilterDropdownOperandSelectUnfolded] = useRecoilScopedState(
|
||||||
isFilterDropdownOperandSelectUnfoldedScopedState,
|
isFilterDropdownOperandSelectUnfoldedScopedState,
|
||||||
@ -40,6 +43,10 @@ export function MultipleFiltersDropdownButton({
|
|||||||
context,
|
context,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { isDropdownButtonOpen } = useDropdownButton({
|
||||||
|
dropdownId: FilterDropdownId,
|
||||||
|
});
|
||||||
|
|
||||||
const resetState = useCallback(() => {
|
const resetState = useCallback(() => {
|
||||||
setIsFilterDropdownOperandSelectUnfolded(false);
|
setIsFilterDropdownOperandSelectUnfolded(false);
|
||||||
setFilterDefinitionUsedInDropdown(null);
|
setFilterDefinitionUsedInDropdown(null);
|
||||||
@ -51,14 +58,19 @@ export function MultipleFiltersDropdownButton({
|
|||||||
setFilterDropdownSearchInput,
|
setFilterDropdownSearchInput,
|
||||||
setIsFilterDropdownOperandSelectUnfolded,
|
setIsFilterDropdownOperandSelectUnfolded,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isDropdownButtonOpen) {
|
||||||
|
resetState();
|
||||||
|
}
|
||||||
|
}, [isDropdownButtonOpen, resetState]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
dropdownKey={FilterDropdownKey}
|
dropdownId={FilterDropdownId}
|
||||||
buttonComponents={<MultipleFiltersButton />}
|
buttonComponents={<MultipleFiltersButton />}
|
||||||
dropdownComponents={<MultipleFiltersDropdownContent context={context} />}
|
dropdownComponents={<MultipleFiltersDropdownContent context={context} />}
|
||||||
onDropdownToggle={() => {
|
dropdownHotkeyScope={hotkeyScope}
|
||||||
resetState();
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,6 +39,8 @@ export function MultipleFiltersDropdownContent({
|
|||||||
context,
|
context,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log('filterDefinitionUsedInDropdown', filterDefinitionUsedInDropdown);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledDropdownMenu>
|
<StyledDropdownMenu>
|
||||||
<>
|
<>
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import styled from '@emotion/styled';
|
|||||||
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
||||||
import { IconChevronDown } from '@/ui/icon';
|
import { IconChevronDown } from '@/ui/icon';
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||||
import { filterDefinitionUsedInDropdownScopedState } from '@/ui/view-bar/states/filterDefinitionUsedInDropdownScopedState';
|
import { filterDefinitionUsedInDropdownScopedState } from '@/ui/view-bar/states/filterDefinitionUsedInDropdownScopedState';
|
||||||
import { filterDropdownSearchInputScopedState } from '@/ui/view-bar/states/filterDropdownSearchInputScopedState';
|
import { filterDropdownSearchInputScopedState } from '@/ui/view-bar/states/filterDropdownSearchInputScopedState';
|
||||||
@ -33,7 +34,7 @@ export function SingleEntityFilterDropdownButton({
|
|||||||
hotkeyScope,
|
hotkeyScope,
|
||||||
}: {
|
}: {
|
||||||
context: Context<string | null>;
|
context: Context<string | null>;
|
||||||
hotkeyScope: string;
|
hotkeyScope: HotkeyScope;
|
||||||
}) {
|
}) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
@ -80,10 +81,10 @@ export function SingleEntityFilterDropdownButton({
|
|||||||
|
|
||||||
function handleIsUnfoldedChange(newIsUnfolded: boolean) {
|
function handleIsUnfoldedChange(newIsUnfolded: boolean) {
|
||||||
if (newIsUnfolded) {
|
if (newIsUnfolded) {
|
||||||
setHotkeyScope(hotkeyScope);
|
setHotkeyScope(hotkeyScope.scope, hotkeyScope.customScopes);
|
||||||
setIsFilterDropdownUnfolded(true);
|
setIsFilterDropdownUnfolded(true);
|
||||||
} else {
|
} else {
|
||||||
setHotkeyScope(hotkeyScope);
|
setHotkeyScope(hotkeyScope.scope, hotkeyScope.customScopes);
|
||||||
setIsFilterDropdownUnfolded(false);
|
setIsFilterDropdownUnfolded(false);
|
||||||
setFilterDropdownSearchInput('');
|
setFilterDropdownSearchInput('');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,120 +1,136 @@
|
|||||||
import { Context, useCallback, useState } from 'react';
|
import { Context, useCallback, useState } from 'react';
|
||||||
|
import { produce } from 'immer';
|
||||||
|
|
||||||
|
import { LightButton } from '@/ui/button/components/LightButton';
|
||||||
|
import { DropdownButton } from '@/ui/dropdown/components/DropdownButton';
|
||||||
import { DropdownMenuHeader } from '@/ui/dropdown/components/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/dropdown/components/DropdownMenuHeader';
|
||||||
|
import { StyledDropdownMenu } from '@/ui/dropdown/components/StyledDropdownMenu';
|
||||||
import { StyledDropdownMenuItemsContainer } from '@/ui/dropdown/components/StyledDropdownMenuItemsContainer';
|
import { StyledDropdownMenuItemsContainer } from '@/ui/dropdown/components/StyledDropdownMenuItemsContainer';
|
||||||
import { StyledDropdownMenuSeparator } from '@/ui/dropdown/components/StyledDropdownMenuSeparator';
|
import { StyledDropdownMenuSeparator } from '@/ui/dropdown/components/StyledDropdownMenuSeparator';
|
||||||
|
import { useDropdownButton } from '@/ui/dropdown/hooks/useDropdownButton';
|
||||||
import { IconChevronDown } from '@/ui/icon';
|
import { IconChevronDown } from '@/ui/icon';
|
||||||
import { MenuItem } from '@/ui/menu-item/components/MenuItem';
|
import { MenuItem } from '@/ui/menu-item/components/MenuItem';
|
||||||
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||||
|
|
||||||
|
import { SortDropdownId } from '../constants/SortDropdownId';
|
||||||
|
import { availableSortsScopedState } from '../states/availableSortsScopedState';
|
||||||
import { sortsScopedState } from '../states/sortsScopedState';
|
import { sortsScopedState } from '../states/sortsScopedState';
|
||||||
import { FiltersHotkeyScope } from '../types/FiltersHotkeyScope';
|
import { SortDefinition } from '../types/SortDefinition';
|
||||||
import { SelectedSortType, SortType } from '../types/interface';
|
import { SORT_DIRECTIONS, SortDirection } from '../types/SortDirection';
|
||||||
|
|
||||||
import DropdownButton from './DropdownButton';
|
export type SortDropdownButtonProps = {
|
||||||
|
|
||||||
export type SortDropdownButtonProps<SortField> = {
|
|
||||||
availableSorts: SortType<SortField>[];
|
|
||||||
hotkeyScope: FiltersHotkeyScope;
|
|
||||||
context: Context<string | null>;
|
context: Context<string | null>;
|
||||||
|
hotkeyScope: HotkeyScope;
|
||||||
isPrimaryButton?: boolean;
|
isPrimaryButton?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const options: Array<SelectedSortType<any>['order']> = ['asc', 'desc'];
|
export function SortDropdownButton({
|
||||||
|
|
||||||
export function SortDropdownButton<SortField>({
|
|
||||||
context,
|
|
||||||
availableSorts,
|
|
||||||
hotkeyScope,
|
hotkeyScope,
|
||||||
}: SortDropdownButtonProps<SortField>) {
|
context,
|
||||||
const [isUnfolded, setIsUnfolded] = useState(false);
|
}: SortDropdownButtonProps) {
|
||||||
const [isOptionUnfolded, setIsOptionUnfolded] = useState(false);
|
const [isSortDirectionMenuUnfolded, setIsSortDirectionMenuUnfolded] =
|
||||||
|
useState(false);
|
||||||
|
|
||||||
const [selectedSortDirection, setSelectedSortDirection] =
|
const [selectedSortDirection, setSelectedSortDirection] =
|
||||||
useState<SelectedSortType<SortField>['order']>('asc');
|
useState<SortDirection>('asc');
|
||||||
|
|
||||||
const [sorts, setSorts] = useRecoilScopedState<SelectedSortType<SortField>[]>(
|
|
||||||
sortsScopedState,
|
|
||||||
context,
|
|
||||||
);
|
|
||||||
|
|
||||||
const isSortSelected = sorts.length > 0;
|
|
||||||
|
|
||||||
const onSortItemSelect = useCallback(
|
|
||||||
(sort: SortType<SortField>) => {
|
|
||||||
const newSort = { ...sort, order: selectedSortDirection };
|
|
||||||
const sortIndex = sorts.findIndex((sort) => sort.key === newSort.key);
|
|
||||||
const newSorts = [...sorts];
|
|
||||||
|
|
||||||
if (sortIndex !== -1) {
|
|
||||||
newSorts[sortIndex] = newSort;
|
|
||||||
} else {
|
|
||||||
newSorts.push(newSort);
|
|
||||||
}
|
|
||||||
|
|
||||||
setSorts(newSorts);
|
|
||||||
},
|
|
||||||
[selectedSortDirection, setSorts, sorts],
|
|
||||||
);
|
|
||||||
|
|
||||||
const resetState = useCallback(() => {
|
const resetState = useCallback(() => {
|
||||||
setIsOptionUnfolded(false);
|
setIsSortDirectionMenuUnfolded(false);
|
||||||
setSelectedSortDirection('asc');
|
setSelectedSortDirection('asc');
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
function handleIsUnfoldedChange(newIsUnfolded: boolean) {
|
const [availableSorts] = useRecoilScopedState(
|
||||||
setIsUnfolded(newIsUnfolded);
|
availableSortsScopedState,
|
||||||
if (!newIsUnfolded) resetState();
|
context,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [sorts, setSorts] = useRecoilScopedState(sortsScopedState, context);
|
||||||
|
|
||||||
|
const isSortSelected = sorts.length > 0;
|
||||||
|
|
||||||
|
const { toggleDropdownButton } = useDropdownButton({
|
||||||
|
dropdownId: SortDropdownId,
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleButtonClick() {
|
||||||
|
toggleDropdownButton();
|
||||||
|
resetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAddSort(sort: SortType<SortField>) {
|
function handleAddSort(selectedSortDefinition: SortDefinition) {
|
||||||
setIsUnfolded(false);
|
toggleDropdownButton();
|
||||||
onSortItemSelect(sort);
|
|
||||||
|
setSorts(
|
||||||
|
produce(sorts, (existingSortsDraft) => {
|
||||||
|
const foundExistingSortIndex = existingSortsDraft.findIndex(
|
||||||
|
(existingSort) => existingSort.key === selectedSortDefinition.key,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (foundExistingSortIndex !== -1) {
|
||||||
|
existingSortsDraft[foundExistingSortIndex].direction =
|
||||||
|
selectedSortDirection;
|
||||||
|
} else {
|
||||||
|
existingSortsDraft.push({
|
||||||
|
key: selectedSortDefinition.key,
|
||||||
|
direction: selectedSortDirection,
|
||||||
|
definition: selectedSortDefinition,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
label="Sort"
|
dropdownId={SortDropdownId}
|
||||||
isActive={isSortSelected}
|
dropdownHotkeyScope={hotkeyScope}
|
||||||
isUnfolded={isUnfolded}
|
buttonComponents={
|
||||||
onIsUnfoldedChange={handleIsUnfoldedChange}
|
<LightButton
|
||||||
hotkeyScope={hotkeyScope}
|
title="Sort"
|
||||||
>
|
active={isSortSelected}
|
||||||
{isOptionUnfolded ? (
|
onClick={handleButtonClick}
|
||||||
<StyledDropdownMenuItemsContainer>
|
/>
|
||||||
{options.map((option, index) => (
|
}
|
||||||
<MenuItem
|
dropdownComponents={
|
||||||
key={index}
|
<StyledDropdownMenu>
|
||||||
onClick={() => {
|
{isSortDirectionMenuUnfolded ? (
|
||||||
setSelectedSortDirection(option);
|
<StyledDropdownMenuItemsContainer>
|
||||||
setIsOptionUnfolded(false);
|
{SORT_DIRECTIONS.map((sortOrder, index) => (
|
||||||
}}
|
<MenuItem
|
||||||
text={option === 'asc' ? 'Ascending' : 'Descending'}
|
key={index}
|
||||||
/>
|
onClick={() => {
|
||||||
))}
|
setSelectedSortDirection(sortOrder);
|
||||||
</StyledDropdownMenuItemsContainer>
|
setIsSortDirectionMenuUnfolded(false);
|
||||||
) : (
|
}}
|
||||||
<>
|
text={sortOrder === 'asc' ? 'Ascending' : 'Descending'}
|
||||||
<DropdownMenuHeader
|
/>
|
||||||
EndIcon={IconChevronDown}
|
))}
|
||||||
onClick={() => setIsOptionUnfolded(true)}
|
</StyledDropdownMenuItemsContainer>
|
||||||
>
|
) : (
|
||||||
{selectedSortDirection === 'asc' ? 'Ascending' : 'Descending'}
|
<>
|
||||||
</DropdownMenuHeader>
|
<DropdownMenuHeader
|
||||||
<StyledDropdownMenuSeparator />
|
EndIcon={IconChevronDown}
|
||||||
|
onClick={() => setIsSortDirectionMenuUnfolded(true)}
|
||||||
<StyledDropdownMenuItemsContainer>
|
>
|
||||||
{availableSorts.map((sort, index) => (
|
{selectedSortDirection === 'asc' ? 'Ascending' : 'Descending'}
|
||||||
<MenuItem
|
</DropdownMenuHeader>
|
||||||
testId={`select-sort-${index}`}
|
<StyledDropdownMenuSeparator />
|
||||||
key={index}
|
<StyledDropdownMenuItemsContainer>
|
||||||
onClick={() => handleAddSort(sort)}
|
{availableSorts.map((availableSort, index) => (
|
||||||
LeftIcon={sort.Icon}
|
<MenuItem
|
||||||
text={sort.label}
|
testId={`select-sort-${index}`}
|
||||||
/>
|
key={index}
|
||||||
))}
|
onClick={() => handleAddSort(availableSort)}
|
||||||
</StyledDropdownMenuItemsContainer>
|
LeftIcon={availableSort.Icon}
|
||||||
</>
|
text={availableSort.label}
|
||||||
)}
|
/>
|
||||||
</DropdownButton>
|
))}
|
||||||
|
</StyledDropdownMenuItemsContainer>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</StyledDropdownMenu>
|
||||||
|
}
|
||||||
|
></DropdownButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,10 +7,7 @@ import { FiltersHotkeyScope } from '../types/FiltersHotkeyScope';
|
|||||||
import { ViewsHotkeyScope } from '../types/ViewsHotkeyScope';
|
import { ViewsHotkeyScope } from '../types/ViewsHotkeyScope';
|
||||||
|
|
||||||
import { FilterDropdownButton } from './FilterDropdownButton';
|
import { FilterDropdownButton } from './FilterDropdownButton';
|
||||||
import {
|
import { SortDropdownButton } from './SortDropdownButton';
|
||||||
SortDropdownButton,
|
|
||||||
type SortDropdownButtonProps,
|
|
||||||
} from './SortDropdownButton';
|
|
||||||
import {
|
import {
|
||||||
UpdateViewButtonGroup,
|
UpdateViewButtonGroup,
|
||||||
type UpdateViewButtonGroupProps,
|
type UpdateViewButtonGroupProps,
|
||||||
@ -21,7 +18,7 @@ import {
|
|||||||
type ViewsDropdownButtonProps,
|
type ViewsDropdownButtonProps,
|
||||||
} from './ViewsDropdownButton';
|
} from './ViewsDropdownButton';
|
||||||
|
|
||||||
export type ViewBarProps<SortField> = ComponentProps<'div'> & {
|
export type ViewBarProps = ComponentProps<'div'> & {
|
||||||
optionsDropdownButton: ReactNode;
|
optionsDropdownButton: ReactNode;
|
||||||
optionsDropdownKey: string;
|
optionsDropdownKey: string;
|
||||||
scopeContext: Context<string | null>;
|
scopeContext: Context<string | null>;
|
||||||
@ -29,12 +26,10 @@ export type ViewBarProps<SortField> = ComponentProps<'div'> & {
|
|||||||
ViewsDropdownButtonProps,
|
ViewsDropdownButtonProps,
|
||||||
'defaultViewName' | 'onViewsChange' | 'onViewSelect'
|
'defaultViewName' | 'onViewsChange' | 'onViewSelect'
|
||||||
> &
|
> &
|
||||||
Pick<SortDropdownButtonProps<SortField>, 'availableSorts'> &
|
|
||||||
Pick<ViewBarDetailsProps, 'canPersistViewFields' | 'onReset'> &
|
Pick<ViewBarDetailsProps, 'canPersistViewFields' | 'onReset'> &
|
||||||
Pick<UpdateViewButtonGroupProps, 'onViewSubmit'>;
|
Pick<UpdateViewButtonGroupProps, 'onViewSubmit'>;
|
||||||
|
|
||||||
export const ViewBar = <SortField,>({
|
export const ViewBar = ({
|
||||||
availableSorts,
|
|
||||||
canPersistViewFields,
|
canPersistViewFields,
|
||||||
defaultViewName,
|
defaultViewName,
|
||||||
onReset,
|
onReset,
|
||||||
@ -45,9 +40,9 @@ export const ViewBar = <SortField,>({
|
|||||||
optionsDropdownKey,
|
optionsDropdownKey,
|
||||||
scopeContext,
|
scopeContext,
|
||||||
...props
|
...props
|
||||||
}: ViewBarProps<SortField>) => {
|
}: ViewBarProps) => {
|
||||||
const { openDropdownButton: openOptionsDropdownButton } = useDropdownButton({
|
const { openDropdownButton: openOptionsDropdownButton } = useDropdownButton({
|
||||||
key: optionsDropdownKey,
|
dropdownId: optionsDropdownKey,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -67,13 +62,12 @@ export const ViewBar = <SortField,>({
|
|||||||
rightComponent={
|
rightComponent={
|
||||||
<>
|
<>
|
||||||
<FilterDropdownButton
|
<FilterDropdownButton
|
||||||
|
hotkeyScope={{ scope: FiltersHotkeyScope.FilterDropdownButton }}
|
||||||
context={scopeContext}
|
context={scopeContext}
|
||||||
hotkeyScope={FiltersHotkeyScope.FilterDropdownButton}
|
|
||||||
/>
|
/>
|
||||||
<SortDropdownButton<SortField>
|
<SortDropdownButton
|
||||||
context={scopeContext}
|
context={scopeContext}
|
||||||
availableSorts={availableSorts}
|
hotkeyScope={{ scope: FiltersHotkeyScope.FilterDropdownButton }}
|
||||||
hotkeyScope={FiltersHotkeyScope.FilterDropdownButton}
|
|
||||||
isPrimaryButton
|
isPrimaryButton
|
||||||
/>
|
/>
|
||||||
{optionsDropdownButton}
|
{optionsDropdownButton}
|
||||||
|
|||||||
@ -15,7 +15,6 @@ import { isViewBarExpandedScopedState } from '../states/isViewBarExpandedScopedS
|
|||||||
import { canPersistFiltersScopedFamilySelector } from '../states/selectors/canPersistFiltersScopedFamilySelector';
|
import { canPersistFiltersScopedFamilySelector } from '../states/selectors/canPersistFiltersScopedFamilySelector';
|
||||||
import { canPersistSortsScopedFamilySelector } from '../states/selectors/canPersistSortsScopedFamilySelector';
|
import { canPersistSortsScopedFamilySelector } from '../states/selectors/canPersistSortsScopedFamilySelector';
|
||||||
import { sortsScopedState } from '../states/sortsScopedState';
|
import { sortsScopedState } from '../states/sortsScopedState';
|
||||||
import { SelectedSortType } from '../types/interface';
|
|
||||||
import { getOperandLabelShort } from '../utils/getOperandLabel';
|
import { getOperandLabelShort } from '../utils/getOperandLabel';
|
||||||
|
|
||||||
import { AddFilterFromDropdownButton } from './AddFilterFromDetailsButton';
|
import { AddFilterFromDropdownButton } from './AddFilterFromDetailsButton';
|
||||||
@ -97,7 +96,7 @@ const StyledAddFilterContainer = styled.div`
|
|||||||
z-index: 5;
|
z-index: 5;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function ViewBarDetails<SortField>({
|
function ViewBarDetails({
|
||||||
canPersistViewFields,
|
canPersistViewFields,
|
||||||
context,
|
context,
|
||||||
hasFilterButton = false,
|
hasFilterButton = false,
|
||||||
@ -120,10 +119,8 @@ function ViewBarDetails<SortField>({
|
|||||||
canPersistFiltersScopedFamilySelector([recoilScopeId, currentViewId]),
|
canPersistFiltersScopedFamilySelector([recoilScopeId, currentViewId]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const [sorts, setSorts] = useRecoilScopedState<SelectedSortType<SortField>[]>(
|
const [sorts, setSorts] = useRecoilScopedState(sortsScopedState, context);
|
||||||
sortsScopedState,
|
|
||||||
context,
|
|
||||||
);
|
|
||||||
const canPersistSorts = useRecoilValue(
|
const canPersistSorts = useRecoilValue(
|
||||||
canPersistSortsScopedFamilySelector([recoilScopeId, currentViewId]),
|
canPersistSortsScopedFamilySelector([recoilScopeId, currentViewId]),
|
||||||
);
|
);
|
||||||
@ -177,9 +174,9 @@ function ViewBarDetails<SortField>({
|
|||||||
<SortOrFilterChip
|
<SortOrFilterChip
|
||||||
key={sort.key}
|
key={sort.key}
|
||||||
testId={sort.key}
|
testId={sort.key}
|
||||||
labelValue={sort.label}
|
labelValue={sort.definition.label}
|
||||||
Icon={
|
Icon={
|
||||||
sort.order === 'desc'
|
sort.direction === 'desc'
|
||||||
? IconArrowNarrowDown
|
? IconArrowNarrowDown
|
||||||
: IconArrowNarrowUp
|
: IconArrowNarrowUp
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
export const FilterDropdownId = 'filter';
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export const SortDropdownId = 'sort-dropdown';
|
||||||
@ -1,17 +0,0 @@
|
|||||||
import { SortOrder as Order_By } from '~/generated/graphql';
|
|
||||||
|
|
||||||
import { SelectedSortType } from './types/interface';
|
|
||||||
|
|
||||||
export const reduceSortsToOrderBy = <OrderByTemplate>(
|
|
||||||
sorts: SelectedSortType<OrderByTemplate>[],
|
|
||||||
): OrderByTemplate[] =>
|
|
||||||
sorts
|
|
||||||
.map((sort) => {
|
|
||||||
const order = sort.order === 'asc' ? Order_By.Asc : Order_By.Desc;
|
|
||||||
return (
|
|
||||||
sort.orderByTemplate?.(order) || [
|
|
||||||
{ [sort.key]: order } as OrderByTemplate,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.flat();
|
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
import { atomFamily } from 'recoil';
|
||||||
|
|
||||||
|
import { SortDefinition } from '../types/SortDefinition';
|
||||||
|
|
||||||
|
export const availableSortsScopedState = atomFamily<SortDefinition[], string>({
|
||||||
|
key: 'availableSortsScopedState',
|
||||||
|
default: [],
|
||||||
|
});
|
||||||
@ -1,11 +1,8 @@
|
|||||||
import { atomFamily } from 'recoil';
|
import { atomFamily } from 'recoil';
|
||||||
|
|
||||||
import type { SelectedSortType } from '../types/interface';
|
import { Sort } from '../types/Sort';
|
||||||
|
|
||||||
export const savedSortsFamilyState = atomFamily<
|
export const savedSortsFamilyState = atomFamily<Sort[], string | undefined>({
|
||||||
SelectedSortType<any>[],
|
|
||||||
string | undefined
|
|
||||||
>({
|
|
||||||
key: 'savedSortsFamilyState',
|
key: 'savedSortsFamilyState',
|
||||||
default: [],
|
default: [],
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { selectorFamily } from 'recoil';
|
import { selectorFamily } from 'recoil';
|
||||||
|
|
||||||
import type { SelectedSortType } from '../../types/interface';
|
import { Sort } from '../../types/Sort';
|
||||||
import { savedSortsFamilyState } from '../savedSortsFamilyState';
|
import { savedSortsFamilyState } from '../savedSortsFamilyState';
|
||||||
|
|
||||||
export const savedSortsByKeyFamilySelector = selectorFamily({
|
export const savedSortsByKeyFamilySelector = selectorFamily({
|
||||||
@ -8,7 +8,8 @@ export const savedSortsByKeyFamilySelector = selectorFamily({
|
|||||||
get:
|
get:
|
||||||
(viewId: string | undefined) =>
|
(viewId: string | undefined) =>
|
||||||
({ get }) =>
|
({ get }) =>
|
||||||
get(savedSortsFamilyState(viewId)).reduce<
|
get(savedSortsFamilyState(viewId)).reduce<Record<string, Sort>>(
|
||||||
Record<string, SelectedSortType<any>>
|
(result, sort) => ({ ...result, [sort.key]: sort }),
|
||||||
>((result, sort) => ({ ...result, [sort.key]: sort }), {}),
|
{},
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { selectorFamily } from 'recoil';
|
|||||||
|
|
||||||
import { SortOrder } from '~/generated/graphql';
|
import { SortOrder } from '~/generated/graphql';
|
||||||
|
|
||||||
import { reduceSortsToOrderBy } from '../../helpers';
|
import { reduceSortsToOrderBy } from '../../utils/helpers';
|
||||||
import { sortsScopedState } from '../sortsScopedState';
|
import { sortsScopedState } from '../sortsScopedState';
|
||||||
|
|
||||||
export const sortsOrderByScopedSelector = selectorFamily({
|
export const sortsOrderByScopedSelector = selectorFamily({
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { atomFamily } from 'recoil';
|
import { atomFamily } from 'recoil';
|
||||||
|
|
||||||
import type { SelectedSortType } from '../types/interface';
|
import { Sort } from '../types/Sort';
|
||||||
|
|
||||||
export const sortsScopedState = atomFamily<SelectedSortType<any>[], string>({
|
export const sortsScopedState = atomFamily<Sort[], string>({
|
||||||
key: 'sortsScopedState',
|
key: 'sortsScopedState',
|
||||||
default: [],
|
default: [],
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
export const FilterDropdownKey = 'filter';
|
|
||||||
8
front/src/modules/ui/view-bar/types/Sort.ts
Normal file
8
front/src/modules/ui/view-bar/types/Sort.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { SortDefinition } from './SortDefinition';
|
||||||
|
import { SortDirection } from './SortDirection';
|
||||||
|
|
||||||
|
export type Sort = {
|
||||||
|
key: string;
|
||||||
|
direction: SortDirection;
|
||||||
|
definition: SortDefinition;
|
||||||
|
};
|
||||||
10
front/src/modules/ui/view-bar/types/SortDefinition.ts
Normal file
10
front/src/modules/ui/view-bar/types/SortDefinition.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { IconComponent } from '@/ui/icon/types/IconComponent';
|
||||||
|
|
||||||
|
import { SortDirection } from './SortDirection';
|
||||||
|
|
||||||
|
export type SortDefinition = {
|
||||||
|
key: string;
|
||||||
|
label: string;
|
||||||
|
Icon?: IconComponent;
|
||||||
|
getOrderByTemplate?: (direction: SortDirection) => any[];
|
||||||
|
};
|
||||||
3
front/src/modules/ui/view-bar/types/SortDirection.ts
Normal file
3
front/src/modules/ui/view-bar/types/SortDirection.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const SORT_DIRECTIONS = ['asc', 'desc'] as const;
|
||||||
|
|
||||||
|
export type SortDirection = (typeof SORT_DIRECTIONS)[number];
|
||||||
16
front/src/modules/ui/view-bar/utils/helpers.ts
Normal file
16
front/src/modules/ui/view-bar/utils/helpers.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { SortOrder as Order_By } from '~/generated/graphql';
|
||||||
|
|
||||||
|
import { Sort } from '../types/Sort';
|
||||||
|
|
||||||
|
export const reduceSortsToOrderBy = (sorts: Sort[]): any[] =>
|
||||||
|
sorts
|
||||||
|
.map((sort) => {
|
||||||
|
const direction = sort.direction === 'asc' ? Order_By.Asc : Order_By.Desc;
|
||||||
|
|
||||||
|
if (sort.definition.getOrderByTemplate) {
|
||||||
|
return sort.definition.getOrderByTemplate(direction);
|
||||||
|
} else {
|
||||||
|
return [{ [sort.definition.key]: direction }];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.flat();
|
||||||
@ -7,8 +7,6 @@ import type {
|
|||||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||||
import { filtersScopedState } from '@/ui/view-bar/states/filtersScopedState';
|
import { filtersScopedState } from '@/ui/view-bar/states/filtersScopedState';
|
||||||
import { sortsScopedState } from '@/ui/view-bar/states/sortsScopedState';
|
import { sortsScopedState } from '@/ui/view-bar/states/sortsScopedState';
|
||||||
import type { FilterDefinitionByEntity } from '@/ui/view-bar/types/FilterDefinitionByEntity';
|
|
||||||
import type { SortType } from '@/ui/view-bar/types/interface';
|
|
||||||
import { ViewType } from '~/generated/graphql';
|
import { ViewType } from '~/generated/graphql';
|
||||||
|
|
||||||
import { useBoardViewFields } from './useBoardViewFields';
|
import { useBoardViewFields } from './useBoardViewFields';
|
||||||
@ -16,15 +14,11 @@ import { useViewFilters } from './useViewFilters';
|
|||||||
import { useViews } from './useViews';
|
import { useViews } from './useViews';
|
||||||
import { useViewSorts } from './useViewSorts';
|
import { useViewSorts } from './useViewSorts';
|
||||||
|
|
||||||
export const useBoardViews = <Entity, SortField>({
|
export const useBoardViews = ({
|
||||||
availableFilters,
|
|
||||||
availableSorts,
|
|
||||||
fieldDefinitions,
|
fieldDefinitions,
|
||||||
objectId,
|
objectId,
|
||||||
scopeContext,
|
scopeContext,
|
||||||
}: {
|
}: {
|
||||||
availableFilters: FilterDefinitionByEntity<Entity>[];
|
|
||||||
availableSorts: SortType<SortField>[];
|
|
||||||
fieldDefinitions: ViewFieldDefinition<ViewFieldMetadata>[];
|
fieldDefinitions: ViewFieldDefinition<ViewFieldMetadata>[];
|
||||||
objectId: 'company';
|
objectId: 'company';
|
||||||
scopeContext: Context<string | null>;
|
scopeContext: Context<string | null>;
|
||||||
@ -38,19 +32,20 @@ export const useBoardViews = <Entity, SortField>({
|
|||||||
type: ViewType.Pipeline,
|
type: ViewType.Pipeline,
|
||||||
scopeContext,
|
scopeContext,
|
||||||
});
|
});
|
||||||
|
|
||||||
useBoardViewFields({
|
useBoardViewFields({
|
||||||
objectId,
|
objectId,
|
||||||
fieldDefinitions,
|
fieldDefinitions,
|
||||||
scopeContext,
|
scopeContext,
|
||||||
skipFetch: isFetchingViews,
|
skipFetch: isFetchingViews,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { createViewFilters, persistFilters } = useViewFilters({
|
const { createViewFilters, persistFilters } = useViewFilters({
|
||||||
availableFilters,
|
|
||||||
scopeContext,
|
scopeContext,
|
||||||
skipFetch: isFetchingViews,
|
skipFetch: isFetchingViews,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { createViewSorts, persistSorts } = useViewSorts({
|
const { createViewSorts, persistSorts } = useViewSorts({
|
||||||
availableSorts,
|
|
||||||
scopeContext,
|
scopeContext,
|
||||||
skipFetch: isFetchingViews,
|
skipFetch: isFetchingViews,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -5,8 +5,6 @@ import type { ColumnDefinition } from '@/ui/table/types/ColumnDefinition';
|
|||||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||||
import { filtersScopedState } from '@/ui/view-bar/states/filtersScopedState';
|
import { filtersScopedState } from '@/ui/view-bar/states/filtersScopedState';
|
||||||
import { sortsScopedState } from '@/ui/view-bar/states/sortsScopedState';
|
import { sortsScopedState } from '@/ui/view-bar/states/sortsScopedState';
|
||||||
import type { FilterDefinitionByEntity } from '@/ui/view-bar/types/FilterDefinitionByEntity';
|
|
||||||
import type { SortType } from '@/ui/view-bar/types/interface';
|
|
||||||
import { ViewType } from '~/generated/graphql';
|
import { ViewType } from '~/generated/graphql';
|
||||||
|
|
||||||
import { useTableViewFields } from './useTableViewFields';
|
import { useTableViewFields } from './useTableViewFields';
|
||||||
@ -14,14 +12,10 @@ import { useViewFilters } from './useViewFilters';
|
|||||||
import { useViews } from './useViews';
|
import { useViews } from './useViews';
|
||||||
import { useViewSorts } from './useViewSorts';
|
import { useViewSorts } from './useViewSorts';
|
||||||
|
|
||||||
export const useTableViews = <Entity, SortField>({
|
export const useTableViews = ({
|
||||||
availableFilters,
|
|
||||||
availableSorts,
|
|
||||||
objectId,
|
objectId,
|
||||||
columnDefinitions,
|
columnDefinitions,
|
||||||
}: {
|
}: {
|
||||||
availableFilters: FilterDefinitionByEntity<Entity>[];
|
|
||||||
availableSorts: SortType<SortField>[];
|
|
||||||
objectId: 'company' | 'person';
|
objectId: 'company' | 'person';
|
||||||
columnDefinitions: ColumnDefinition<ViewFieldMetadata>[];
|
columnDefinitions: ColumnDefinition<ViewFieldMetadata>[];
|
||||||
}) => {
|
}) => {
|
||||||
@ -47,12 +41,10 @@ export const useTableViews = <Entity, SortField>({
|
|||||||
skipFetch: isFetchingViews,
|
skipFetch: isFetchingViews,
|
||||||
});
|
});
|
||||||
const { createViewFilters, persistFilters } = useViewFilters({
|
const { createViewFilters, persistFilters } = useViewFilters({
|
||||||
availableFilters,
|
|
||||||
scopeContext: TableRecoilScopeContext,
|
scopeContext: TableRecoilScopeContext,
|
||||||
skipFetch: isFetchingViews,
|
skipFetch: isFetchingViews,
|
||||||
});
|
});
|
||||||
const { createViewSorts, persistSorts } = useViewSorts({
|
const { createViewSorts, persistSorts } = useViewSorts({
|
||||||
availableSorts,
|
|
||||||
scopeContext: TableRecoilScopeContext,
|
scopeContext: TableRecoilScopeContext,
|
||||||
skipFetch: isFetchingViews,
|
skipFetch: isFetchingViews,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -3,12 +3,12 @@ import { useRecoilState, useRecoilValue } from 'recoil';
|
|||||||
|
|
||||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||||
|
import { availableFiltersScopedState } from '@/ui/view-bar/states/availableFiltersScopedState';
|
||||||
import { currentViewIdScopedState } from '@/ui/view-bar/states/currentViewIdScopedState';
|
import { currentViewIdScopedState } from '@/ui/view-bar/states/currentViewIdScopedState';
|
||||||
import { filtersScopedState } from '@/ui/view-bar/states/filtersScopedState';
|
import { filtersScopedState } from '@/ui/view-bar/states/filtersScopedState';
|
||||||
import { savedFiltersFamilyState } from '@/ui/view-bar/states/savedFiltersFamilyState';
|
import { savedFiltersFamilyState } from '@/ui/view-bar/states/savedFiltersFamilyState';
|
||||||
import { savedFiltersByKeyFamilySelector } from '@/ui/view-bar/states/selectors/savedFiltersByKeyFamilySelector';
|
import { savedFiltersByKeyFamilySelector } from '@/ui/view-bar/states/selectors/savedFiltersByKeyFamilySelector';
|
||||||
import type { Filter } from '@/ui/view-bar/types/Filter';
|
import type { Filter } from '@/ui/view-bar/types/Filter';
|
||||||
import type { FilterDefinitionByEntity } from '@/ui/view-bar/types/FilterDefinitionByEntity';
|
|
||||||
import {
|
import {
|
||||||
useCreateViewFiltersMutation,
|
useCreateViewFiltersMutation,
|
||||||
useDeleteViewFiltersMutation,
|
useDeleteViewFiltersMutation,
|
||||||
@ -17,12 +17,10 @@ import {
|
|||||||
} from '~/generated/graphql';
|
} from '~/generated/graphql';
|
||||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
|
|
||||||
export const useViewFilters = <Entity>({
|
export const useViewFilters = ({
|
||||||
availableFilters,
|
|
||||||
scopeContext,
|
scopeContext,
|
||||||
skipFetch,
|
skipFetch,
|
||||||
}: {
|
}: {
|
||||||
availableFilters: FilterDefinitionByEntity<Entity>[];
|
|
||||||
scopeContext: Context<string | null>;
|
scopeContext: Context<string | null>;
|
||||||
skipFetch?: boolean;
|
skipFetch?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
@ -34,6 +32,10 @@ export const useViewFilters = <Entity>({
|
|||||||
filtersScopedState,
|
filtersScopedState,
|
||||||
scopeContext,
|
scopeContext,
|
||||||
);
|
);
|
||||||
|
const [availableFilters] = useRecoilScopedState(
|
||||||
|
availableFiltersScopedState,
|
||||||
|
scopeContext,
|
||||||
|
);
|
||||||
const [, setSavedFilters] = useRecoilState(
|
const [, setSavedFilters] = useRecoilState(
|
||||||
savedFiltersFamilyState(currentViewId),
|
savedFiltersFamilyState(currentViewId),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,11 +3,12 @@ import { useRecoilState, useRecoilValue } from 'recoil';
|
|||||||
|
|
||||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||||
|
import { availableSortsScopedState } from '@/ui/view-bar/states/availableSortsScopedState';
|
||||||
import { currentViewIdScopedState } from '@/ui/view-bar/states/currentViewIdScopedState';
|
import { currentViewIdScopedState } from '@/ui/view-bar/states/currentViewIdScopedState';
|
||||||
import { savedSortsFamilyState } from '@/ui/view-bar/states/savedSortsFamilyState';
|
import { savedSortsFamilyState } from '@/ui/view-bar/states/savedSortsFamilyState';
|
||||||
import { savedSortsByKeyFamilySelector } from '@/ui/view-bar/states/selectors/savedSortsByKeyFamilySelector';
|
import { savedSortsByKeyFamilySelector } from '@/ui/view-bar/states/selectors/savedSortsByKeyFamilySelector';
|
||||||
import { sortsScopedState } from '@/ui/view-bar/states/sortsScopedState';
|
import { sortsScopedState } from '@/ui/view-bar/states/sortsScopedState';
|
||||||
import type { SelectedSortType, SortType } from '@/ui/view-bar/types/interface';
|
import { Sort } from '@/ui/view-bar/types/Sort';
|
||||||
import {
|
import {
|
||||||
useCreateViewSortsMutation,
|
useCreateViewSortsMutation,
|
||||||
useDeleteViewSortsMutation,
|
useDeleteViewSortsMutation,
|
||||||
@ -17,12 +18,10 @@ import {
|
|||||||
} from '~/generated/graphql';
|
} from '~/generated/graphql';
|
||||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
|
|
||||||
export const useViewSorts = <SortField>({
|
export const useViewSorts = ({
|
||||||
availableSorts,
|
|
||||||
scopeContext,
|
scopeContext,
|
||||||
skipFetch,
|
skipFetch,
|
||||||
}: {
|
}: {
|
||||||
availableSorts: SortType<SortField>[];
|
|
||||||
scopeContext: Context<string | null>;
|
scopeContext: Context<string | null>;
|
||||||
skipFetch?: boolean;
|
skipFetch?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
@ -34,6 +33,10 @@ export const useViewSorts = <SortField>({
|
|||||||
sortsScopedState,
|
sortsScopedState,
|
||||||
scopeContext,
|
scopeContext,
|
||||||
);
|
);
|
||||||
|
const [availableSorts] = useRecoilScopedState(
|
||||||
|
availableSortsScopedState,
|
||||||
|
scopeContext,
|
||||||
|
);
|
||||||
const [, setSavedSorts] = useRecoilState(
|
const [, setSavedSorts] = useRecoilState(
|
||||||
savedSortsFamilyState(currentViewId),
|
savedSortsFamilyState(currentViewId),
|
||||||
);
|
);
|
||||||
@ -51,19 +54,21 @@ export const useViewSorts = <SortField>({
|
|||||||
onCompleted: (data) => {
|
onCompleted: (data) => {
|
||||||
const nextSorts = data.viewSorts
|
const nextSorts = data.viewSorts
|
||||||
.map((viewSort) => {
|
.map((viewSort) => {
|
||||||
const availableSort = availableSorts.find(
|
const foundCorrespondingSortDefinition = availableSorts.find(
|
||||||
(sort) => sort.key === viewSort.key,
|
(sort) => sort.key === viewSort.key,
|
||||||
);
|
);
|
||||||
|
|
||||||
return availableSort
|
if (foundCorrespondingSortDefinition) {
|
||||||
? {
|
return {
|
||||||
...availableSort,
|
key: viewSort.key,
|
||||||
label: viewSort.name,
|
definition: foundCorrespondingSortDefinition,
|
||||||
order: viewSort.direction.toLowerCase(),
|
direction: viewSort.direction.toLowerCase(),
|
||||||
}
|
} as Sort;
|
||||||
: undefined;
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.filter((sort): sort is SelectedSortType<SortField> => !!sort);
|
.filter((sort): sort is Sort => !!sort);
|
||||||
|
|
||||||
if (!isDeeplyEqual(sorts, nextSorts)) {
|
if (!isDeeplyEqual(sorts, nextSorts)) {
|
||||||
setSavedSorts(nextSorts);
|
setSavedSorts(nextSorts);
|
||||||
@ -77,15 +82,15 @@ export const useViewSorts = <SortField>({
|
|||||||
const [deleteViewSortsMutation] = useDeleteViewSortsMutation();
|
const [deleteViewSortsMutation] = useDeleteViewSortsMutation();
|
||||||
|
|
||||||
const createViewSorts = useCallback(
|
const createViewSorts = useCallback(
|
||||||
(sorts: SelectedSortType<SortField>[], viewId = currentViewId) => {
|
(sorts: Sort[], viewId = currentViewId) => {
|
||||||
if (!viewId || !sorts.length) return;
|
if (!viewId || !sorts.length) return;
|
||||||
|
|
||||||
return createViewSortsMutation({
|
return createViewSortsMutation({
|
||||||
variables: {
|
variables: {
|
||||||
data: sorts.map((sort) => ({
|
data: sorts.map((sort) => ({
|
||||||
key: sort.key,
|
key: sort.key,
|
||||||
direction: sort.order as ViewSortDirection,
|
direction: sort.direction as ViewSortDirection,
|
||||||
name: sort.label,
|
name: sort.definition.label,
|
||||||
viewId,
|
viewId,
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
@ -95,7 +100,7 @@ export const useViewSorts = <SortField>({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const updateViewSorts = useCallback(
|
const updateViewSorts = useCallback(
|
||||||
(sorts: SelectedSortType<SortField>[]) => {
|
(sorts: Sort[]) => {
|
||||||
if (!currentViewId || !sorts.length) return;
|
if (!currentViewId || !sorts.length) return;
|
||||||
|
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
@ -103,7 +108,7 @@ export const useViewSorts = <SortField>({
|
|||||||
updateViewSortMutation({
|
updateViewSortMutation({
|
||||||
variables: {
|
variables: {
|
||||||
data: {
|
data: {
|
||||||
direction: sort.order as ViewSortDirection,
|
direction: sort.direction as ViewSortDirection,
|
||||||
},
|
},
|
||||||
where: {
|
where: {
|
||||||
viewId_key: { key: sort.key, viewId: currentViewId },
|
viewId_key: { key: sort.key, viewId: currentViewId },
|
||||||
@ -141,7 +146,7 @@ export const useViewSorts = <SortField>({
|
|||||||
const sortsToUpdate = sorts.filter(
|
const sortsToUpdate = sorts.filter(
|
||||||
(sort) =>
|
(sort) =>
|
||||||
savedSortsByKey[sort.key] &&
|
savedSortsByKey[sort.key] &&
|
||||||
savedSortsByKey[sort.key].order !== sort.order,
|
savedSortsByKey[sort.key].direction !== sort.direction,
|
||||||
);
|
);
|
||||||
await updateViewSorts(sortsToUpdate);
|
await updateViewSorts(sortsToUpdate);
|
||||||
|
|
||||||
|
|||||||
@ -5,10 +5,9 @@ import {
|
|||||||
IconMap,
|
IconMap,
|
||||||
IconUsers,
|
IconUsers,
|
||||||
} from '@/ui/icon/index';
|
} from '@/ui/icon/index';
|
||||||
import { SortType } from '@/ui/view-bar/types/interface';
|
import { SortDefinition } from '@/ui/view-bar/types/SortDefinition';
|
||||||
import { CompanyOrderByWithRelationInput as Companies_Order_By } from '~/generated/graphql';
|
|
||||||
|
|
||||||
export const availableSorts: SortType<Companies_Order_By>[] = [
|
export const companyAvailableSorts: SortDefinition[] = [
|
||||||
{
|
{
|
||||||
key: 'name',
|
key: 'name',
|
||||||
label: 'Name',
|
label: 'Name',
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import { IconCalendarEvent, IconCurrencyDollar } from '@/ui/icon/index';
|
import { IconCalendarEvent, IconCurrencyDollar } from '@/ui/icon/index';
|
||||||
import { SortType } from '@/ui/view-bar/types/interface';
|
import { SortDefinition } from '@/ui/view-bar/types/SortDefinition';
|
||||||
import { PipelineProgressOrderByWithRelationInput as PipelineProgresses_Order_By } from '~/generated/graphql';
|
|
||||||
|
|
||||||
export const opportunitiesSorts = [
|
export const opportunitiesSorts: SortDefinition[] = [
|
||||||
{
|
{
|
||||||
key: 'createdAt',
|
key: 'createdAt',
|
||||||
label: 'Creation',
|
label: 'Creation',
|
||||||
@ -18,4 +17,4 @@ export const opportunitiesSorts = [
|
|||||||
label: 'Expected close date',
|
label: 'Expected close date',
|
||||||
Icon: IconCalendarEvent,
|
Icon: IconCalendarEvent,
|
||||||
},
|
},
|
||||||
] satisfies Array<SortType<PipelineProgresses_Order_By>>;
|
];
|
||||||
|
|||||||
@ -6,28 +6,27 @@ import {
|
|||||||
IconPhone,
|
IconPhone,
|
||||||
IconUser,
|
IconUser,
|
||||||
} from '@/ui/icon/index';
|
} from '@/ui/icon/index';
|
||||||
import { SortType } from '@/ui/view-bar/types/interface';
|
import { SortDefinition } from '@/ui/view-bar/types/SortDefinition';
|
||||||
import {
|
import { SortDirection } from '@/ui/view-bar/types/SortDirection';
|
||||||
PersonOrderByWithRelationInput as People_Order_By,
|
|
||||||
SortOrder as Order_By,
|
|
||||||
} from '~/generated/graphql';
|
|
||||||
|
|
||||||
export const availableSorts: SortType<People_Order_By>[] = [
|
export const peopleAvailableSorts: SortDefinition[] = [
|
||||||
{
|
{
|
||||||
key: 'fullname',
|
key: 'fullname',
|
||||||
label: 'People',
|
label: 'People',
|
||||||
Icon: IconUser,
|
Icon: IconUser,
|
||||||
|
|
||||||
orderByTemplate: (order: Order_By) => [
|
getOrderByTemplate: (direction: SortDirection) => [
|
||||||
{ firstName: order },
|
{ firstName: direction },
|
||||||
{ lastName: order },
|
{ lastName: direction },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'company_name',
|
key: 'company_name',
|
||||||
label: 'Company',
|
label: 'Company',
|
||||||
Icon: IconBuildingSkyscraper,
|
Icon: IconBuildingSkyscraper,
|
||||||
orderByTemplate: (order: Order_By) => [{ company: { name: order } }],
|
getOrderByTemplate: (direction: SortDirection) => [
|
||||||
|
{ company: { name: direction } },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'email',
|
key: 'email',
|
||||||
|
|||||||
@ -68,7 +68,9 @@ export function Tasks() {
|
|||||||
<FilterDropdownButton
|
<FilterDropdownButton
|
||||||
key="tasks-filter-dropdown-button"
|
key="tasks-filter-dropdown-button"
|
||||||
context={TasksRecoilScopeContext}
|
context={TasksRecoilScopeContext}
|
||||||
hotkeyScope={RelationPickerHotkeyScope.RelationPicker}
|
hotkeyScope={{
|
||||||
|
scope: RelationPickerHotkeyScope.RelationPicker,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user