POC: Save view as url param (#1710)

* - save view as url param

* - fix tests
This commit is contained in:
brendanlaschke 2023-09-28 11:50:44 +02:00 committed by GitHub
parent b2bac0b217
commit 485bc64b4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 105 additions and 14 deletions

View File

@ -15,8 +15,8 @@ const meta: Meta<typeof CompanyBoard> = {
decorators: [ decorators: [
(Story) => ( (Story) => (
<RecoilScope CustomRecoilScopeContext={CompanyBoardRecoilScopeContext}> <RecoilScope CustomRecoilScopeContext={CompanyBoardRecoilScopeContext}>
<HooksCompanyBoardEffect />
<MemoryRouter> <MemoryRouter>
<HooksCompanyBoardEffect />
<Story /> <Story />
</MemoryRouter> </MemoryRouter>
</RecoilScope> </RecoilScope>

View File

@ -40,14 +40,14 @@ const meta: Meta<typeof CompanyBoardCard> = {
context.parameters.customRecoilScopeContext, context.parameters.customRecoilScopeContext,
}} }}
> >
<HooksCompanyBoardEffect /> <MemoryRouter>
<BoardCardIdContext.Provider <HooksCompanyBoardEffect />
value={mockedPipelineProgressData[1].id} <BoardCardIdContext.Provider
> value={mockedPipelineProgressData[1].id}
<MemoryRouter> >
<Story /> <Story />
</MemoryRouter> </BoardCardIdContext.Provider>
</BoardCardIdContext.Provider> </MemoryRouter>
</BoardContext.Provider> </BoardContext.Provider>
</RecoilScope> </RecoilScope>
); );

View File

@ -1,15 +1,21 @@
import { useEffect, useMemo } from 'react'; import { useEffect, useMemo } from 'react';
import { useRecoilState } from 'recoil'; import { useSearchParams } from 'react-router-dom';
import { useRecoilCallback, useRecoilState } from 'recoil';
import { useBoardActionBarEntries } from '@/ui/board/hooks/useBoardActionBarEntries'; import { useBoardActionBarEntries } from '@/ui/board/hooks/useBoardActionBarEntries';
import { useBoardContextMenuEntries } from '@/ui/board/hooks/useBoardContextMenuEntries'; import { useBoardContextMenuEntries } from '@/ui/board/hooks/useBoardContextMenuEntries';
import { isBoardLoadedState } from '@/ui/board/states/isBoardLoadedState'; 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 { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
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 { availableSortsScopedState } from '@/ui/view-bar/states/availableSortsScopedState';
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 { savedSortsFamilyState } from '@/ui/view-bar/states/savedSortsFamilyState';
import { sortsOrderByScopedSelector } from '@/ui/view-bar/states/selectors/sortsOrderByScopedSelector'; import { sortsOrderByScopedSelector } from '@/ui/view-bar/states/selectors/sortsOrderByScopedSelector';
import { sortsScopedState } from '@/ui/view-bar/states/sortsScopedState';
import { turnFilterIntoWhereClause } from '@/ui/view-bar/utils/turnFilterIntoWhereClause'; import { turnFilterIntoWhereClause } from '@/ui/view-bar/utils/turnFilterIntoWhereClause';
import { import {
Pipeline, Pipeline,
@ -111,6 +117,32 @@ export const HooksCompanyBoardEffect = () => {
}, },
}); });
const [searchParams] = useSearchParams();
const boardRecoilScopeId = useRecoilScopeId(CompanyBoardRecoilScopeContext);
const handleViewSelect = useRecoilCallback(
({ set, snapshot }) =>
async (viewId: string) => {
const currentView = await snapshot.getPromise(
currentViewIdScopedState(boardRecoilScopeId),
);
if (currentView === viewId) {
return;
}
const savedFilters = await snapshot.getPromise(
savedFiltersFamilyState(viewId),
);
const savedSorts = await snapshot.getPromise(
savedSortsFamilyState(viewId),
);
set(filtersScopedState(boardRecoilScopeId), savedFilters);
set(sortsScopedState(boardRecoilScopeId), savedSorts);
set(currentViewIdScopedState(boardRecoilScopeId), viewId);
},
[boardRecoilScopeId],
);
const loading = const loading =
loadingGetPipelines || loadingGetPipelineProgress || loadingGetCompanies; loadingGetPipelines || loadingGetPipelineProgress || loadingGetCompanies;
@ -119,6 +151,10 @@ export const HooksCompanyBoardEffect = () => {
useEffect(() => { useEffect(() => {
if (!loading && pipeline && pipelineProgresses && companiesData) { if (!loading && pipeline && pipelineProgresses && companiesData) {
const viewId = searchParams.get('view');
if (viewId) {
handleViewSelect(viewId);
}
setActionBarEntries(); setActionBarEntries();
setContextMenuEntries(); setContextMenuEntries();
updateCompanyBoard(pipeline, pipelineProgresses, companiesData.companies); updateCompanyBoard(pipeline, pipelineProgresses, companiesData.companies);
@ -131,6 +167,8 @@ export const HooksCompanyBoardEffect = () => {
updateCompanyBoard, updateCompanyBoard,
setActionBarEntries, setActionBarEntries,
setContextMenuEntries, setContextMenuEntries,
searchParams,
handleViewSelect,
]); ]);
return <></>; return <></>;

View File

@ -25,8 +25,8 @@ const meta: Meta<typeof ActionBar> = {
decorators: [ decorators: [
(Story) => ( (Story) => (
<RecoilScope CustomRecoilScopeContext={TableRecoilScopeContext}> <RecoilScope CustomRecoilScopeContext={TableRecoilScopeContext}>
<CompanyTableMockMode />
<MemoryRouter> <MemoryRouter>
<CompanyTableMockMode />
<Story /> <Story />
</MemoryRouter> </MemoryRouter>
</RecoilScope> </RecoilScope>

View File

@ -1,4 +1,5 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { useSearchParams } from 'react-router-dom';
import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil'; import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil';
import { BoardContext } from '@/companies/states/contexts/BoardContext'; import { BoardContext } from '@/companies/states/contexts/BoardContext';
@ -60,6 +61,7 @@ export const BoardHeader = ({ className, onStageAdd }: BoardHeaderProps) => {
savedBoardCardFieldsFamilyState(currentViewId), savedBoardCardFieldsFamilyState(currentViewId),
); );
const [_, setSearchParams] = useSearchParams();
const [boardColumns, setBoardColumns] = useRecoilState(boardColumnsState); const [boardColumns, setBoardColumns] = useRecoilState(boardColumnsState);
const [, setSavedBoardColumns] = useRecoilState(savedBoardColumnsState); const [, setSavedBoardColumns] = useRecoilState(savedBoardColumnsState);
@ -80,8 +82,9 @@ export const BoardHeader = ({ className, onStageAdd }: BoardHeaderProps) => {
boardCardFieldsScopedState(boardRecoilScopeId), boardCardFieldsScopedState(boardRecoilScopeId),
savedBoardCardFields, savedBoardCardFields,
); );
setSearchParams({ view: viewId });
}, },
[boardRecoilScopeId], [boardRecoilScopeId, setSearchParams],
); );
const handleCurrentViewSubmit = async () => { const handleCurrentViewSubmit = async () => {
@ -106,6 +109,7 @@ export const BoardHeader = ({ className, onStageAdd }: BoardHeaderProps) => {
onCurrentViewSubmit: handleCurrentViewSubmit, onCurrentViewSubmit: handleCurrentViewSubmit,
onViewBarReset: handleViewBarReset, onViewBarReset: handleViewBarReset,
onViewSelect: handleViewSelect, onViewSelect: handleViewSelect,
onViewCreate: (view) => setSearchParams({ view: view.id }),
}} }}
> >
<ViewBar <ViewBar

View File

@ -31,8 +31,8 @@ const meta: Meta<typeof ContextMenu> = {
decorators: [ decorators: [
(Story) => ( (Story) => (
<RecoilScope CustomRecoilScopeContext={TableRecoilScopeContext}> <RecoilScope CustomRecoilScopeContext={TableRecoilScopeContext}>
<CompanyTableMockMode></CompanyTableMockMode>
<MemoryRouter> <MemoryRouter>
<CompanyTableMockMode></CompanyTableMockMode>
<Story /> <Story />
</MemoryRouter> </MemoryRouter>
</RecoilScope> </RecoilScope>

View File

@ -1,12 +1,22 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useSearchParams } from 'react-router-dom';
import { useRecoilCallback } from 'recoil';
import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect'; import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect';
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 { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
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 { savedSortsFamilyState } from '@/ui/view-bar/states/savedSortsFamilyState';
import { sortsScopedState } from '@/ui/view-bar/states/sortsScopedState';
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 { SortDefinition } from '@/ui/view-bar/types/SortDefinition';
import { SortOrder } from '~/generated/graphql'; import { SortOrder } from '~/generated/graphql';
import { TableRecoilScopeContext } from '../states/recoil-scope-contexts/TableRecoilScopeContext';
export const EntityTableEffect = ({ export const EntityTableEffect = ({
useGetRequest, useGetRequest,
getRequestResultKey, getRequestResultKey,
@ -52,10 +62,45 @@ export const EntityTableEffect = ({
}, },
}); });
const [searchParams] = useSearchParams();
const tableRecoilScopeId = useRecoilScopeId(TableRecoilScopeContext);
const handleViewSelect = useRecoilCallback(
({ set, snapshot }) =>
async (viewId: string) => {
const currentView = await snapshot.getPromise(
currentViewIdScopedState(tableRecoilScopeId),
);
if (currentView === viewId) {
return;
}
const savedFilters = await snapshot.getPromise(
savedFiltersFamilyState(viewId),
);
const savedSorts = await snapshot.getPromise(
savedSortsFamilyState(viewId),
);
set(filtersScopedState(tableRecoilScopeId), savedFilters);
set(sortsScopedState(tableRecoilScopeId), savedSorts);
set(currentViewIdScopedState(tableRecoilScopeId), viewId);
},
[tableRecoilScopeId],
);
useEffect(() => { useEffect(() => {
const viewId = searchParams.get('view');
if (viewId) {
handleViewSelect(viewId);
}
setActionBarEntries?.(); setActionBarEntries?.();
setContextMenuEntries?.(); setContextMenuEntries?.();
}, [setActionBarEntries, setContextMenuEntries]); }, [
handleViewSelect,
searchParams,
setActionBarEntries,
setContextMenuEntries,
]);
return <></>; return <></>;
}; };

View File

@ -1,4 +1,5 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { useSearchParams } from 'react-router-dom';
import { useRecoilCallback } from 'recoil'; import { useRecoilCallback } from 'recoil';
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext'; import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
@ -18,6 +19,7 @@ export const TableHeader = () => {
const { onCurrentViewSubmit, ...viewBarContextProps } = const { onCurrentViewSubmit, ...viewBarContextProps } =
useContext(ViewBarContext); useContext(ViewBarContext);
const tableRecoilScopeId = useRecoilScopeId(TableRecoilScopeContext); const tableRecoilScopeId = useRecoilScopeId(TableRecoilScopeContext);
const [_, setSearchParams] = useSearchParams();
const handleViewSelect = useRecoilCallback( const handleViewSelect = useRecoilCallback(
({ set, snapshot }) => ({ set, snapshot }) =>
@ -26,8 +28,9 @@ export const TableHeader = () => {
savedTableColumnsFamilyState(viewId), savedTableColumnsFamilyState(viewId),
); );
set(tableColumnsScopedState(tableRecoilScopeId), savedTableColumns); set(tableColumnsScopedState(tableRecoilScopeId), savedTableColumns);
setSearchParams({ view: viewId });
}, },
[tableRecoilScopeId], [tableRecoilScopeId, setSearchParams],
); );
return ( return (
@ -37,6 +40,7 @@ export const TableHeader = () => {
...viewBarContextProps, ...viewBarContextProps,
onCurrentViewSubmit, onCurrentViewSubmit,
onViewSelect: handleViewSelect, onViewSelect: handleViewSelect,
onViewCreate: (view) => setSearchParams({ view: view.id }),
}} }}
> >
<ViewBar <ViewBar