From 53072298bcf55637192f155012742204a9d76524 Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Sat, 4 Nov 2023 09:28:55 +0100 Subject: [PATCH] Feat/improve new views (#2298) * POC new recoil injected scoped states * Finished useViewScopedState refactor * Finished refactor * Renamed mappers * Fixed update view fields bug * Post merge * Complete refactor * Fix tests --------- Co-authored-by: Charles Bochet --- .../components/HooksCompanyBoardEffect.tsx | 14 +- .../table/components/CompanyTable.tsx | 21 +- .../metadata/components/RecordTable.tsx | 21 +- .../people/table/components/PersonTable.tsx | 31 +- .../BoardOptionsDropdownContent.tsx | 9 +- .../isEntityFieldEmptyFamilySelector.ts | 2 + .../TableOptionsDropdownContent.tsx | 8 +- .../types/RecoilScopedSelector.ts | 7 + .../recoil-scope/types/RecoilScopedState.ts | 7 + .../utils/createScopedSelector.ts | 30 ++ .../utils/getScopedFamilyState.ts | 19 ++ .../recoil-scope/utils/getScopedSelector.ts | 10 + .../recoil-scope/utils/getScopedState.ts | 10 + .../utils/getSnapshotScopedSelector.ts | 15 + .../utils/getSnapshotScopedValue.ts | 13 + .../recoil-scope/utils/getSnapshotValue.ts | 8 + .../components/UpdateViewButtonGroup.tsx | 10 +- .../src/modules/views/components/ViewBar.tsx | 15 +- .../views/components/ViewBarDetails.tsx | 21 +- .../views/components/ViewBarEffect.tsx | 171 +++++------ .../views/components/ViewsDropdownButton.tsx | 17 +- front/src/modules/views/constants/index.ts | 2 + .../views/hooks/internal/useViewFields.ts | 39 ++- .../views/hooks/internal/useViewFilters.ts | 102 +++---- .../hooks/internal/useViewScopedStates.ts | 84 ++++++ .../views/hooks/internal/useViewSorts.ts | 103 +++---- .../modules/views/hooks/internal/useViews.ts | 17 +- front/src/modules/views/hooks/useView.ts | 272 ++++++++---------- .../modules/views/hooks/useViewGetStates.ts | 211 -------------- .../modules/views/hooks/useViewSetStates.ts | 160 ----------- .../init-effect/ViewScopeInitEffect.tsx | 15 +- .../selectors/currentViewScopedSelector.ts | 33 +-- ...savedViewFieldByKeyScopedFamilySelector.ts | 1 + .../getViewScopedStateValuesFromSnapshot.ts | 106 +++++++ .../utils/getViewScopedStatesFromSnapshot.ts | 85 ++++++ .../utils/internal/getViewScopedStates.ts | 198 +++++++++++++ ...d.ts => mapColumnDefinitionToViewField.ts} | 2 +- ...> mapViewFieldsToBoardFieldDefinitions.ts} | 2 +- ...ts => mapViewFieldsToColumnDefinitions.ts} | 2 +- ...oFilters.ts => mapViewFiltersToFilters.ts} | 4 +- ...SortsToSorts.ts => mapViewSortsToSorts.ts} | 2 +- .../__stories__/People.sortBy.stories.tsx | 4 +- 42 files changed, 1018 insertions(+), 885 deletions(-) create mode 100644 front/src/modules/ui/utilities/recoil-scope/types/RecoilScopedSelector.ts create mode 100644 front/src/modules/ui/utilities/recoil-scope/types/RecoilScopedState.ts create mode 100644 front/src/modules/ui/utilities/recoil-scope/utils/createScopedSelector.ts create mode 100644 front/src/modules/ui/utilities/recoil-scope/utils/getScopedFamilyState.ts create mode 100644 front/src/modules/ui/utilities/recoil-scope/utils/getScopedSelector.ts create mode 100644 front/src/modules/ui/utilities/recoil-scope/utils/getScopedState.ts create mode 100644 front/src/modules/ui/utilities/recoil-scope/utils/getSnapshotScopedSelector.ts create mode 100644 front/src/modules/ui/utilities/recoil-scope/utils/getSnapshotScopedValue.ts create mode 100644 front/src/modules/ui/utilities/recoil-scope/utils/getSnapshotValue.ts create mode 100644 front/src/modules/views/constants/index.ts create mode 100644 front/src/modules/views/hooks/internal/useViewScopedStates.ts delete mode 100644 front/src/modules/views/hooks/useViewGetStates.ts delete mode 100644 front/src/modules/views/hooks/useViewSetStates.ts create mode 100644 front/src/modules/views/utils/getViewScopedStateValuesFromSnapshot.ts create mode 100644 front/src/modules/views/utils/getViewScopedStatesFromSnapshot.ts create mode 100644 front/src/modules/views/utils/internal/getViewScopedStates.ts rename front/src/modules/views/utils/{columnDefinitionToViewField.ts => mapColumnDefinitionToViewField.ts} (92%) rename front/src/modules/views/utils/{viewFieldsToBoardFieldDefinitions.ts => mapViewFieldsToBoardFieldDefinitions.ts} (96%) rename front/src/modules/views/utils/{viewFieldsToColumnDefinitions.ts => mapViewFieldsToColumnDefinitions.ts} (96%) rename front/src/modules/views/utils/{viewFiltersToFilters.ts => mapViewFiltersToFilters.ts} (81%) rename front/src/modules/views/utils/{viewSortsToSorts.ts => mapViewSortsToSorts.ts} (80%) diff --git a/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx b/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx index 8ff2b37e4..54be00c75 100644 --- a/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx +++ b/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx @@ -1,6 +1,6 @@ import { useEffect, useMemo } from 'react'; import { useSearchParams } from 'react-router-dom'; -import { useRecoilState } from 'recoil'; +import { useRecoilState, useRecoilValue } from 'recoil'; import { pipelineAvailableFieldDefinitions } from '@/pipeline/constants/pipelineAvailableFieldDefinitions'; import { useBoardActionBarEntries } from '@/ui/layout/board/hooks/useBoardActionBarEntries'; @@ -11,10 +11,10 @@ import { boardCardFieldsScopedState } from '@/ui/layout/board/states/boardCardFi import { isBoardLoadedState } from '@/ui/layout/board/states/isBoardLoadedState'; import { turnFilterIntoWhereClause } from '@/ui/object/object-filter-dropdown/utils/turnFilterIntoWhereClause'; import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; +import { useViewScopedStates } from '@/views/hooks/internal/useViewScopedStates'; import { useView } from '@/views/hooks/useView'; -import { useViewGetStates } from '@/views/hooks/useViewGetStates'; import { ViewType } from '@/views/types/ViewType'; -import { viewFieldsToBoardFieldDefinitions } from '@/views/utils/viewFieldsToBoardFieldDefinitions'; +import { mapViewFieldsToBoardFieldDefinitions } from '@/views/utils/mapViewFieldsToBoardFieldDefinitions'; import { Pipeline, PipelineProgressableType, @@ -37,7 +37,11 @@ export const HooksCompanyBoardEffect = () => { setViewType, } = useView(); - const { currentViewFilters, currentViewFields } = useViewGetStates(); + const { currentViewFiltersState, currentViewFieldsState } = + useViewScopedStates(); + + const currentViewFields = useRecoilValue(currentViewFieldsState); + const currentViewFilters = useRecoilValue(currentViewFiltersState); const [, setIsBoardLoaded] = useRecoilState(isBoardLoadedState); @@ -159,7 +163,7 @@ export const HooksCompanyBoardEffect = () => { useEffect(() => { if (currentViewFields) { setBoardCardFields( - viewFieldsToBoardFieldDefinitions( + mapViewFieldsToBoardFieldDefinitions( currentViewFields, pipelineAvailableFieldDefinitions, ), diff --git a/front/src/modules/companies/table/components/CompanyTable.tsx b/front/src/modules/companies/table/components/CompanyTable.tsx index f4674b176..9527da379 100644 --- a/front/src/modules/companies/table/components/CompanyTable.tsx +++ b/front/src/modules/companies/table/components/CompanyTable.tsx @@ -16,12 +16,11 @@ import { tableFiltersScopedState } from '@/ui/object/record-table/states/tableFi import { tableSortsScopedState } from '@/ui/object/record-table/states/tableSortsScopedState'; import { ViewBar } from '@/views/components/ViewBar'; import { useViewFields } from '@/views/hooks/internal/useViewFields'; -import { useView } from '@/views/hooks/useView'; import { ViewScope } from '@/views/scopes/ViewScope'; -import { columnDefinitionsToViewFields } from '@/views/utils/columnDefinitionToViewField'; -import { viewFieldsToColumnDefinitions } from '@/views/utils/viewFieldsToColumnDefinitions'; -import { viewFiltersToFilters } from '@/views/utils/viewFiltersToFilters'; -import { viewSortsToSorts } from '@/views/utils/viewSortsToSorts'; +import { mapColumnDefinitionsToViewFields } from '@/views/utils/mapColumnDefinitionToViewField'; +import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions'; +import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters'; +import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts'; import { UpdateOneCompanyMutationVariables, useGetCompaniesQuery, @@ -58,9 +57,6 @@ export const CompanyTable = () => { const [getWorkspaceMember] = useGetWorkspaceMembersLazyQuery(); const { persistViewFields } = useViewFields(viewScopeId); - const { setCurrentViewFields } = useView({ - viewScopeId, - }); const { setContextMenuEntries, setActionBarEntries } = useCompanyTableContextMenuEntries(); @@ -102,25 +98,24 @@ export const CompanyTable = () => { viewScopeId={viewScopeId} onViewFieldsChange={(viewFields) => { setTableColumns( - viewFieldsToColumnDefinitions( + mapViewFieldsToColumnDefinitions( viewFields, companiesAvailableFieldDefinitions, ), ); }} onViewFiltersChange={(viewFilters) => { - setTableFilters(viewFiltersToFilters(viewFilters)); + setTableFilters(mapViewFiltersToFilters(viewFilters)); }} onViewSortsChange={(viewSorts) => { - setTableSorts(viewSortsToSorts(viewSorts)); + setTableSorts(mapViewSortsToSorts(viewSorts)); }} > (columns) => { - setCurrentViewFields?.(columnDefinitionsToViewFields(columns)); - persistViewFields(columnDefinitionsToViewFields(columns)); + persistViewFields(mapColumnDefinitionsToViewFields(columns)); }), }} > diff --git a/front/src/modules/metadata/components/RecordTable.tsx b/front/src/modules/metadata/components/RecordTable.tsx index f1ba42446..3cecf0972 100644 --- a/front/src/modules/metadata/components/RecordTable.tsx +++ b/front/src/modules/metadata/components/RecordTable.tsx @@ -10,12 +10,11 @@ import { tableFiltersScopedState } from '@/ui/object/record-table/states/tableFi import { tableSortsScopedState } from '@/ui/object/record-table/states/tableSortsScopedState'; import { ViewBar } from '@/views/components/ViewBar'; import { useViewFields } from '@/views/hooks/internal/useViewFields'; -import { useView } from '@/views/hooks/useView'; import { ViewScope } from '@/views/scopes/ViewScope'; -import { columnDefinitionsToViewFields } from '@/views/utils/columnDefinitionToViewField'; -import { viewFieldsToColumnDefinitions } from '@/views/utils/viewFieldsToColumnDefinitions'; -import { viewFiltersToFilters } from '@/views/utils/viewFiltersToFilters'; -import { viewSortsToSorts } from '@/views/utils/viewSortsToSorts'; +import { mapColumnDefinitionsToViewFields } from '@/views/utils/mapColumnDefinitionToViewField'; +import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions'; +import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters'; +import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts'; import { useObjectMetadataItemInContext } from '../hooks/useObjectMetadataItemInContext'; import { useUpdateOneObject } from '../hooks/useUpdateOneObject'; @@ -46,9 +45,6 @@ export const ObjectTable = ({ objectNamePlural }: ObjectTableProps) => { const viewScopeId = objectNamePlural ?? ''; const { persistViewFields } = useViewFields(viewScopeId); - const { setCurrentViewFields } = useView({ - viewScopeId, - }); const setTableColumns = useSetRecoilState( tableColumnsScopedState(tableScopeId), @@ -81,22 +77,21 @@ export const ObjectTable = ({ objectNamePlural }: ObjectTableProps) => { viewScopeId={viewScopeId} onViewFieldsChange={(viewFields) => { setTableColumns( - viewFieldsToColumnDefinitions(viewFields, columnDefinitions), + mapViewFieldsToColumnDefinitions(viewFields, columnDefinitions), ); }} onViewFiltersChange={(viewFilters) => { - setTableFilters(viewFiltersToFilters(viewFilters)); + setTableFilters(mapViewFiltersToFilters(viewFilters)); }} onViewSortsChange={(viewSorts) => { - setTableSorts(viewSortsToSorts(viewSorts)); + setTableSorts(mapViewSortsToSorts(viewSorts)); }} > (columns) => { - setCurrentViewFields?.(columnDefinitionsToViewFields(columns)); - persistViewFields(columnDefinitionsToViewFields(columns)); + persistViewFields(mapColumnDefinitionsToViewFields(columns)); }), }} > diff --git a/front/src/modules/people/table/components/PersonTable.tsx b/front/src/modules/people/table/components/PersonTable.tsx index ce6d78755..46b35250e 100644 --- a/front/src/modules/people/table/components/PersonTable.tsx +++ b/front/src/modules/people/table/components/PersonTable.tsx @@ -1,10 +1,11 @@ import styled from '@emotion/styled'; -import { useRecoilCallback, useSetRecoilState } from 'recoil'; +import { useSetRecoilState } from 'recoil'; import { peopleAvailableFieldDefinitions } from '@/people/constants/peopleAvailableFieldDefinitions'; import { getPeopleOptimisticEffectDefinition } from '@/people/graphql/optimistic-effect-definitions/getPeopleOptimisticEffectDefinition'; import { usePersonTableContextMenuEntries } from '@/people/hooks/usePersonTableContextMenuEntries'; import { useSpreadsheetPersonImport } from '@/people/hooks/useSpreadsheetPersonImport'; +import { FieldMetadata } from '@/ui/object/field/types/FieldMetadata'; import { RecordTable } from '@/ui/object/record-table/components/RecordTable'; import { RecordTableEffect } from '@/ui/object/record-table/components/RecordTableEffect'; import { TableOptionsDropdownId } from '@/ui/object/record-table/constants/TableOptionsDropdownId'; @@ -14,14 +15,14 @@ import { TableOptionsDropdown } from '@/ui/object/record-table/options/component import { tableColumnsScopedState } from '@/ui/object/record-table/states/tableColumnsScopedState'; import { tableFiltersScopedState } from '@/ui/object/record-table/states/tableFiltersScopedState'; import { tableSortsScopedState } from '@/ui/object/record-table/states/tableSortsScopedState'; +import { ColumnDefinition } from '@/ui/object/record-table/types/ColumnDefinition'; import { ViewBar } from '@/views/components/ViewBar'; import { useViewFields } from '@/views/hooks/internal/useViewFields'; -import { useView } from '@/views/hooks/useView'; import { ViewScope } from '@/views/scopes/ViewScope'; -import { columnDefinitionsToViewFields } from '@/views/utils/columnDefinitionToViewField'; -import { viewFieldsToColumnDefinitions } from '@/views/utils/viewFieldsToColumnDefinitions'; -import { viewFiltersToFilters } from '@/views/utils/viewFiltersToFilters'; -import { viewSortsToSorts } from '@/views/utils/viewSortsToSorts'; +import { mapColumnDefinitionsToViewFields } from '@/views/utils/mapColumnDefinitionToViewField'; +import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions'; +import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters'; +import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts'; import { UpdateOnePersonMutationVariables, useGetPeopleQuery, @@ -49,9 +50,6 @@ export const PersonTable = () => { const upsertRecordTableItem = useUpsertRecordTableItem(); const { persistViewFields } = useViewFields(viewScopeId); - const { setCurrentViewFields } = useView({ - viewScopeId, - }); const { setContextMenuEntries, setActionBarEntries } = usePersonTableContextMenuEntries(); @@ -68,6 +66,10 @@ export const PersonTable = () => { }); }; + const handleColumnChange = (columns: ColumnDefinition[]) => { + persistViewFields(mapColumnDefinitionsToViewFields(columns)); + }; + const { openPersonSpreadsheetImport: onImport } = useSpreadsheetPersonImport(); @@ -82,26 +84,23 @@ export const PersonTable = () => { viewScopeId={viewScopeId} onViewFieldsChange={(viewFields) => { setTableColumns( - viewFieldsToColumnDefinitions( + mapViewFieldsToColumnDefinitions( viewFields, peopleAvailableFieldDefinitions, ), ); }} onViewFiltersChange={(viewFilters) => { - setTableFilters(viewFiltersToFilters(viewFilters)); + setTableFilters(mapViewFiltersToFilters(viewFilters)); }} onViewSortsChange={(viewSorts) => { - setTableSorts(viewSortsToSorts(viewSorts)); + setTableSorts(mapViewSortsToSorts(viewSorts)); }} > (columns) => { - setCurrentViewFields?.(columnDefinitionsToViewFields(columns)); - persistViewFields(columnDefinitionsToViewFields(columns)); - }), + onColumnsChange: handleColumnChange, }} > { const { setViewEditMode, handleViewNameSubmit } = useView(); - const { viewEditMode, currentView } = useViewGetStates(); + const { viewEditModeState, currentViewSelector } = useViewScopedStates(); const { BoardRecoilScopeContext } = useContext(BoardContext); + const viewEditMode = useRecoilValue(viewEditModeState); + const currentView = useRecoilValue(currentViewSelector); + const stageInputRef = useRef(null); const viewEditInputRef = useRef(null); diff --git a/front/src/modules/ui/object/field/states/selectors/isEntityFieldEmptyFamilySelector.ts b/front/src/modules/ui/object/field/states/selectors/isEntityFieldEmptyFamilySelector.ts index d3ce4d5d8..eb49da6ce 100644 --- a/front/src/modules/ui/object/field/states/selectors/isEntityFieldEmptyFamilySelector.ts +++ b/front/src/modules/ui/object/field/states/selectors/isEntityFieldEmptyFamilySelector.ts @@ -10,6 +10,7 @@ import { isFieldEmail } from '../../types/guards/isFieldEmail'; import { isFieldMoney } from '../../types/guards/isFieldMoney'; import { isFieldNumber } from '../../types/guards/isFieldNumber'; import { isFieldPhone } from '../../types/guards/isFieldPhone'; +import { isFieldProbability } from '../../types/guards/isFieldProbability'; import { isFieldRelation } from '../../types/guards/isFieldRelation'; import { isFieldRelationValue } from '../../types/guards/isFieldRelationValue'; import { isFieldText } from '../../types/guards/isFieldText'; @@ -34,6 +35,7 @@ export const isEntityFieldEmptyFamilySelector = selectorFamily({ isFieldURL(fieldDefinition) || isFieldDate(fieldDefinition) || isFieldNumber(fieldDefinition) || + isFieldProbability(fieldDefinition) || isFieldMoney(fieldDefinition) || isFieldEmail(fieldDefinition) || isFieldBoolean(fieldDefinition) || diff --git a/front/src/modules/ui/object/record-table/options/components/TableOptionsDropdownContent.tsx b/front/src/modules/ui/object/record-table/options/components/TableOptionsDropdownContent.tsx index 1357220d6..1b4861050 100644 --- a/front/src/modules/ui/object/record-table/options/components/TableOptionsDropdownContent.tsx +++ b/front/src/modules/ui/object/record-table/options/components/TableOptionsDropdownContent.tsx @@ -1,5 +1,6 @@ import { useCallback, useRef, useState } from 'react'; import { OnDragEndResponder } from '@hello-pangea/dnd'; +import { useRecoilValue } from 'recoil'; import { Key } from 'ts-key-enum'; import { IconChevronLeft, IconFileImport, IconTag } from '@/ui/display/icon'; @@ -12,8 +13,8 @@ import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection'; +import { useViewScopedStates } from '@/views/hooks/internal/useViewScopedStates'; import { useView } from '@/views/hooks/useView'; -import { useViewGetStates } from '@/views/hooks/useViewGetStates'; import { useTableColumns } from '../../hooks/useTableColumns'; import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext'; @@ -29,7 +30,10 @@ export const TableOptionsDropdownContent = ({ onImport?: () => void; }) => { const { setViewEditMode, handleViewNameSubmit } = useView(); - const { viewEditMode, currentView } = useViewGetStates(); + const { viewEditModeState, currentViewSelector } = useViewScopedStates(); + + const viewEditMode = useRecoilValue(viewEditModeState); + const currentView = useRecoilValue(currentViewSelector); const { closeDropdown } = useDropdown(); diff --git a/front/src/modules/ui/utilities/recoil-scope/types/RecoilScopedSelector.ts b/front/src/modules/ui/utilities/recoil-scope/types/RecoilScopedSelector.ts new file mode 100644 index 000000000..99d96b736 --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/types/RecoilScopedSelector.ts @@ -0,0 +1,7 @@ +import { RecoilValueReadOnly } from 'recoil'; + +import { ScopedStateKey } from '../scopes-internal/types/ScopedStateKey'; + +export type RecoilScopedSelector = ( + scopedKey: ScopedStateKey, +) => RecoilValueReadOnly; diff --git a/front/src/modules/ui/utilities/recoil-scope/types/RecoilScopedState.ts b/front/src/modules/ui/utilities/recoil-scope/types/RecoilScopedState.ts new file mode 100644 index 000000000..f17cc4d71 --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/types/RecoilScopedState.ts @@ -0,0 +1,7 @@ +import { RecoilState } from 'recoil'; + +import { ScopedStateKey } from '../scopes-internal/types/ScopedStateKey'; + +export type RecoilScopedState = ( + scopedKey: ScopedStateKey, +) => RecoilState; diff --git a/front/src/modules/ui/utilities/recoil-scope/utils/createScopedSelector.ts b/front/src/modules/ui/utilities/recoil-scope/utils/createScopedSelector.ts new file mode 100644 index 000000000..53e9ca672 --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/utils/createScopedSelector.ts @@ -0,0 +1,30 @@ +import { + GetCallback, + GetRecoilValue, + Loadable, + RecoilValue, + selectorFamily, + WrappedValue, +} from 'recoil'; + +import { ScopedStateKey } from '../scopes-internal/types/ScopedStateKey'; + +type SelectorGetter = ( + param: P, +) => (opts: { + get: GetRecoilValue; + getCallback: GetCallback; +}) => Promise | RecoilValue | Loadable | WrappedValue | T; + +export const createScopedSelector = ({ + key, + get, +}: { + key: string; + get: SelectorGetter; +}) => { + return selectorFamily({ + key, + get, + }); +}; diff --git a/front/src/modules/ui/utilities/recoil-scope/utils/getScopedFamilyState.ts b/front/src/modules/ui/utilities/recoil-scope/utils/getScopedFamilyState.ts new file mode 100644 index 000000000..8d516e820 --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/utils/getScopedFamilyState.ts @@ -0,0 +1,19 @@ +import { RecoilState, SerializableParam } from 'recoil'; + +import { ScopedFamilyStateKey } from '../scopes-internal/types/ScopedFamilyStateKey'; + +export const getScopedFamilyState = < + StateType, + FamilyKey extends SerializableParam, +>( + recoilState: ( + scopedFamilyKey: ScopedFamilyStateKey, + ) => RecoilState, + scopeId: string, + familyKey: FamilyKey, +) => { + return recoilState({ + scopeId, + familyKey: familyKey || ('' as FamilyKey), + }); +}; diff --git a/front/src/modules/ui/utilities/recoil-scope/utils/getScopedSelector.ts b/front/src/modules/ui/utilities/recoil-scope/utils/getScopedSelector.ts new file mode 100644 index 000000000..2998d3f30 --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/utils/getScopedSelector.ts @@ -0,0 +1,10 @@ +import { RecoilScopedSelector } from '../types/RecoilScopedSelector'; + +export const getScopedSelector = ( + recoilScopedState: RecoilScopedSelector, + scopeId: string, +) => { + return recoilScopedState({ + scopeId, + }); +}; diff --git a/front/src/modules/ui/utilities/recoil-scope/utils/getScopedState.ts b/front/src/modules/ui/utilities/recoil-scope/utils/getScopedState.ts new file mode 100644 index 000000000..10be20e4b --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/utils/getScopedState.ts @@ -0,0 +1,10 @@ +import { RecoilScopedState } from '../types/RecoilScopedState'; + +export const getScopedState = ( + recoilScopedState: RecoilScopedState, + scopeId: string, +) => { + return recoilScopedState({ + scopeId, + }); +}; diff --git a/front/src/modules/ui/utilities/recoil-scope/utils/getSnapshotScopedSelector.ts b/front/src/modules/ui/utilities/recoil-scope/utils/getSnapshotScopedSelector.ts new file mode 100644 index 000000000..73c084793 --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/utils/getSnapshotScopedSelector.ts @@ -0,0 +1,15 @@ +import { Snapshot } from 'recoil'; + +import { RecoilScopedSelector } from '../types/RecoilScopedSelector'; + +import { getScopedSelector } from './getScopedSelector'; + +export const getSnapshotScopedSelector = ( + snapshot: Snapshot, + scopedState: RecoilScopedSelector, + scopeId: string, +) => { + return snapshot + .getLoadable(getScopedSelector(scopedState, scopeId)) + .getValue(); +}; diff --git a/front/src/modules/ui/utilities/recoil-scope/utils/getSnapshotScopedValue.ts b/front/src/modules/ui/utilities/recoil-scope/utils/getSnapshotScopedValue.ts new file mode 100644 index 000000000..596283788 --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/utils/getSnapshotScopedValue.ts @@ -0,0 +1,13 @@ +import { Snapshot } from 'recoil'; + +import { RecoilScopedState } from '../types/RecoilScopedState'; + +import { getScopedState } from './getScopedState'; + +export const getSnapshotScopedValue = ( + snapshot: Snapshot, + scopedState: RecoilScopedState, + scopeId: string, +) => { + return snapshot.getLoadable(getScopedState(scopedState, scopeId)).getValue(); +}; diff --git a/front/src/modules/ui/utilities/recoil-scope/utils/getSnapshotValue.ts b/front/src/modules/ui/utilities/recoil-scope/utils/getSnapshotValue.ts new file mode 100644 index 000000000..711d21a4a --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/utils/getSnapshotValue.ts @@ -0,0 +1,8 @@ +import { RecoilState, RecoilValueReadOnly, Snapshot } from 'recoil'; + +export const getSnapshotValue = ( + snapshot: Snapshot, + state: RecoilState | RecoilValueReadOnly, +) => { + return snapshot.getLoadable(state).getValue(); +}; diff --git a/front/src/modules/views/components/UpdateViewButtonGroup.tsx b/front/src/modules/views/components/UpdateViewButtonGroup.tsx index d94ee56e6..b5660584d 100644 --- a/front/src/modules/views/components/UpdateViewButtonGroup.tsx +++ b/front/src/modules/views/components/UpdateViewButtonGroup.tsx @@ -1,5 +1,6 @@ import { useCallback, useState } from 'react'; import styled from '@emotion/styled'; +import { useRecoilValue } from 'recoil'; import { Key } from 'ts-key-enum'; import { IconChevronDown, IconPlus } from '@/ui/display/icon'; @@ -10,13 +11,14 @@ import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { useView } from '@/views/hooks/useView'; -import { useViewGetStates } from '../hooks/useViewGetStates'; +import { useViewScopedStates } from '../hooks/internal/useViewScopedStates'; const StyledContainer = styled.div` display: inline-flex; margin-right: ${({ theme }) => theme.spacing(2)}; position: relative; `; + export type UpdateViewButtonGroupProps = { hotkeyScope: string; onViewEditModeChange?: () => void; @@ -28,7 +30,11 @@ export const UpdateViewButtonGroup = ({ }: UpdateViewButtonGroupProps) => { const [isDropdownOpen, setIsDropdownOpen] = useState(false); const { updateCurrentView, setViewEditMode } = useView(); - const { canPersistFilters, canPersistSorts } = useViewGetStates(); + const { canPersistFiltersSelector, canPersistSortsSelector } = + useViewScopedStates(); + + const canPersistFilters = useRecoilValue(canPersistFiltersSelector); + const canPersistSorts = useRecoilValue(canPersistSortsSelector); const canPersistView = canPersistFilters || canPersistSorts; diff --git a/front/src/modules/views/components/ViewBar.tsx b/front/src/modules/views/components/ViewBar.tsx index 7b24cc7cd..2f4788714 100644 --- a/front/src/modules/views/components/ViewBar.tsx +++ b/front/src/modules/views/components/ViewBar.tsx @@ -1,4 +1,5 @@ import { ReactNode } from 'react'; +import { useRecoilValue } from 'recoil'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { TopBar } from '@/ui/layout/top-bar/TopBar'; @@ -8,8 +9,8 @@ import { FiltersHotkeyScope } from '@/ui/object/object-filter-dropdown/types/Fil import { ObjectSortDropdownButton } from '@/ui/object/object-sort-dropdown/components/ObjectSortDropdownButton'; import { ObjectSortDropdownScope } from '@/ui/object/object-sort-dropdown/scopes/ObjectSortDropdownScope'; +import { useViewScopedStates } from '../hooks/internal/useViewScopedStates'; import { useView } from '../hooks/useView'; -import { useViewGetStates } from '../hooks/useViewGetStates'; import { ViewsHotkeyScope } from '../types/ViewsHotkeyScope'; import { UpdateViewButtonGroup } from './UpdateViewButtonGroup'; @@ -32,8 +33,16 @@ export const ViewBar = ({ dropdownScopeId: optionsDropdownScopeId, }); const { upsertViewSort, upsertViewFilter } = useView(); - const { availableFilterDefinitions, availableSortDefinitions } = - useViewGetStates(); + + const { availableFilterDefinitionsState, availableSortDefinitionsState } = + useViewScopedStates(); + + const availableFilterDefinitions = useRecoilValue( + availableFilterDefinitionsState, + ); + const availableSortDefinitions = useRecoilValue( + availableSortDefinitionsState, + ); return ( { const { - currentViewSorts, - currentViewFilters, - canPersistFilters, - canPersistSorts, - isViewBarExpanded, - } = useViewGetStates(); + currentViewSortsState, + currentViewFiltersState, + canPersistFiltersSelector, + canPersistSortsSelector, + isViewBarExpandedState, + } = useViewScopedStates(); + + const currentViewSorts = useRecoilValue(currentViewSortsState); + const currentViewFilters = useRecoilValue(currentViewFiltersState); + const canPersistFilters = useRecoilValue(canPersistFiltersSelector); + const canPersistSorts = useRecoilValue(canPersistSortsSelector); + const isViewBarExpanded = useRecoilValue(isViewBarExpandedState); const { resetViewBar, removeViewSort, removeViewFilter } = useView(); diff --git a/front/src/modules/views/components/ViewBarEffect.tsx b/front/src/modules/views/components/ViewBarEffect.tsx index dc4e74382..24e97e52a 100644 --- a/front/src/modules/views/components/ViewBarEffect.tsx +++ b/front/src/modules/views/components/ViewBarEffect.tsx @@ -1,66 +1,58 @@ import { useEffect } from 'react'; import { useSearchParams } from 'react-router-dom'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilCallback, useRecoilValue } from 'recoil'; import { useFindManyObjects } from '@/metadata/hooks/useFindManyObjects'; import { PaginatedObjectTypeResults } from '@/metadata/types/PaginatedObjectTypeResults'; +import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; import { assertNotNull } from '~/utils/assert'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; +import { useViewScopedStates } from '../hooks/internal/useViewScopedStates'; import { useView } from '../hooks/useView'; -import { useViewGetStates } from '../hooks/useViewGetStates'; -import { availableFieldDefinitionsScopedState } from '../states/availableFieldDefinitionsScopedState'; -import { availableFilterDefinitionsScopedState } from '../states/availableFilterDefinitionsScopedState'; -import { availableSortDefinitionsScopedState } from '../states/availableSortDefinitionsScopedState'; -import { onViewFieldsChangeScopedState } from '../states/onViewFieldsChangeScopedState'; -import { onViewFiltersChangeScopedState } from '../states/onViewFiltersChangeScopedState'; -import { onViewSortsChangeScopedState } from '../states/onViewSortsChangeScopedState'; -import { savedViewFieldsScopedFamilyState } from '../states/savedViewFieldsScopedFamilyState'; -import { savedViewFiltersScopedFamilyState } from '../states/savedViewFiltersScopedFamilyState'; -import { savedViewSortsScopedFamilyState } from '../states/savedViewSortsScopedFamilyState'; -import { viewsScopedState } from '../states/viewsScopedState'; import { View } from '../types/View'; import { ViewField } from '../types/ViewField'; import { ViewFilter } from '../types/ViewFilter'; import { ViewSort } from '../types/ViewSort'; +import { getViewScopedStatesFromSnapshot } from '../utils/getViewScopedStatesFromSnapshot'; +import { getViewScopedStateValuesFromSnapshot } from '../utils/getViewScopedStateValuesFromSnapshot'; export const ViewBarEffect = () => { const { scopeId: viewScopeId, - setCurrentViewFields, - setSavedViewFields, - setCurrentViewFilters, - setSavedViewFilters, - setCurrentViewSorts, - setSavedViewSorts, currentViewId, - setViews, loadView, changeViewInUrl, - setCurrentViewId, } = useView(); const [searchParams] = useSearchParams(); const currentViewIdFromUrl = searchParams.get('view'); - const { viewType, viewObjectId } = useViewGetStates(viewScopeId); + const { viewTypeState, viewObjectIdState } = useViewScopedStates(); + + const viewType = useRecoilValue(viewTypeState); + const viewObjectId = useRecoilValue(viewObjectIdState); useFindManyObjects({ objectNamePlural: 'viewsV2', filter: { type: { eq: viewType }, objectId: { eq: viewObjectId } }, onCompleted: useRecoilCallback( - ({ snapshot }) => + ({ snapshot, set }) => async (data: PaginatedObjectTypeResults) => { const nextViews = data.edges.map((view) => ({ id: view.node.id, name: view.node.name, objectId: view.node.objectId, })); - const views = snapshot - .getLoadable(viewsScopedState({ scopeId: viewScopeId })) - .getValue(); - if (!isDeeplyEqual(views, nextViews)) setViews(nextViews); + const { viewsState } = getViewScopedStatesFromSnapshot({ + snapshot, + viewScopeId, + }); + + const views = getSnapshotValue(snapshot, viewsState); + + if (!isDeeplyEqual(views, nextViews)) set(viewsState, nextViews); if (!nextViews.length) return; @@ -74,43 +66,39 @@ export const ViewBarEffect = () => { objectNamePlural: 'viewFieldsV2', filter: { viewId: { eq: currentViewId } }, onCompleted: useRecoilCallback( - ({ snapshot }) => + ({ snapshot, set }) => async (data: PaginatedObjectTypeResults) => { - const availableFields = snapshot - .getLoadable( - availableFieldDefinitionsScopedState({ scopeId: viewScopeId }), - ) - .getValue(); + const { + availableFieldDefinitions, + onViewFieldsChange, + savedViewFields, + currentViewId, + } = getViewScopedStateValuesFromSnapshot({ + snapshot, + viewScopeId, + }); - const onViewFieldsChange = snapshot - .getLoadable( - onViewFieldsChangeScopedState({ scopeId: viewScopeId }), - ) - .getValue(); + const { savedViewFieldsState, currentViewFieldsState } = + getViewScopedStatesFromSnapshot({ + snapshot, + viewScopeId, + }); - if (!availableFields || !currentViewId) { + if (!availableFieldDefinitions || !currentViewId) { return; } - const savedViewFields = snapshot - .getLoadable( - savedViewFieldsScopedFamilyState({ - scopeId: viewScopeId, - familyKey: currentViewId, - }), - ) - .getValue(); - const queriedViewFields = data.edges .map((viewField) => viewField.node) .filter(assertNotNull); if (!isDeeplyEqual(savedViewFields, queriedViewFields)) { - setCurrentViewFields?.(queriedViewFields); - setSavedViewFields?.(queriedViewFields); + set(currentViewFieldsState, queriedViewFields); + set(savedViewFieldsState, queriedViewFields); onViewFieldsChange?.(queriedViewFields); } }, + [viewScopeId], ), }); @@ -119,33 +107,28 @@ export const ViewBarEffect = () => { objectNamePlural: 'viewFiltersV2', filter: { viewId: { eq: currentViewId } }, onCompleted: useRecoilCallback( - ({ snapshot }) => + ({ snapshot, set }) => async (data: PaginatedObjectTypeResults>) => { - const availableFilterDefinitions = snapshot - .getLoadable( - availableFilterDefinitionsScopedState({ scopeId: viewScopeId }), - ) - .getValue(); + const { + availableFilterDefinitions, + savedViewFilters, + onViewFiltersChange, + currentViewId, + } = getViewScopedStateValuesFromSnapshot({ + snapshot, + viewScopeId, + }); + + const { savedViewFiltersState, currentViewFiltersState } = + getViewScopedStatesFromSnapshot({ + snapshot, + viewScopeId, + }); if (!availableFilterDefinitions || !currentViewId) { return; } - const savedViewFilters = snapshot - .getLoadable( - savedViewFiltersScopedFamilyState({ - scopeId: viewScopeId, - familyKey: currentViewId, - }), - ) - .getValue(); - - const onViewFiltersChange = snapshot - .getLoadable( - onViewFiltersChangeScopedState({ scopeId: viewScopeId }), - ) - .getValue(); - const queriedViewFilters = data.edges .map(({ node }) => { const availableFilterDefinition = availableFilterDefinitions.find( @@ -163,11 +146,12 @@ export const ViewBarEffect = () => { .filter(assertNotNull); if (!isDeeplyEqual(savedViewFilters, queriedViewFilters)) { - setSavedViewFilters?.(queriedViewFilters); - setCurrentViewFilters?.(queriedViewFilters); + set(savedViewFiltersState, queriedViewFilters); + set(currentViewFiltersState, queriedViewFilters); onViewFiltersChange?.(queriedViewFilters); } }, + [viewScopeId], ), }); @@ -176,31 +160,28 @@ export const ViewBarEffect = () => { objectNamePlural: 'viewSortsV2', filter: { viewId: { eq: currentViewId } }, onCompleted: useRecoilCallback( - ({ snapshot }) => + ({ snapshot, set }) => async (data: PaginatedObjectTypeResults>) => { - const availableSortDefinitions = snapshot - .getLoadable( - availableSortDefinitionsScopedState({ scopeId: viewScopeId }), - ) - .getValue(); + const { + availableSortDefinitions, + savedViewSorts, + onViewSortsChange, + currentViewId, + } = getViewScopedStateValuesFromSnapshot({ + snapshot, + viewScopeId, + }); + + const { savedViewSortsState, currentViewSortsState } = + getViewScopedStatesFromSnapshot({ + snapshot, + viewScopeId, + }); if (!availableSortDefinitions || !currentViewId) { return; } - const savedViewSorts = snapshot - .getLoadable( - savedViewSortsScopedFamilyState({ - scopeId: viewScopeId, - familyKey: currentViewId, - }), - ) - .getValue(); - - const onViewSortsChange = snapshot - .getLoadable(onViewSortsChangeScopedState({ scopeId: viewScopeId })) - .getValue(); - const queriedViewSorts = data.edges .map(({ node }) => { const availableSortDefinition = availableSortDefinitions.find( @@ -219,18 +200,20 @@ export const ViewBarEffect = () => { .filter(assertNotNull); if (!isDeeplyEqual(savedViewSorts, queriedViewSorts)) { - setSavedViewSorts?.(queriedViewSorts); - setCurrentViewSorts?.(queriedViewSorts); + set(savedViewSortsState, queriedViewSorts); + set(currentViewSortsState, queriedViewSorts); onViewSortsChange?.(queriedViewSorts); } }, + [viewScopeId], ), }); useEffect(() => { if (!currentViewIdFromUrl) return; + loadView(currentViewIdFromUrl); - }, [currentViewIdFromUrl, loadView, setCurrentViewId]); + }, [currentViewIdFromUrl, loadView]); return <>; }; diff --git a/front/src/modules/views/components/ViewsDropdownButton.tsx b/front/src/modules/views/components/ViewsDropdownButton.tsx index 86a5007dc..72b223cdd 100644 --- a/front/src/modules/views/components/ViewsDropdownButton.tsx +++ b/front/src/modules/views/components/ViewsDropdownButton.tsx @@ -1,7 +1,7 @@ import { MouseEvent } from 'react'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilCallback, useRecoilValue } from 'recoil'; import { IconChevronDown, @@ -22,8 +22,8 @@ import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; import { assertNotNull } from '~/utils/assert'; import { ViewsDropdownId } from '../constants/ViewsDropdownId'; +import { useViewScopedStates } from '../hooks/internal/useViewScopedStates'; import { useView } from '../hooks/useView'; -import { useViewGetStates } from '../hooks/useViewGetStates'; const StyledBoldDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)` font-weight: ${({ theme }) => theme.font.weight.regular}; @@ -68,12 +68,17 @@ export const ViewsDropdownButton = ({ optionsDropdownScopeId, }: ViewsDropdownButtonProps) => { const theme = useTheme(); - const { scopeId, removeView, currentViewId, changeViewInUrl } = useView(); + const { removeView, changeViewInUrl } = useView(); - const { views, currentView, entityCountInCurrentView } = useViewGetStates( - scopeId, - currentViewId, + const { viewsState, currentViewSelector, entityCountInCurrentViewState } = + useViewScopedStates(); + + const views = useRecoilValue(viewsState); + const currentView = useRecoilValue(currentViewSelector); + const entityCountInCurrentView = useRecoilValue( + entityCountInCurrentViewState, ); + const { setViewEditMode } = useView(); const { diff --git a/front/src/modules/views/constants/index.ts b/front/src/modules/views/constants/index.ts new file mode 100644 index 000000000..932654ac3 --- /dev/null +++ b/front/src/modules/views/constants/index.ts @@ -0,0 +1,2 @@ +// TODO: find a better pattern than using '' as a fallback +export const UNDEFINED_FAMILY_ITEM_ID = ''; diff --git a/front/src/modules/views/hooks/internal/useViewFields.ts b/front/src/modules/views/hooks/internal/useViewFields.ts index 359f8046a..80b51ecaf 100644 --- a/front/src/modules/views/hooks/internal/useViewFields.ts +++ b/front/src/modules/views/hooks/internal/useViewFields.ts @@ -2,37 +2,28 @@ import { useApolloClient } from '@apollo/client'; import { useRecoilCallback } from 'recoil'; import { useFindOneObjectMetadataItem } from '@/metadata/hooks/useFindOneObjectMetadataItem'; -import { currentViewIdScopedState } from '@/views/states/currentViewIdScopedState'; -import { savedViewFieldByKeyScopedFamilySelector } from '@/views/states/selectors/savedViewFieldByKeyScopedFamilySelector'; -import { viewObjectIdScopeState } from '@/views/states/viewObjectIdScopeState'; import { ViewField } from '@/views/types/ViewField'; +import { getViewScopedStateValuesFromSnapshot } from '@/views/utils/getViewScopedStateValuesFromSnapshot'; export const useViewFields = (viewScopeId: string) => { const { updateOneMutation, createOneMutation, findManyQuery } = useFindOneObjectMetadataItem({ objectNameSingular: 'viewFieldV2', }); + const apolloClient = useApolloClient(); const persistViewFields = useRecoilCallback( ({ snapshot }) => async (viewFieldsToPersist: ViewField[], viewId?: string) => { - const currentViewId = snapshot - .getLoadable(currentViewIdScopedState({ scopeId: viewScopeId })) - .getValue(); + const { viewObjectId, currentViewId, savedViewFieldsByKey } = + getViewScopedStateValuesFromSnapshot({ + snapshot, + viewScopeId, + viewId, + }); - const viewObjectId = snapshot - .getLoadable(viewObjectIdScopeState({ scopeId: viewScopeId })) - .getValue(); - - const savedViewFieldsByKey = snapshot - .getLoadable( - savedViewFieldByKeyScopedFamilySelector({ - viewScopeId: viewScopeId, - viewId: viewId ?? currentViewId, - }), - ) - .getValue(); + const viewIdToPersist = viewId ?? currentViewId; if (!currentViewId || !savedViewFieldsByKey || !viewObjectId) { return; @@ -50,7 +41,7 @@ export const useViewFields = (viewScopeId: string) => { variables: { input: { fieldId: viewField.fieldId, - viewId: viewId, + viewId: viewIdToPersist, isVisible: viewField.isVisible, size: viewField.size, position: viewField.position, @@ -87,7 +78,6 @@ export const useViewFields = (viewScopeId: string) => { const viewFieldsToCreate = viewFieldsToPersist.filter( (viewField) => !savedViewFieldsByKey[viewField.fieldId], ); - await _createViewFields(viewFieldsToCreate); const viewFieldsToUpdate = viewFieldsToPersist.filter( (viewFieldToPersit) => @@ -100,8 +90,17 @@ export const useViewFields = (viewScopeId: string) => { viewFieldToPersit.isVisible), ); + await _createViewFields(viewFieldsToCreate); + await _updateViewFields(viewFieldsToUpdate); }, + [ + apolloClient, + createOneMutation, + findManyQuery, + updateOneMutation, + viewScopeId, + ], ); return { persistViewFields }; diff --git a/front/src/modules/views/hooks/internal/useViewFilters.ts b/front/src/modules/views/hooks/internal/useViewFilters.ts index d4e51b947..5e63ae5af 100644 --- a/front/src/modules/views/hooks/internal/useViewFilters.ts +++ b/front/src/modules/views/hooks/internal/useViewFilters.ts @@ -4,14 +4,11 @@ import { useRecoilCallback } from 'recoil'; import { useFindOneObjectMetadataItem } from '@/metadata/hooks/useFindOneObjectMetadataItem'; import { Filter } from '@/ui/object/object-filter-dropdown/types/Filter'; -import { currentViewFiltersScopedFamilyState } from '@/views/states/currentViewFiltersScopedFamilyState'; -import { currentViewIdScopedState } from '@/views/states/currentViewIdScopedState'; -import { onViewFiltersChangeScopedState } from '@/views/states/onViewFiltersChangeScopedState'; import { savedViewFiltersScopedFamilyState } from '@/views/states/savedViewFiltersScopedFamilyState'; -import { savedViewFiltersByKeyScopedFamilySelector } from '@/views/states/selectors/savedViewFiltersByKeyScopedFamilySelector'; import { ViewFilter } from '@/views/types/ViewFilter'; +import { getViewScopedStateValuesFromSnapshot } from '@/views/utils/getViewScopedStateValuesFromSnapshot'; -import { useViewSetStates } from '../useViewSetStates'; +import { useViewScopedStates } from './useViewScopedStates'; export const useViewFilters = (viewScopeId: string) => { const { @@ -23,17 +20,27 @@ export const useViewFilters = (viewScopeId: string) => { objectNameSingular: 'viewFilterV2', }); const apolloClient = useApolloClient(); - const { setCurrentViewFilters } = useViewSetStates(viewScopeId); + + const { currentViewFiltersState } = useViewScopedStates(); const persistViewFilters = useRecoilCallback( ({ snapshot, set }) => async (viewId?: string) => { - const currentViewId = snapshot - .getLoadable(currentViewIdScopedState({ scopeId: viewScopeId })) - .getValue(); + const { currentViewId, currentViewFilters, savedViewFiltersByKey } = + getViewScopedStateValuesFromSnapshot({ + snapshot, + viewScopeId, + }); + if (!currentViewId) { return; } + if (!currentViewFilters) { + return; + } + if (!savedViewFiltersByKey) { + return; + } const createViewFilters = (viewFiltersToCreate: ViewFilter[]) => { if (!viewFiltersToCreate.length) return; @@ -92,31 +99,6 @@ export const useViewFilters = (viewScopeId: string) => { ); }; - const currentViewFilters = snapshot - .getLoadable( - currentViewFiltersScopedFamilyState({ - scopeId: viewScopeId, - familyKey: currentViewId, - }), - ) - .getValue(); - - const savedViewFiltersByKey = snapshot - .getLoadable( - savedViewFiltersByKeyScopedFamilySelector({ - scopeId: viewScopeId, - viewId: viewId ?? currentViewId, - }), - ) - .getValue(); - - if (!currentViewFilters) { - return; - } - if (!savedViewFiltersByKey) { - return; - } - const filtersToCreate = currentViewFilters.filter( (filter) => !savedViewFiltersByKey[filter.fieldId], ); @@ -158,37 +140,26 @@ export const useViewFilters = (viewScopeId: string) => { ); const upsertViewFilter = useRecoilCallback( - ({ snapshot }) => + ({ snapshot, set }) => (filterToUpsert: Filter) => { - const currentViewId = snapshot - .getLoadable(currentViewIdScopedState({ scopeId: viewScopeId })) - .getValue(); + const { currentViewId, savedViewFiltersByKey, onViewFiltersChange } = + getViewScopedStateValuesFromSnapshot({ + snapshot, + viewScopeId, + }); if (!currentViewId) { return; } - const savedViewFiltersByKey = snapshot - .getLoadable( - savedViewFiltersByKeyScopedFamilySelector({ - scopeId: viewScopeId, - viewId: currentViewId, - }), - ) - .getValue(); - if (!savedViewFiltersByKey) { return; } - const onViewFiltersChange = snapshot - .getLoadable(onViewFiltersChangeScopedState({ scopeId: viewScopeId })) - .getValue(); - const existingSavedFilterId = savedViewFiltersByKey[filterToUpsert.fieldId]?.id; - setCurrentViewFilters?.((filters) => { + set(currentViewFiltersState, (filters) => { const newViewFilters = produce(filters, (filtersDraft) => { const existingFilterIndex = filtersDraft.findIndex( (filter) => filter.fieldId === filterToUpsert.fieldId, @@ -211,38 +182,29 @@ export const useViewFilters = (viewScopeId: string) => { return newViewFilters; }); }, + [currentViewFiltersState, viewScopeId], ); const removeViewFilter = useRecoilCallback( - ({ snapshot }) => + ({ snapshot, set }) => (fieldId: string) => { - const currentViewId = snapshot - .getLoadable(currentViewIdScopedState({ scopeId: viewScopeId })) - .getValue(); + const { currentViewId, currentViewFilters, onViewFiltersChange } = + getViewScopedStateValuesFromSnapshot({ + snapshot, + viewScopeId, + }); if (!currentViewId) { return; } - const onViewFiltersChange = snapshot - .getLoadable(onViewFiltersChangeScopedState({ scopeId: viewScopeId })) - .getValue(); - - const currentViewFilters = snapshot - .getLoadable( - currentViewFiltersScopedFamilyState({ - scopeId: viewScopeId, - familyKey: currentViewId, - }), - ) - .getValue(); - const newViewFilters = currentViewFilters.filter((filter) => { return filter.fieldId !== fieldId; }); - setCurrentViewFilters?.(newViewFilters); + set(currentViewFiltersState, newViewFilters); onViewFiltersChange?.(newViewFilters); }, + [currentViewFiltersState, viewScopeId], ); return { persistViewFilters, removeViewFilter, upsertViewFilter }; diff --git a/front/src/modules/views/hooks/internal/useViewScopedStates.ts b/front/src/modules/views/hooks/internal/useViewScopedStates.ts new file mode 100644 index 000000000..3bb97ddf0 --- /dev/null +++ b/front/src/modules/views/hooks/internal/useViewScopedStates.ts @@ -0,0 +1,84 @@ +import { useRecoilState } from 'recoil'; + +import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; +import { getScopedState } from '@/ui/utilities/recoil-scope/utils/getScopedState'; + +import { UNDEFINED_FAMILY_ITEM_ID } from '../../constants'; +import { ViewScopeInternalContext } from '../../scopes/scope-internal-context/ViewScopeInternalContext'; +import { currentViewIdScopedState } from '../../states/currentViewIdScopedState'; +import { getViewScopedStates } from '../../utils/internal/getViewScopedStates'; + +export const useViewScopedStates = (args?: { customViewScopeId?: string }) => { + const { customViewScopeId } = args ?? {}; + + const scopeId = useAvailableScopeIdOrThrow( + ViewScopeInternalContext, + customViewScopeId, + ); + + // View + const [currentViewId] = useRecoilState( + getScopedState(currentViewIdScopedState, scopeId), + ); + + const viewId = currentViewId ?? UNDEFINED_FAMILY_ITEM_ID; + + const { + availableFieldDefinitionsState, + availableFilterDefinitionsState, + availableSortDefinitionsState, + canPersistFiltersSelector, + canPersistSortsSelector, + currentViewFieldsState, + currentViewFiltersState, + currentViewIdState, + currentViewSelector, + currentViewSortsState, + entityCountInCurrentViewState, + isViewBarExpandedState, + onViewFieldsChangeState, + onViewFiltersChangeState, + onViewSortsChangeState, + savedViewFieldsByKeySelector, + savedViewFieldsState, + savedViewFiltersByKeySelector, + savedViewFiltersState, + savedViewSortsByKeySelector, + savedViewSortsState, + viewEditModeState, + viewObjectIdState, + viewTypeState, + viewsState, + } = getViewScopedStates({ + viewScopeId: scopeId, + viewId, + }); + + return { + availableFieldDefinitionsState, + availableFilterDefinitionsState, + availableSortDefinitionsState, + canPersistFiltersSelector, + canPersistSortsSelector, + currentViewFieldsState, + currentViewFiltersState, + currentViewIdState, + currentViewSelector, + currentViewSortsState, + entityCountInCurrentViewState, + isViewBarExpandedState, + onViewFieldsChangeState, + onViewFiltersChangeState, + onViewSortsChangeState, + savedViewFieldsByKeySelector, + savedViewFieldsState, + savedViewFiltersByKeySelector, + savedViewFiltersState, + savedViewSortsByKeySelector, + savedViewSortsState, + viewEditModeState, + viewObjectIdState, + viewTypeState, + viewsState, + }; +}; diff --git a/front/src/modules/views/hooks/internal/useViewSorts.ts b/front/src/modules/views/hooks/internal/useViewSorts.ts index 0565cc530..95a30ef62 100644 --- a/front/src/modules/views/hooks/internal/useViewSorts.ts +++ b/front/src/modules/views/hooks/internal/useViewSorts.ts @@ -4,14 +4,11 @@ import { useRecoilCallback } from 'recoil'; import { useFindOneObjectMetadataItem } from '@/metadata/hooks/useFindOneObjectMetadataItem'; import { Sort } from '@/ui/object/object-sort-dropdown/types/Sort'; -import { currentViewIdScopedState } from '@/views/states/currentViewIdScopedState'; -import { currentViewSortsScopedFamilyState } from '@/views/states/currentViewSortsScopedFamilyState'; -import { onViewSortsChangeScopedState } from '@/views/states/onViewSortsChangeScopedState'; import { savedViewSortsScopedFamilyState } from '@/views/states/savedViewSortsScopedFamilyState'; -import { savedViewSortsByKeyScopedFamilySelector } from '@/views/states/selectors/savedViewSortsByKeyScopedFamilySelector'; import { ViewSort } from '@/views/types/ViewSort'; +import { getViewScopedStateValuesFromSnapshot } from '@/views/utils/getViewScopedStateValuesFromSnapshot'; -import { useViewSetStates } from '../useViewSetStates'; +import { useViewScopedStates } from './useViewScopedStates'; export const useViewSorts = (viewScopeId: string) => { const { @@ -23,18 +20,29 @@ export const useViewSorts = (viewScopeId: string) => { objectNameSingular: 'viewSortV2', }); const apolloClient = useApolloClient(); - const { setCurrentViewSorts } = useViewSetStates(viewScopeId); + + const { currentViewSortsState } = useViewScopedStates(); const persistViewSorts = useRecoilCallback( ({ snapshot, set }) => async (viewId?: string) => { - const currentViewId = snapshot - .getLoadable(currentViewIdScopedState({ scopeId: viewScopeId })) - .getValue(); + const { currentViewId, currentViewSorts, savedViewSortsByKey } = + getViewScopedStateValuesFromSnapshot({ + snapshot, + viewScopeId, + }); + if (!currentViewId) { return; } + if (!currentViewSorts) { + return; + } + if (!savedViewSortsByKey) { + return; + } + const createViewSorts = (viewSortsToCreate: ViewSort[]) => { if (!viewSortsToCreate.length) return; @@ -88,31 +96,6 @@ export const useViewSorts = (viewScopeId: string) => { ); }; - const currentViewSorts = snapshot - .getLoadable( - currentViewSortsScopedFamilyState({ - scopeId: viewScopeId, - familyKey: currentViewId, - }), - ) - .getValue(); - - const savedViewSortsByKey = snapshot - .getLoadable( - savedViewSortsByKeyScopedFamilySelector({ - scopeId: viewScopeId, - viewId: viewId ?? currentViewId, - }), - ) - .getValue(); - - if (!currentViewSorts) { - return; - } - if (!savedViewSortsByKey) { - return; - } - const sortsToCreate = currentViewSorts.filter( (sort) => !savedViewSortsByKey[sort.fieldId], ); @@ -153,37 +136,26 @@ export const useViewSorts = (viewScopeId: string) => { ); const upsertViewSort = useRecoilCallback( - ({ snapshot }) => + ({ snapshot, set }) => (sortToUpsert: Sort) => { - const currentViewId = snapshot - .getLoadable(currentViewIdScopedState({ scopeId: viewScopeId })) - .getValue(); + const { currentViewId, onViewSortsChange, savedViewSortsByKey } = + getViewScopedStateValuesFromSnapshot({ + snapshot, + viewScopeId, + }); if (!currentViewId) { return; } - const savedViewSortsByKey = snapshot - .getLoadable( - savedViewSortsByKeyScopedFamilySelector({ - scopeId: viewScopeId, - viewId: currentViewId, - }), - ) - .getValue(); - if (!savedViewSortsByKey) { return; } - const onViewSortsChange = snapshot - .getLoadable(onViewSortsChangeScopedState({ scopeId: viewScopeId })) - .getValue(); - const existingSavedSortId = savedViewSortsByKey[sortToUpsert.fieldId]?.id; - setCurrentViewSorts?.((sorts) => { + set(currentViewSortsState, (sorts) => { const newViewSorts = produce(sorts, (sortsDraft) => { const existingSortIndex = sortsDraft.findIndex( (sort) => sort.fieldId === sortToUpsert.fieldId, @@ -203,38 +175,29 @@ export const useViewSorts = (viewScopeId: string) => { return newViewSorts; }); }, + [currentViewSortsState, viewScopeId], ); const removeViewSort = useRecoilCallback( - ({ snapshot }) => + ({ snapshot, set }) => (fieldId: string) => { - const currentViewId = snapshot - .getLoadable(currentViewIdScopedState({ scopeId: viewScopeId })) - .getValue(); + const { currentViewId, onViewSortsChange, currentViewSorts } = + getViewScopedStateValuesFromSnapshot({ + snapshot, + viewScopeId, + }); if (!currentViewId) { return; } - const onViewSortsChange = snapshot - .getLoadable(onViewSortsChangeScopedState({ scopeId: viewScopeId })) - .getValue(); - - const currentViewSorts = snapshot - .getLoadable( - currentViewSortsScopedFamilyState({ - scopeId: viewScopeId, - familyKey: currentViewId, - }), - ) - .getValue(); - const newViewSorts = currentViewSorts.filter((filter) => { return filter.fieldId !== fieldId; }); - setCurrentViewSorts?.(newViewSorts); + set(currentViewSortsState, newViewSorts); onViewSortsChange?.(newViewSorts); }, + [currentViewSortsState, viewScopeId], ); return { persistViewSorts, upsertViewSort, removeViewSort }; diff --git a/front/src/modules/views/hooks/internal/useViews.ts b/front/src/modules/views/hooks/internal/useViews.ts index 854e35a54..5190607b3 100644 --- a/front/src/modules/views/hooks/internal/useViews.ts +++ b/front/src/modules/views/hooks/internal/useViews.ts @@ -2,9 +2,8 @@ import { useApolloClient } from '@apollo/client'; import { useRecoilCallback } from 'recoil'; import { useFindOneObjectMetadataItem } from '@/metadata/hooks/useFindOneObjectMetadataItem'; -import { viewObjectIdScopeState } from '@/views/states/viewObjectIdScopeState'; -import { viewTypeScopedState } from '@/views/states/viewTypeScopedState'; import { View } from '@/views/types/View'; +import { getViewScopedStateValuesFromSnapshot } from '@/views/utils/getViewScopedStateValuesFromSnapshot'; export const useViews = (scopeId: string) => { const { @@ -20,13 +19,12 @@ export const useViews = (scopeId: string) => { const createView = useRecoilCallback( ({ snapshot }) => async (view: Pick) => { - const viewObjectId = await snapshot - .getLoadable(viewObjectIdScopeState({ scopeId })) - .getValue(); - - const viewType = await snapshot - .getLoadable(viewTypeScopedState({ scopeId })) - .getValue(); + const { viewObjectId, viewType } = getViewScopedStateValuesFromSnapshot( + { + snapshot, + viewScopeId: scopeId, + }, + ); if (!viewObjectId || !viewType) { return; @@ -43,6 +41,7 @@ export const useViews = (scopeId: string) => { refetchQueries: [findManyQuery], }); }, + [scopeId, apolloClient, createOneMutation, findManyQuery], ); const updateView = async (view: View) => { diff --git a/front/src/modules/views/hooks/useView.ts b/front/src/modules/views/hooks/useView.ts index 35a12c0bd..4e32c45b7 100644 --- a/front/src/modules/views/hooks/useView.ts +++ b/front/src/modules/views/hooks/useView.ts @@ -1,6 +1,6 @@ import { useCallback } from 'react'; import { useSearchParams } from 'react-router-dom'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil'; import { v4 } from 'uuid'; import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; @@ -8,22 +8,15 @@ import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-i import { ViewScopeInternalContext } from '../scopes/scope-internal-context/ViewScopeInternalContext'; import { currentViewFieldsScopedFamilyState } from '../states/currentViewFieldsScopedFamilyState'; import { currentViewFiltersScopedFamilyState } from '../states/currentViewFiltersScopedFamilyState'; -import { currentViewIdScopedState } from '../states/currentViewIdScopedState'; import { currentViewSortsScopedFamilyState } from '../states/currentViewSortsScopedFamilyState'; -import { onViewFieldsChangeScopedState } from '../states/onViewFieldsChangeScopedState'; -import { onViewFiltersChangeScopedState } from '../states/onViewFiltersChangeScopedState'; -import { onViewSortsChangeScopedState } from '../states/onViewSortsChangeScopedState'; -import { savedViewFiltersScopedFamilyState } from '../states/savedViewFiltersScopedFamilyState'; -import { savedViewSortsScopedFamilyState } from '../states/savedViewSortsScopedFamilyState'; -import { currentViewScopedSelector } from '../states/selectors/currentViewScopedSelector'; -import { viewEditModeScopedState } from '../states/viewEditModeScopedState'; -import { viewsScopedState } from '../states/viewsScopedState'; +import { getViewScopedStatesFromSnapshot } from '../utils/getViewScopedStatesFromSnapshot'; +import { getViewScopedStateValuesFromSnapshot } from '../utils/getViewScopedStateValuesFromSnapshot'; import { useViewFields } from './internal/useViewFields'; import { useViewFilters } from './internal/useViewFilters'; import { useViews } from './internal/useViews'; +import { useViewScopedStates } from './internal/useViewScopedStates'; import { useViewSorts } from './internal/useViewSorts'; -import { useViewSetStates } from './useViewSetStates'; type UseViewProps = { viewScopeId?: string; @@ -36,32 +29,19 @@ export const useView = (props?: UseViewProps) => { ); const { - setCurrentViewId, - currentViewId, - - setViews, - setViewEditMode, - setViewObjectId, - setViewType, - setEntityCountInCurrentView, - setIsViewBarExpanded, - - setAvailableSortDefinitions, - setCurrentViewSorts, - setSavedViewSorts, - - setAvailableFilterDefinitions, - setCurrentViewFilters, - setSavedViewFilters, - - setAvailableFieldDefinitions, - setCurrentViewFields, - setSavedViewFields, - - setOnViewFieldsChange, - setOnViewFiltersChange, - setOnViewSortsChange, - } = useViewSetStates(scopeId); + currentViewFiltersState, + currentViewIdState, + currentViewSortsState, + viewEditModeState, + availableFieldDefinitionsState, + availableFilterDefinitionsState, + availableSortDefinitionsState, + entityCountInCurrentViewState, + viewObjectIdState, + viewTypeState, + } = useViewScopedStates({ + customViewScopeId: scopeId, + }); const { persistViewSorts, upsertViewSort, removeViewSort } = useViewSorts(scopeId); @@ -73,6 +53,28 @@ export const useView = (props?: UseViewProps) => { updateView: internalUpdateView, deleteView: internalDeleteView, } = useViews(scopeId); + + const [currentViewId, setCurrentViewId] = useRecoilState(currentViewIdState); + const setAvailableFieldDefinitions = useSetRecoilState( + availableFieldDefinitionsState, + ); + + const setAvailableSortDefinitions = useSetRecoilState( + availableSortDefinitionsState, + ); + + const setAvailableFilterDefinitions = useSetRecoilState( + availableFilterDefinitionsState, + ); + + const setEntityCountInCurrentView = useSetRecoilState( + entityCountInCurrentViewState, + ); + + const setViewEditMode = useSetRecoilState(viewEditModeState); + const setViewObjectId = useSetRecoilState(viewObjectIdState); + const setViewType = useSetRecoilState(viewTypeState); + const [_, setSearchParams] = useSearchParams(); const changeViewInUrl = useCallback( @@ -82,72 +84,62 @@ export const useView = (props?: UseViewProps) => { [setSearchParams], ); - const loadView = useRecoilCallback(({ snapshot }) => (viewId: string) => { - setCurrentViewId?.(viewId); - const currentViewFields = snapshot - .getLoadable( - currentViewFieldsScopedFamilyState({ scopeId, familyKey: viewId }), - ) - .getValue(); + const loadView = useRecoilCallback( + ({ snapshot }) => + (viewId: string) => { + setCurrentViewId?.(viewId); - const onViewFieldsChange = snapshot - .getLoadable(onViewFieldsChangeScopedState({ scopeId })) - .getValue(); + const { + currentViewFields, + onViewFieldsChange, + currentViewFilters, + onViewFiltersChange, + currentViewSorts, + onViewSortsChange, + } = getViewScopedStateValuesFromSnapshot({ + snapshot, + viewScopeId: scopeId, + viewId, + }); - onViewFieldsChange?.(currentViewFields); + onViewFieldsChange?.(currentViewFields); + onViewFiltersChange?.(currentViewFilters); + onViewSortsChange?.(currentViewSorts); + }, + [setCurrentViewId, scopeId], + ); - const currentViewFilters = snapshot - .getLoadable( - currentViewFiltersScopedFamilyState({ scopeId, familyKey: viewId }), - ) - .getValue(); + const resetViewBar = useRecoilCallback( + ({ snapshot, set }) => + () => { + const { + savedViewFilters, + savedViewSorts, + onViewFiltersChange, + onViewSortsChange, + } = getViewScopedStateValuesFromSnapshot({ + snapshot, + viewScopeId: scopeId, + }); - const onViewFiltersChange = snapshot - .getLoadable(onViewFiltersChangeScopedState({ scopeId })) - .getValue(); + if (savedViewFilters) { + set(currentViewFiltersState, savedViewFilters); + onViewFiltersChange?.(savedViewFilters); + } + if (savedViewSorts) { + set(currentViewSortsState, savedViewSorts); + onViewSortsChange?.(savedViewSorts); + } - onViewFiltersChange?.(currentViewFilters); - - const currentViewSorts = snapshot - .getLoadable( - currentViewSortsScopedFamilyState({ scopeId, familyKey: viewId }), - ) - .getValue(); - - const onViewSortsChange = snapshot - .getLoadable(onViewSortsChangeScopedState({ scopeId })) - .getValue(); - - onViewSortsChange?.(currentViewSorts); - }); - - const resetViewBar = useRecoilCallback(({ snapshot }) => () => { - const savedViewFilters = snapshot - .getLoadable( - savedViewFiltersScopedFamilyState({ - scopeId, - familyKey: currentViewId || '', - }), - ) - .getValue(); - - const savedViewSorts = snapshot - .getLoadable( - savedViewSortsScopedFamilyState({ - scopeId, - familyKey: currentViewId || '', - }), - ) - .getValue(); - - if (savedViewFilters) { - setCurrentViewFilters?.(savedViewFilters); - } - if (savedViewSorts) { - setCurrentViewSorts?.(savedViewSorts); - } - setViewEditMode?.('none'); - }); + set(viewEditModeState, 'none'); + }, + [ + currentViewFiltersState, + currentViewSortsState, + scopeId, + viewEditModeState, + ], + ); const createView = useRecoilCallback( ({ snapshot, set }) => @@ -155,29 +147,17 @@ export const useView = (props?: UseViewProps) => { const newViewId = v4(); await internalCreateView({ id: newViewId, name }); - const currentViewFields = snapshot - .getLoadable( - currentViewFieldsScopedFamilyState({ - scopeId, - familyKey: currentViewId || '', - }), - ) - .getValue(); + const { currentViewFields, currentViewFilters, currentViewSorts } = + getViewScopedStateValuesFromSnapshot({ + snapshot, + viewScopeId: scopeId, + }); set( currentViewFieldsScopedFamilyState({ scopeId, familyKey: newViewId }), currentViewFields, ); - const currentViewFilters = snapshot - .getLoadable( - currentViewFiltersScopedFamilyState({ - scopeId, - familyKey: currentViewId || '', - }), - ) - .getValue(); - set( currentViewFiltersScopedFamilyState({ scopeId, @@ -186,15 +166,6 @@ export const useView = (props?: UseViewProps) => { currentViewFilters, ); - const currentViewSorts = snapshot - .getLoadable( - currentViewSortsScopedFamilyState({ - scopeId, - familyKey: currentViewId || '', - }), - ) - .getValue(); - set( currentViewSortsScopedFamilyState({ scopeId, @@ -211,7 +182,6 @@ export const useView = (props?: UseViewProps) => { }, [ changeViewInUrl, - currentViewId, internalCreateView, persistViewFields, persistViewFilters, @@ -228,19 +198,30 @@ export const useView = (props?: UseViewProps) => { const removeView = useRecoilCallback( ({ set, snapshot }) => async (viewIdToDelete: string) => { - const currentViewId = await snapshot.getPromise( - currentViewIdScopedState({ scopeId }), - ); + const { currentViewId } = getViewScopedStateValuesFromSnapshot({ + snapshot, + viewScopeId: scopeId, + }); - if (currentViewId === viewIdToDelete) - set(currentViewIdScopedState({ scopeId }), undefined); + const { currentViewIdState, viewsState } = + getViewScopedStatesFromSnapshot({ + snapshot, + viewScopeId: scopeId, + }); - set(viewsScopedState({ scopeId }), (previousViews) => + if (currentViewId === viewIdToDelete) { + set(currentViewIdState, undefined); + } + + set(viewsState, (previousViews) => previousViews.filter((view) => view.id !== viewIdToDelete), ); + internalDeleteView(viewIdToDelete); - if (currentViewId === viewIdToDelete) setSearchParams(); + if (currentViewId === viewIdToDelete) { + setSearchParams(); + } }, [internalDeleteView, scopeId, setSearchParams], ); @@ -252,13 +233,11 @@ export const useView = (props?: UseViewProps) => { return; } - const viewEditMode = snapshot - .getLoadable(viewEditModeScopedState({ scopeId })) - .getValue(); - - const currentView = snapshot - .getLoadable(currentViewScopedSelector(scopeId)) - .getValue(); + const { viewEditMode, currentView } = + getViewScopedStateValuesFromSnapshot({ + snapshot, + viewScopeId: scopeId, + }); if (!currentView) { return; @@ -284,38 +263,25 @@ export const useView = (props?: UseViewProps) => { updateCurrentView, createView, removeView, - setIsViewBarExpanded, resetViewBar, handleViewNameSubmit, - setViews, setViewEditMode, setViewObjectId, setViewType, setEntityCountInCurrentView, + setAvailableFieldDefinitions, setAvailableSortDefinitions, - setCurrentViewSorts, - setSavedViewSorts, upsertViewSort, removeViewSort, setAvailableFilterDefinitions, - setCurrentViewFilters, - setSavedViewFilters, upsertViewFilter, removeViewFilter, - setAvailableFieldDefinitions, - setCurrentViewFields, - setSavedViewFields, - persistViewFields, changeViewInUrl, loadView, - - setOnViewFieldsChange, - setOnViewFiltersChange, - setOnViewSortsChange, }; }; diff --git a/front/src/modules/views/hooks/useViewGetStates.ts b/front/src/modules/views/hooks/useViewGetStates.ts deleted file mode 100644 index 3a50e95af..000000000 --- a/front/src/modules/views/hooks/useViewGetStates.ts +++ /dev/null @@ -1,211 +0,0 @@ -import { useRecoilValue } from 'recoil'; - -import { useRecoilScopedFamilyState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState'; -import { useRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2'; -import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; - -import { ViewScopeInternalContext } from '../scopes/scope-internal-context/ViewScopeInternalContext'; -import { availableFieldDefinitionsScopedState } from '../states/availableFieldDefinitionsScopedState'; -import { availableFilterDefinitionsScopedState } from '../states/availableFilterDefinitionsScopedState'; -import { availableSortDefinitionsScopedState } from '../states/availableSortDefinitionsScopedState'; -import { currentViewFieldsScopedFamilyState } from '../states/currentViewFieldsScopedFamilyState'; -import { currentViewFiltersScopedFamilyState } from '../states/currentViewFiltersScopedFamilyState'; -import { currentViewIdScopedState } from '../states/currentViewIdScopedState'; -import { currentViewSortsScopedFamilyState } from '../states/currentViewSortsScopedFamilyState'; -import { entityCountInCurrentViewScopedState } from '../states/entityCountInCurrentViewScopedState'; -import { isViewBarExpandedScopedState } from '../states/isViewBarExpandedScopedState'; -import { onViewFieldsChangeScopedState } from '../states/onViewFieldsChangeScopedState'; -import { onViewFiltersChangeScopedState } from '../states/onViewFiltersChangeScopedState'; -import { onViewSortsChangeScopedState } from '../states/onViewSortsChangeScopedState'; -import { savedViewFieldsScopedFamilyState } from '../states/savedViewFieldsScopedFamilyState'; -import { savedViewFiltersScopedFamilyState } from '../states/savedViewFiltersScopedFamilyState'; -import { savedViewSortsScopedFamilyState } from '../states/savedViewSortsScopedFamilyState'; -import { canPersistViewFiltersScopedFamilySelector } from '../states/selectors/canPersistViewFiltersScopedFamilySelector'; -import { canPersistViewSortsScopedFamilySelector } from '../states/selectors/canPersistViewSortsScopedFamilySelector'; -import { currentViewScopedSelector } from '../states/selectors/currentViewScopedSelector'; -import { savedViewFieldByKeyScopedFamilySelector } from '../states/selectors/savedViewFieldByKeyScopedFamilySelector'; -import { savedViewFiltersByKeyScopedFamilySelector } from '../states/selectors/savedViewFiltersByKeyScopedFamilySelector'; -import { savedViewSortsByKeyScopedFamilySelector } from '../states/selectors/savedViewSortsByKeyScopedFamilySelector'; -import { viewEditModeScopedState } from '../states/viewEditModeScopedState'; -import { viewObjectIdScopeState } from '../states/viewObjectIdScopeState'; -import { viewsScopedState } from '../states/viewsScopedState'; -import { viewTypeScopedState } from '../states/viewTypeScopedState'; - -export const useViewGetStates = (viewScopeId?: string, viewId?: string) => { - const scopeId = useAvailableScopeIdOrThrow( - ViewScopeInternalContext, - viewScopeId, - ); - - // View - const [currentViewId] = useRecoilScopedStateV2( - currentViewIdScopedState, - scopeId, - ); - - const familyItemId = viewId ?? currentViewId; - - const currentView = useRecoilValue(currentViewScopedSelector(scopeId)); - - const [viewEditMode] = useRecoilScopedStateV2( - viewEditModeScopedState, - scopeId, - ); - - const [views] = useRecoilScopedStateV2(viewsScopedState, scopeId); - - const [viewObjectId] = useRecoilScopedStateV2( - viewObjectIdScopeState, - scopeId, - ); - - const [viewType] = useRecoilScopedStateV2(viewTypeScopedState, scopeId); - - const [entityCountInCurrentView] = useRecoilScopedStateV2( - entityCountInCurrentViewScopedState, - scopeId, - ); - - const [isViewBarExpanded] = useRecoilScopedStateV2( - isViewBarExpandedScopedState, - scopeId, - ); - - // ViewSorts - const [currentViewSorts] = useRecoilScopedFamilyState( - currentViewSortsScopedFamilyState, - scopeId, - familyItemId, - ); - - const [savedViewSorts] = useRecoilScopedFamilyState( - savedViewSortsScopedFamilyState, - scopeId, - familyItemId, - ); - - const savedViewSortsByKey = useRecoilValue( - savedViewSortsByKeyScopedFamilySelector({ - scopeId: scopeId, - viewId: familyItemId, - }), - ); - - const [availableSortDefinitions] = useRecoilScopedStateV2( - availableSortDefinitionsScopedState, - scopeId, - ); - - const canPersistSorts = useRecoilValue( - canPersistViewSortsScopedFamilySelector({ - viewScopeId: scopeId, - viewId: familyItemId, - }), - ); - - // ViewFilters - const [currentViewFilters] = useRecoilScopedFamilyState( - currentViewFiltersScopedFamilyState, - scopeId, - familyItemId, - ); - - const [savedViewFilters] = useRecoilScopedFamilyState( - savedViewFiltersScopedFamilyState, - scopeId, - familyItemId, - ); - - const savedViewFiltersByKey = useRecoilValue( - savedViewFiltersByKeyScopedFamilySelector({ - scopeId: scopeId, - viewId: familyItemId, - }), - ); - - const [availableFilterDefinitions] = useRecoilScopedStateV2( - availableFilterDefinitionsScopedState, - scopeId, - ); - - const canPersistFilters = useRecoilValue( - canPersistViewFiltersScopedFamilySelector({ - viewScopeId: scopeId, - viewId: familyItemId, - }), - ); - - // ViewFields - const [availableFieldDefinitions] = useRecoilScopedStateV2( - availableFieldDefinitionsScopedState, - scopeId, - ); - - const [currentViewFields] = useRecoilScopedFamilyState( - currentViewFieldsScopedFamilyState, - scopeId, - familyItemId, - ); - - const [savedViewFields] = useRecoilScopedFamilyState( - savedViewFieldsScopedFamilyState, - scopeId, - familyItemId, - ); - - const savedViewFieldsByKey = useRecoilValue( - savedViewFieldByKeyScopedFamilySelector({ - viewScopeId: scopeId, - viewId: familyItemId, - }), - ); - - // ViewChangeHandlers - const [onViewSortsChange] = useRecoilScopedStateV2( - onViewSortsChangeScopedState, - scopeId, - ); - - const [onViewFiltersChange] = useRecoilScopedStateV2( - onViewFiltersChangeScopedState, - scopeId, - ); - - const [onViewFieldsChange] = useRecoilScopedStateV2( - onViewFieldsChangeScopedState, - scopeId, - ); - - return { - currentViewId, - currentView, - isViewBarExpanded, - - views, - viewEditMode, - viewObjectId, - viewType, - entityCountInCurrentView, - - availableSortDefinitions, - currentViewSorts, - savedViewSorts, - savedViewSortsByKey, - canPersistSorts, - - availableFilterDefinitions, - currentViewFilters, - savedViewFilters, - savedViewFiltersByKey, - canPersistFilters, - - availableFieldDefinitions, - currentViewFields, - savedViewFieldsByKey, - savedViewFields, - - onViewSortsChange, - onViewFiltersChange, - onViewFieldsChange, - }; -}; diff --git a/front/src/modules/views/hooks/useViewSetStates.ts b/front/src/modules/views/hooks/useViewSetStates.ts deleted file mode 100644 index e41e4921e..000000000 --- a/front/src/modules/views/hooks/useViewSetStates.ts +++ /dev/null @@ -1,160 +0,0 @@ -import { useRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2'; -import { useSetRecoilScopedFamilyState } from '@/ui/utilities/recoil-scope/hooks/useSetRecoilScopedFamilyState'; -import { useSetRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/useSetRecoilScopedStateV2'; -import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; - -import { ViewScopeInternalContext } from '../scopes/scope-internal-context/ViewScopeInternalContext'; -import { availableFieldDefinitionsScopedState } from '../states/availableFieldDefinitionsScopedState'; -import { availableFilterDefinitionsScopedState } from '../states/availableFilterDefinitionsScopedState'; -import { availableSortDefinitionsScopedState } from '../states/availableSortDefinitionsScopedState'; -import { currentViewFieldsScopedFamilyState } from '../states/currentViewFieldsScopedFamilyState'; -import { currentViewFiltersScopedFamilyState } from '../states/currentViewFiltersScopedFamilyState'; -import { currentViewIdScopedState } from '../states/currentViewIdScopedState'; -import { currentViewSortsScopedFamilyState } from '../states/currentViewSortsScopedFamilyState'; -import { entityCountInCurrentViewScopedState } from '../states/entityCountInCurrentViewScopedState'; -import { isViewBarExpandedScopedState } from '../states/isViewBarExpandedScopedState'; -import { onViewFieldsChangeScopedState } from '../states/onViewFieldsChangeScopedState'; -import { onViewFiltersChangeScopedState } from '../states/onViewFiltersChangeScopedState'; -import { onViewSortsChangeScopedState } from '../states/onViewSortsChangeScopedState'; -import { savedViewFieldsScopedFamilyState } from '../states/savedViewFieldsScopedFamilyState'; -import { savedViewFiltersScopedFamilyState } from '../states/savedViewFiltersScopedFamilyState'; -import { savedViewSortsScopedFamilyState } from '../states/savedViewSortsScopedFamilyState'; -import { viewEditModeScopedState } from '../states/viewEditModeScopedState'; -import { viewObjectIdScopeState } from '../states/viewObjectIdScopeState'; -import { viewsScopedState } from '../states/viewsScopedState'; -import { viewTypeScopedState } from '../states/viewTypeScopedState'; - -export const useViewSetStates = (viewScopeId?: string, viewId?: string) => { - const scopeId = useAvailableScopeIdOrThrow( - ViewScopeInternalContext, - viewScopeId, - ); - // View - const [currentViewId, setCurrentViewId] = useRecoilScopedStateV2( - currentViewIdScopedState, - scopeId, - ); - - const setViewObjectId = useSetRecoilScopedStateV2( - viewObjectIdScopeState, - scopeId, - ); - - const setViewType = useSetRecoilScopedStateV2(viewTypeScopedState, scopeId); - - const familyItemId = viewId ? viewId : currentViewId; - - const setViewEditMode = useSetRecoilScopedStateV2( - viewEditModeScopedState, - scopeId, - ); - - const setViews = useSetRecoilScopedStateV2(viewsScopedState, scopeId); - - const setEntityCountInCurrentView = useSetRecoilScopedStateV2( - entityCountInCurrentViewScopedState, - scopeId, - ); - - const setIsViewBarExpanded = useSetRecoilScopedStateV2( - isViewBarExpandedScopedState, - scopeId, - ); - - // ViewSorts - const setCurrentViewSorts = useSetRecoilScopedFamilyState( - currentViewSortsScopedFamilyState, - scopeId, - familyItemId, - ); - - const setSavedViewSorts = useSetRecoilScopedFamilyState( - savedViewSortsScopedFamilyState, - scopeId, - familyItemId, - ); - - const setAvailableSortDefinitions = useSetRecoilScopedStateV2( - availableSortDefinitionsScopedState, - scopeId, - ); - - // ViewFilters - const setCurrentViewFilters = useSetRecoilScopedFamilyState( - currentViewFiltersScopedFamilyState, - scopeId, - familyItemId, - ); - - const setSavedViewFilters = useSetRecoilScopedFamilyState( - savedViewFiltersScopedFamilyState, - scopeId, - familyItemId, - ); - - const setAvailableFilterDefinitions = useSetRecoilScopedStateV2( - availableFilterDefinitionsScopedState, - scopeId, - ); - - // ViewFields - const setAvailableFieldDefinitions = useSetRecoilScopedStateV2( - availableFieldDefinitionsScopedState, - scopeId, - ); - - const setCurrentViewFields = useSetRecoilScopedFamilyState( - currentViewFieldsScopedFamilyState, - scopeId, - familyItemId, - ); - - const setSavedViewFields = useSetRecoilScopedFamilyState( - savedViewFieldsScopedFamilyState, - scopeId, - familyItemId, - ); - - const setOnViewFieldsChange = useSetRecoilScopedStateV2( - onViewFieldsChangeScopedState, - scopeId, - ); - - const setOnViewFiltersChange = useSetRecoilScopedStateV2( - onViewFiltersChangeScopedState, - scopeId, - ); - - const setOnViewSortsChange = useSetRecoilScopedStateV2( - onViewSortsChangeScopedState, - scopeId, - ); - - return { - currentViewId, - setCurrentViewId, - setIsViewBarExpanded, - setViewObjectId, - setViewType, - - setViews, - setViewEditMode, - setEntityCountInCurrentView, - - setAvailableSortDefinitions, - setCurrentViewSorts, - setSavedViewSorts, - - setAvailableFilterDefinitions, - setCurrentViewFilters, - setSavedViewFilters, - - setAvailableFieldDefinitions, - setCurrentViewFields, - setSavedViewFields, - - setOnViewFieldsChange, - setOnViewFiltersChange, - setOnViewSortsChange, - }; -}; diff --git a/front/src/modules/views/scopes/init-effect/ViewScopeInitEffect.tsx b/front/src/modules/views/scopes/init-effect/ViewScopeInitEffect.tsx index 214134e17..9aaca1330 100644 --- a/front/src/modules/views/scopes/init-effect/ViewScopeInitEffect.tsx +++ b/front/src/modules/views/scopes/init-effect/ViewScopeInitEffect.tsx @@ -1,8 +1,9 @@ import { useEffect } from 'react'; +import { useSetRecoilState } from 'recoil'; import { Filter } from '@/ui/object/object-filter-dropdown/types/Filter'; import { Sort } from '@/ui/object/object-sort-dropdown/types/Sort'; -import { useView } from '@/views/hooks/useView'; +import { useViewScopedStates } from '@/views/hooks/internal/useViewScopedStates'; import { ViewField } from '@/views/types/ViewField'; type ViewScopeInitEffectProps = { @@ -18,10 +19,14 @@ export const ViewScopeInitEffect = ({ onViewFieldsChange, }: ViewScopeInitEffectProps) => { const { - setOnViewSortsChange, - setOnViewFieldsChange, - setOnViewFiltersChange, - } = useView(); + onViewFieldsChangeState, + onViewFiltersChangeState, + onViewSortsChangeState, + } = useViewScopedStates(); + + const setOnViewSortsChange = useSetRecoilState(onViewSortsChangeState); + const setOnViewFiltersChange = useSetRecoilState(onViewFiltersChangeState); + const setOnViewFieldsChange = useSetRecoilState(onViewFieldsChangeState); useEffect(() => { setOnViewSortsChange(() => onViewSortsChange); diff --git a/front/src/modules/views/states/selectors/currentViewScopedSelector.ts b/front/src/modules/views/states/selectors/currentViewScopedSelector.ts index c1606d2c0..e0862ffc2 100644 --- a/front/src/modules/views/states/selectors/currentViewScopedSelector.ts +++ b/front/src/modules/views/states/selectors/currentViewScopedSelector.ts @@ -1,22 +1,23 @@ -import { selectorFamily } from 'recoil'; - +import { createScopedSelector } from '@/ui/utilities/recoil-scope/utils/createScopedSelector'; import { View } from '@/views/types/View'; import { currentViewIdScopedState } from '../currentViewIdScopedState'; import { viewsByIdScopedSelector } from './viewsByIdScopedSelector'; -export const currentViewScopedSelector = selectorFamily< - View | undefined, - string ->({ - key: 'currentViewScopedSelector', - get: - (scopeId) => - ({ get }) => { - const currentViewId = get(currentViewIdScopedState({ scopeId: scopeId })); - return currentViewId - ? get(viewsByIdScopedSelector(scopeId))[currentViewId] - : undefined; - }, -}); +export const currentViewScopedSelector = createScopedSelector( + { + key: 'currentViewScopedSelector', + get: + ({ scopeId }: { scopeId: string }) => + ({ get }) => { + const currentViewId = get( + currentViewIdScopedState({ scopeId: scopeId }), + ); + + return currentViewId + ? get(viewsByIdScopedSelector(scopeId))[currentViewId] + : undefined; + }, + }, +); diff --git a/front/src/modules/views/states/selectors/savedViewFieldByKeyScopedFamilySelector.ts b/front/src/modules/views/states/selectors/savedViewFieldByKeyScopedFamilySelector.ts index 7d1424e9b..aba69d834 100644 --- a/front/src/modules/views/states/selectors/savedViewFieldByKeyScopedFamilySelector.ts +++ b/front/src/modules/views/states/selectors/savedViewFieldByKeyScopedFamilySelector.ts @@ -18,6 +18,7 @@ export const savedViewFieldByKeyScopedFamilySelector = selectorFamily({ if (viewId === undefined) { return undefined; } + return get( savedViewFieldsScopedFamilyState({ scopeId: viewScopeId, diff --git a/front/src/modules/views/utils/getViewScopedStateValuesFromSnapshot.ts b/front/src/modules/views/utils/getViewScopedStateValuesFromSnapshot.ts new file mode 100644 index 000000000..f68754b0c --- /dev/null +++ b/front/src/modules/views/utils/getViewScopedStateValuesFromSnapshot.ts @@ -0,0 +1,106 @@ +import { Snapshot } from 'recoil'; + +import { getScopedState } from '@/ui/utilities/recoil-scope/utils/getScopedState'; +import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; + +import { UNDEFINED_FAMILY_ITEM_ID } from '../constants'; +import { currentViewIdScopedState } from '../states/currentViewIdScopedState'; + +import { getViewScopedStates } from './internal/getViewScopedStates'; + +export const getViewScopedStateValuesFromSnapshot = ({ + snapshot, + viewScopeId, + viewId, +}: { + snapshot: Snapshot; + viewScopeId: string; + viewId?: string; +}) => { + const currentViewId = getSnapshotValue( + snapshot, + getScopedState(currentViewIdScopedState, viewScopeId), + ); + + const familyItemId = viewId ?? currentViewId ?? UNDEFINED_FAMILY_ITEM_ID; + + const { + availableFieldDefinitionsState, + availableFilterDefinitionsState, + availableSortDefinitionsState, + canPersistFiltersSelector, + canPersistSortsSelector, + currentViewFieldsState, + currentViewFiltersState, + currentViewIdState, + currentViewSelector, + currentViewSortsState, + entityCountInCurrentViewState, + isViewBarExpandedState, + onViewFieldsChangeState, + onViewFiltersChangeState, + onViewSortsChangeState, + savedViewFieldsByKeySelector, + savedViewFieldsState, + savedViewFiltersByKeySelector, + savedViewFiltersState, + savedViewSortsByKeySelector, + savedViewSortsState, + viewEditModeState, + viewObjectIdState, + viewTypeState, + viewsState, + } = getViewScopedStates({ + viewScopeId, + viewId: familyItemId, + }); + + return { + availableFieldDefinitions: getSnapshotValue( + snapshot, + availableFieldDefinitionsState, + ), + availableFilterDefinitions: getSnapshotValue( + snapshot, + availableFilterDefinitionsState, + ), + availableSortDefinitions: getSnapshotValue( + snapshot, + availableSortDefinitionsState, + ), + canPersistFilters: getSnapshotValue(snapshot, canPersistFiltersSelector), + canPersistSorts: getSnapshotValue(snapshot, canPersistSortsSelector), + currentViewFields: getSnapshotValue(snapshot, currentViewFieldsState), + currentViewFilters: getSnapshotValue(snapshot, currentViewFiltersState), + currentViewId: getSnapshotValue(snapshot, currentViewIdState), + currentView: getSnapshotValue(snapshot, currentViewSelector), + currentViewSorts: getSnapshotValue(snapshot, currentViewSortsState), + entityCountInCurrentView: getSnapshotValue( + snapshot, + entityCountInCurrentViewState, + ), + isViewBarExpanded: getSnapshotValue(snapshot, isViewBarExpandedState), + onViewFieldsChange: getSnapshotValue(snapshot, onViewFieldsChangeState), + onViewFiltersChange: getSnapshotValue(snapshot, onViewFiltersChangeState), + onViewSortsChange: getSnapshotValue(snapshot, onViewSortsChangeState), + savedViewFieldsByKey: getSnapshotValue( + snapshot, + savedViewFieldsByKeySelector, + ), + savedViewFields: getSnapshotValue(snapshot, savedViewFieldsState), + savedViewFiltersByKey: getSnapshotValue( + snapshot, + savedViewFiltersByKeySelector, + ), + savedViewFilters: getSnapshotValue(snapshot, savedViewFiltersState), + savedViewSortsByKey: getSnapshotValue( + snapshot, + savedViewSortsByKeySelector, + ), + savedViewSorts: getSnapshotValue(snapshot, savedViewSortsState), + viewEditMode: getSnapshotValue(snapshot, viewEditModeState), + viewObjectId: getSnapshotValue(snapshot, viewObjectIdState), + viewType: getSnapshotValue(snapshot, viewTypeState), + views: getSnapshotValue(snapshot, viewsState), + }; +}; diff --git a/front/src/modules/views/utils/getViewScopedStatesFromSnapshot.ts b/front/src/modules/views/utils/getViewScopedStatesFromSnapshot.ts new file mode 100644 index 000000000..efb3e4a19 --- /dev/null +++ b/front/src/modules/views/utils/getViewScopedStatesFromSnapshot.ts @@ -0,0 +1,85 @@ +import { Snapshot } from 'recoil'; + +import { getScopedState } from '@/ui/utilities/recoil-scope/utils/getScopedState'; +import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; + +import { UNDEFINED_FAMILY_ITEM_ID } from '../constants'; +import { currentViewIdScopedState } from '../states/currentViewIdScopedState'; + +import { getViewScopedStates } from './internal/getViewScopedStates'; + +export const getViewScopedStatesFromSnapshot = ({ + snapshot, + viewScopeId, + viewId, +}: { + snapshot: Snapshot; + viewScopeId: string; + viewId?: string; +}) => { + const currentViewId = getSnapshotValue( + snapshot, + getScopedState(currentViewIdScopedState, viewScopeId), + ); + + const usedViewId = viewId ?? currentViewId ?? UNDEFINED_FAMILY_ITEM_ID; + + const { + availableFieldDefinitionsState, + availableFilterDefinitionsState, + availableSortDefinitionsState, + canPersistFiltersSelector: canPersistFiltersSelector, + canPersistSortsSelector: canPersistSortsSelector, + currentViewFieldsState, + currentViewFiltersState, + currentViewIdState, + currentViewSelector, + currentViewSortsState, + entityCountInCurrentViewState, + isViewBarExpandedState, + onViewFieldsChangeState, + onViewFiltersChangeState, + onViewSortsChangeState, + savedViewFieldsByKeySelector: savedViewFieldsByKeySelector, + savedViewFieldsState, + savedViewFiltersByKeySelector: savedViewFiltersByKeySelector, + savedViewFiltersState, + savedViewSortsByKeySelector: savedViewSortsByKeySelector, + savedViewSortsState, + viewEditModeState, + viewObjectIdState, + viewTypeState, + viewsState, + } = getViewScopedStates({ + viewScopeId, + viewId: usedViewId, + }); + + return { + availableFieldDefinitionsState, + availableFilterDefinitionsState, + availableSortDefinitionsState, + canPersistFiltersReadOnlyState: canPersistFiltersSelector, + canPersistSortsReadOnlyState: canPersistSortsSelector, + currentViewFieldsState, + currentViewFiltersState, + currentViewIdState, + currentViewSelector, + currentViewSortsState, + entityCountInCurrentViewState, + isViewBarExpandedState, + onViewFieldsChangeState, + onViewFiltersChangeState, + onViewSortsChangeState, + savedViewFieldsByKeyReadOnlyState: savedViewFieldsByKeySelector, + savedViewFieldsState, + savedViewFiltersByKeyReadOnlyState: savedViewFiltersByKeySelector, + savedViewFiltersState, + savedViewSortsByKeyReadOnlyState: savedViewSortsByKeySelector, + savedViewSortsState, + viewEditModeState, + viewObjectIdState, + viewTypeState, + viewsState, + }; +}; diff --git a/front/src/modules/views/utils/internal/getViewScopedStates.ts b/front/src/modules/views/utils/internal/getViewScopedStates.ts new file mode 100644 index 000000000..869192cf3 --- /dev/null +++ b/front/src/modules/views/utils/internal/getViewScopedStates.ts @@ -0,0 +1,198 @@ +import { getScopedFamilyState } from '@/ui/utilities/recoil-scope/utils/getScopedFamilyState'; +import { getScopedSelector } from '@/ui/utilities/recoil-scope/utils/getScopedSelector'; +import { getScopedState } from '@/ui/utilities/recoil-scope/utils/getScopedState'; +import { currentViewIdScopedState } from '@/views/states/currentViewIdScopedState'; +import { currentViewScopedSelector } from '@/views/states/selectors/currentViewScopedSelector'; + +import { availableFieldDefinitionsScopedState } from '../../states/availableFieldDefinitionsScopedState'; +import { availableFilterDefinitionsScopedState } from '../../states/availableFilterDefinitionsScopedState'; +import { availableSortDefinitionsScopedState } from '../../states/availableSortDefinitionsScopedState'; +import { currentViewFieldsScopedFamilyState } from '../../states/currentViewFieldsScopedFamilyState'; +import { currentViewFiltersScopedFamilyState } from '../../states/currentViewFiltersScopedFamilyState'; +import { currentViewSortsScopedFamilyState } from '../../states/currentViewSortsScopedFamilyState'; +import { entityCountInCurrentViewScopedState } from '../../states/entityCountInCurrentViewScopedState'; +import { isViewBarExpandedScopedState } from '../../states/isViewBarExpandedScopedState'; +import { onViewFieldsChangeScopedState } from '../../states/onViewFieldsChangeScopedState'; +import { onViewFiltersChangeScopedState } from '../../states/onViewFiltersChangeScopedState'; +import { onViewSortsChangeScopedState } from '../../states/onViewSortsChangeScopedState'; +import { savedViewFieldsScopedFamilyState } from '../../states/savedViewFieldsScopedFamilyState'; +import { savedViewFiltersScopedFamilyState } from '../../states/savedViewFiltersScopedFamilyState'; +import { savedViewSortsScopedFamilyState } from '../../states/savedViewSortsScopedFamilyState'; +import { canPersistViewFiltersScopedFamilySelector } from '../../states/selectors/canPersistViewFiltersScopedFamilySelector'; +import { canPersistViewSortsScopedFamilySelector } from '../../states/selectors/canPersistViewSortsScopedFamilySelector'; +import { savedViewFieldByKeyScopedFamilySelector } from '../../states/selectors/savedViewFieldByKeyScopedFamilySelector'; +import { savedViewFiltersByKeyScopedFamilySelector } from '../../states/selectors/savedViewFiltersByKeyScopedFamilySelector'; +import { savedViewSortsByKeyScopedFamilySelector } from '../../states/selectors/savedViewSortsByKeyScopedFamilySelector'; +import { viewEditModeScopedState } from '../../states/viewEditModeScopedState'; +import { viewObjectIdScopeState } from '../../states/viewObjectIdScopeState'; +import { viewsScopedState } from '../../states/viewsScopedState'; +import { viewTypeScopedState } from '../../states/viewTypeScopedState'; + +export const getViewScopedStates = ({ + viewScopeId, + viewId, +}: { + viewScopeId: string; + viewId: string; +}) => { + const viewEditModeState = getScopedState( + viewEditModeScopedState, + viewScopeId, + ); + + const viewsState = getScopedState(viewsScopedState, viewScopeId); + + const viewObjectIdState = getScopedState(viewObjectIdScopeState, viewScopeId); + + const viewTypeState = getScopedState(viewTypeScopedState, viewScopeId); + + const entityCountInCurrentViewState = getScopedState( + entityCountInCurrentViewScopedState, + viewScopeId, + ); + + const isViewBarExpandedState = getScopedState( + isViewBarExpandedScopedState, + viewScopeId, + ); + + // ViewSorts + const currentViewSortsState = getScopedFamilyState( + currentViewSortsScopedFamilyState, + viewScopeId, + viewId, + ); + + const savedViewSortsState = getScopedFamilyState( + savedViewSortsScopedFamilyState, + viewScopeId, + viewId, + ); + + const savedViewSortsByKeySelector = savedViewSortsByKeyScopedFamilySelector({ + scopeId: viewScopeId, + viewId: viewId, + }); + + const availableSortDefinitionsState = getScopedState( + availableSortDefinitionsScopedState, + viewScopeId, + ); + + const canPersistSortsSelector = canPersistViewSortsScopedFamilySelector({ + viewScopeId: viewScopeId, + viewId: viewId, + }); + + // ViewFilters + const currentViewFiltersState = getScopedFamilyState( + currentViewFiltersScopedFamilyState, + viewScopeId, + viewId, + ); + + const savedViewFiltersState = getScopedFamilyState( + savedViewFiltersScopedFamilyState, + viewScopeId, + viewId, + ); + + const savedViewFiltersByKeySelector = + savedViewFiltersByKeyScopedFamilySelector({ + scopeId: viewScopeId, + viewId: viewId, + }); + + const availableFilterDefinitionsState = getScopedState( + availableFilterDefinitionsScopedState, + viewScopeId, + ); + + const canPersistFiltersSelector = canPersistViewFiltersScopedFamilySelector({ + viewScopeId: viewScopeId, + viewId: viewId, + }); + + // ViewFields + const availableFieldDefinitionsState = getScopedState( + availableFieldDefinitionsScopedState, + viewScopeId, + ); + + const currentViewFieldsState = getScopedFamilyState( + currentViewFieldsScopedFamilyState, + viewScopeId, + viewId, + ); + + const savedViewFieldsState = getScopedFamilyState( + savedViewFieldsScopedFamilyState, + viewScopeId, + viewId, + ); + + const savedViewFieldsByKeySelector = savedViewFieldByKeyScopedFamilySelector({ + viewScopeId, + viewId, + }); + + // ViewChangeHandlers + const onViewSortsChangeState = getScopedState( + onViewSortsChangeScopedState, + viewScopeId, + ); + + const onViewFiltersChangeState = getScopedState( + onViewFiltersChangeScopedState, + viewScopeId, + ); + + const onViewFieldsChangeState = getScopedState( + onViewFieldsChangeScopedState, + viewScopeId, + ); + + const currentViewIdState = getScopedState( + currentViewIdScopedState, + viewScopeId, + ); + + const currentViewSelector = getScopedSelector( + currentViewScopedSelector, + viewScopeId, + ); + + return { + currentViewIdState, + currentViewSelector, + + isViewBarExpandedState, + + viewsState, + viewEditModeState, + viewObjectIdState, + viewTypeState, + entityCountInCurrentViewState, + + availableSortDefinitionsState, + currentViewSortsState, + savedViewSortsState, + savedViewSortsByKeySelector, + canPersistSortsSelector, + + availableFilterDefinitionsState, + currentViewFiltersState, + savedViewFiltersState, + savedViewFiltersByKeySelector, + canPersistFiltersSelector, + + availableFieldDefinitionsState, + currentViewFieldsState, + savedViewFieldsByKeySelector, + savedViewFieldsState, + + onViewSortsChangeState, + onViewFiltersChangeState, + onViewFieldsChangeState, + }; +}; diff --git a/front/src/modules/views/utils/columnDefinitionToViewField.ts b/front/src/modules/views/utils/mapColumnDefinitionToViewField.ts similarity index 92% rename from front/src/modules/views/utils/columnDefinitionToViewField.ts rename to front/src/modules/views/utils/mapColumnDefinitionToViewField.ts index cc807716c..7e4ed2a70 100644 --- a/front/src/modules/views/utils/columnDefinitionToViewField.ts +++ b/front/src/modules/views/utils/mapColumnDefinitionToViewField.ts @@ -3,7 +3,7 @@ import { ColumnDefinition } from '@/ui/object/record-table/types/ColumnDefinitio import { ViewField } from '../types/ViewField'; -export const columnDefinitionsToViewFields = ( +export const mapColumnDefinitionsToViewFields = ( columnDefinitions: ColumnDefinition[], ): ViewField[] => { return columnDefinitions.map((columnDefinition) => ({ diff --git a/front/src/modules/views/utils/viewFieldsToBoardFieldDefinitions.ts b/front/src/modules/views/utils/mapViewFieldsToBoardFieldDefinitions.ts similarity index 96% rename from front/src/modules/views/utils/viewFieldsToBoardFieldDefinitions.ts rename to front/src/modules/views/utils/mapViewFieldsToBoardFieldDefinitions.ts index 39132efe6..700c477be 100644 --- a/front/src/modules/views/utils/viewFieldsToBoardFieldDefinitions.ts +++ b/front/src/modules/views/utils/mapViewFieldsToBoardFieldDefinitions.ts @@ -4,7 +4,7 @@ import { assertNotNull } from '~/utils/assert'; import { ViewField } from '../types/ViewField'; -export const viewFieldsToBoardFieldDefinitions = ( +export const mapViewFieldsToBoardFieldDefinitions = ( viewFields: ViewField[], fieldsMetadata: BoardFieldDefinition[], ): BoardFieldDefinition[] => { diff --git a/front/src/modules/views/utils/viewFieldsToColumnDefinitions.ts b/front/src/modules/views/utils/mapViewFieldsToColumnDefinitions.ts similarity index 96% rename from front/src/modules/views/utils/viewFieldsToColumnDefinitions.ts rename to front/src/modules/views/utils/mapViewFieldsToColumnDefinitions.ts index 90c1cb6d3..901b07e05 100644 --- a/front/src/modules/views/utils/viewFieldsToColumnDefinitions.ts +++ b/front/src/modules/views/utils/mapViewFieldsToColumnDefinitions.ts @@ -4,7 +4,7 @@ import { assertNotNull } from '~/utils/assert'; import { ViewField } from '../types/ViewField'; -export const viewFieldsToColumnDefinitions = ( +export const mapViewFieldsToColumnDefinitions = ( viewFields: ViewField[], fieldsMetadata: ColumnDefinition[], ): ColumnDefinition[] => { diff --git a/front/src/modules/views/utils/viewFiltersToFilters.ts b/front/src/modules/views/utils/mapViewFiltersToFilters.ts similarity index 81% rename from front/src/modules/views/utils/viewFiltersToFilters.ts rename to front/src/modules/views/utils/mapViewFiltersToFilters.ts index eeb908914..fcc1144c2 100644 --- a/front/src/modules/views/utils/viewFiltersToFilters.ts +++ b/front/src/modules/views/utils/mapViewFiltersToFilters.ts @@ -2,7 +2,9 @@ import { Filter } from '@/ui/object/object-filter-dropdown/types/Filter'; import { ViewFilter } from '../types/ViewFilter'; -export const viewFiltersToFilters = (viewFilters: ViewFilter[]): Filter[] => { +export const mapViewFiltersToFilters = ( + viewFilters: ViewFilter[], +): Filter[] => { return viewFilters.map((viewFilter) => { return { fieldId: viewFilter.fieldId, diff --git a/front/src/modules/views/utils/viewSortsToSorts.ts b/front/src/modules/views/utils/mapViewSortsToSorts.ts similarity index 80% rename from front/src/modules/views/utils/viewSortsToSorts.ts rename to front/src/modules/views/utils/mapViewSortsToSorts.ts index 1a314c520..360d0df19 100644 --- a/front/src/modules/views/utils/viewSortsToSorts.ts +++ b/front/src/modules/views/utils/mapViewSortsToSorts.ts @@ -2,7 +2,7 @@ import { Sort } from '@/ui/object/object-sort-dropdown/types/Sort'; import { ViewSort } from '../types/ViewSort'; -export const viewSortsToSorts = (viewSorts: ViewSort[]): Sort[] => { +export const mapViewSortsToSorts = (viewSorts: ViewSort[]): Sort[] => { return viewSorts.map((viewSort) => { return { fieldId: viewSort.fieldId, diff --git a/front/src/pages/people/__stories__/People.sortBy.stories.tsx b/front/src/pages/people/__stories__/People.sortBy.stories.tsx index be3600e58..acfae6c7b 100644 --- a/front/src/pages/people/__stories__/People.sortBy.stories.tsx +++ b/front/src/pages/people/__stories__/People.sortBy.stories.tsx @@ -38,7 +38,7 @@ export const Email: Story = { await canvas.findByText( mockedPeopleData[0].displayName, {}, - { timeout: 3000 }, + { timeout: 1000 }, ); }); @@ -82,7 +82,7 @@ export const Reset: Story = { await canvas.findByText( mockedPeopleData[0].displayName, {}, - { timeout: 3000 }, + { timeout: 1000 }, ); });