From 485bc64b4f40eee37ad36a4b992d2e4719516fd9 Mon Sep 17 00:00:00 2001 From: brendanlaschke Date: Thu, 28 Sep 2023 11:50:44 +0200 Subject: [PATCH] POC: Save view as url param (#1710) * - save view as url param * - fix tests --- .../companies/__stories__/Board.stories.tsx | 2 +- .../__stories__/CompanyBoardCard.stories.tsx | 14 +++--- .../components/HooksCompanyBoardEffect.tsx | 40 +++++++++++++++- .../__stories__/ActionBar.stories.tsx | 2 +- .../ui/board/components/BoardHeader.tsx | 6 ++- .../__stories__/ContextMenu.stories.tsx | 2 +- .../ui/table/components/EntityTableEffect.tsx | 47 ++++++++++++++++++- .../table-header/components/TableHeader.tsx | 6 ++- 8 files changed, 105 insertions(+), 14 deletions(-) diff --git a/front/src/modules/companies/__stories__/Board.stories.tsx b/front/src/modules/companies/__stories__/Board.stories.tsx index 1f90ea138..90f3c5f72 100644 --- a/front/src/modules/companies/__stories__/Board.stories.tsx +++ b/front/src/modules/companies/__stories__/Board.stories.tsx @@ -15,8 +15,8 @@ const meta: Meta = { decorators: [ (Story) => ( - + diff --git a/front/src/modules/companies/__stories__/CompanyBoardCard.stories.tsx b/front/src/modules/companies/__stories__/CompanyBoardCard.stories.tsx index 2ec44f4fd..12ce3b94f 100644 --- a/front/src/modules/companies/__stories__/CompanyBoardCard.stories.tsx +++ b/front/src/modules/companies/__stories__/CompanyBoardCard.stories.tsx @@ -40,14 +40,14 @@ const meta: Meta = { context.parameters.customRecoilScopeContext, }} > - - - + + + - - + + ); diff --git a/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx b/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx index 60e388340..a4157e939 100644 --- a/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx +++ b/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx @@ -1,15 +1,21 @@ 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 { useBoardContextMenuEntries } from '@/ui/board/hooks/useBoardContextMenuEntries'; 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 { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId'; import { availableFiltersScopedState } from '@/ui/view-bar/states/availableFiltersScopedState'; 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 { 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 { sortsScopedState } from '@/ui/view-bar/states/sortsScopedState'; import { turnFilterIntoWhereClause } from '@/ui/view-bar/utils/turnFilterIntoWhereClause'; import { 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 = loadingGetPipelines || loadingGetPipelineProgress || loadingGetCompanies; @@ -119,6 +151,10 @@ export const HooksCompanyBoardEffect = () => { useEffect(() => { if (!loading && pipeline && pipelineProgresses && companiesData) { + const viewId = searchParams.get('view'); + if (viewId) { + handleViewSelect(viewId); + } setActionBarEntries(); setContextMenuEntries(); updateCompanyBoard(pipeline, pipelineProgresses, companiesData.companies); @@ -131,6 +167,8 @@ export const HooksCompanyBoardEffect = () => { updateCompanyBoard, setActionBarEntries, setContextMenuEntries, + searchParams, + handleViewSelect, ]); return <>; diff --git a/front/src/modules/ui/action-bar/components/__stories__/ActionBar.stories.tsx b/front/src/modules/ui/action-bar/components/__stories__/ActionBar.stories.tsx index db361ec46..3e9a3b49c 100644 --- a/front/src/modules/ui/action-bar/components/__stories__/ActionBar.stories.tsx +++ b/front/src/modules/ui/action-bar/components/__stories__/ActionBar.stories.tsx @@ -25,8 +25,8 @@ const meta: Meta = { decorators: [ (Story) => ( - + diff --git a/front/src/modules/ui/board/components/BoardHeader.tsx b/front/src/modules/ui/board/components/BoardHeader.tsx index 4bea188a2..8c03e0676 100644 --- a/front/src/modules/ui/board/components/BoardHeader.tsx +++ b/front/src/modules/ui/board/components/BoardHeader.tsx @@ -1,4 +1,5 @@ import { useContext } from 'react'; +import { useSearchParams } from 'react-router-dom'; import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil'; import { BoardContext } from '@/companies/states/contexts/BoardContext'; @@ -60,6 +61,7 @@ export const BoardHeader = ({ className, onStageAdd }: BoardHeaderProps) => { savedBoardCardFieldsFamilyState(currentViewId), ); + const [_, setSearchParams] = useSearchParams(); const [boardColumns, setBoardColumns] = useRecoilState(boardColumnsState); const [, setSavedBoardColumns] = useRecoilState(savedBoardColumnsState); @@ -80,8 +82,9 @@ export const BoardHeader = ({ className, onStageAdd }: BoardHeaderProps) => { boardCardFieldsScopedState(boardRecoilScopeId), savedBoardCardFields, ); + setSearchParams({ view: viewId }); }, - [boardRecoilScopeId], + [boardRecoilScopeId, setSearchParams], ); const handleCurrentViewSubmit = async () => { @@ -106,6 +109,7 @@ export const BoardHeader = ({ className, onStageAdd }: BoardHeaderProps) => { onCurrentViewSubmit: handleCurrentViewSubmit, onViewBarReset: handleViewBarReset, onViewSelect: handleViewSelect, + onViewCreate: (view) => setSearchParams({ view: view.id }), }} > = { decorators: [ (Story) => ( - + diff --git a/front/src/modules/ui/table/components/EntityTableEffect.tsx b/front/src/modules/ui/table/components/EntityTableEffect.tsx index 864a5cb3f..0de8c5302 100644 --- a/front/src/modules/ui/table/components/EntityTableEffect.tsx +++ b/front/src/modules/ui/table/components/EntityTableEffect.tsx @@ -1,12 +1,22 @@ import { useEffect } from 'react'; +import { useSearchParams } from 'react-router-dom'; +import { useRecoilCallback } from 'recoil'; import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect'; import { OptimisticEffectDefinition } from '@/apollo/optimistic-effect/types/OptimisticEffectDefinition'; 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 { SortDefinition } from '@/ui/view-bar/types/SortDefinition'; import { SortOrder } from '~/generated/graphql'; +import { TableRecoilScopeContext } from '../states/recoil-scope-contexts/TableRecoilScopeContext'; + export const EntityTableEffect = ({ useGetRequest, 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(() => { + const viewId = searchParams.get('view'); + if (viewId) { + handleViewSelect(viewId); + } setActionBarEntries?.(); setContextMenuEntries?.(); - }, [setActionBarEntries, setContextMenuEntries]); + }, [ + handleViewSelect, + searchParams, + setActionBarEntries, + setContextMenuEntries, + ]); return <>; }; diff --git a/front/src/modules/ui/table/table-header/components/TableHeader.tsx b/front/src/modules/ui/table/table-header/components/TableHeader.tsx index a91620874..4c7ae91b8 100644 --- a/front/src/modules/ui/table/table-header/components/TableHeader.tsx +++ b/front/src/modules/ui/table/table-header/components/TableHeader.tsx @@ -1,4 +1,5 @@ import { useContext } from 'react'; +import { useSearchParams } from 'react-router-dom'; import { useRecoilCallback } from 'recoil'; import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext'; @@ -18,6 +19,7 @@ export const TableHeader = () => { const { onCurrentViewSubmit, ...viewBarContextProps } = useContext(ViewBarContext); const tableRecoilScopeId = useRecoilScopeId(TableRecoilScopeContext); + const [_, setSearchParams] = useSearchParams(); const handleViewSelect = useRecoilCallback( ({ set, snapshot }) => @@ -26,8 +28,9 @@ export const TableHeader = () => { savedTableColumnsFamilyState(viewId), ); set(tableColumnsScopedState(tableRecoilScopeId), savedTableColumns); + setSearchParams({ view: viewId }); }, - [tableRecoilScopeId], + [tableRecoilScopeId, setSearchParams], ); return ( @@ -37,6 +40,7 @@ export const TableHeader = () => { ...viewBarContextProps, onCurrentViewSubmit, onViewSelect: handleViewSelect, + onViewCreate: (view) => setSearchParams({ view: view.id }), }} >