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