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 <charles@twenty.com>
This commit is contained in:
Lucas Bordeau
2023-11-04 09:28:55 +01:00
committed by GitHub
parent e70ef58f97
commit 53072298bc
42 changed files with 1018 additions and 885 deletions

View File

@ -1,6 +1,6 @@
import { useEffect, useMemo } from 'react'; import { useEffect, useMemo } from 'react';
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
import { useRecoilState } from 'recoil'; import { useRecoilState, useRecoilValue } from 'recoil';
import { pipelineAvailableFieldDefinitions } from '@/pipeline/constants/pipelineAvailableFieldDefinitions'; import { pipelineAvailableFieldDefinitions } from '@/pipeline/constants/pipelineAvailableFieldDefinitions';
import { useBoardActionBarEntries } from '@/ui/layout/board/hooks/useBoardActionBarEntries'; 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 { isBoardLoadedState } from '@/ui/layout/board/states/isBoardLoadedState';
import { turnFilterIntoWhereClause } from '@/ui/object/object-filter-dropdown/utils/turnFilterIntoWhereClause'; import { turnFilterIntoWhereClause } from '@/ui/object/object-filter-dropdown/utils/turnFilterIntoWhereClause';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
import { useViewScopedStates } from '@/views/hooks/internal/useViewScopedStates';
import { useView } from '@/views/hooks/useView'; import { useView } from '@/views/hooks/useView';
import { useViewGetStates } from '@/views/hooks/useViewGetStates';
import { ViewType } from '@/views/types/ViewType'; import { ViewType } from '@/views/types/ViewType';
import { viewFieldsToBoardFieldDefinitions } from '@/views/utils/viewFieldsToBoardFieldDefinitions'; import { mapViewFieldsToBoardFieldDefinitions } from '@/views/utils/mapViewFieldsToBoardFieldDefinitions';
import { import {
Pipeline, Pipeline,
PipelineProgressableType, PipelineProgressableType,
@ -37,7 +37,11 @@ export const HooksCompanyBoardEffect = () => {
setViewType, setViewType,
} = useView(); } = useView();
const { currentViewFilters, currentViewFields } = useViewGetStates(); const { currentViewFiltersState, currentViewFieldsState } =
useViewScopedStates();
const currentViewFields = useRecoilValue(currentViewFieldsState);
const currentViewFilters = useRecoilValue(currentViewFiltersState);
const [, setIsBoardLoaded] = useRecoilState(isBoardLoadedState); const [, setIsBoardLoaded] = useRecoilState(isBoardLoadedState);
@ -159,7 +163,7 @@ export const HooksCompanyBoardEffect = () => {
useEffect(() => { useEffect(() => {
if (currentViewFields) { if (currentViewFields) {
setBoardCardFields( setBoardCardFields(
viewFieldsToBoardFieldDefinitions( mapViewFieldsToBoardFieldDefinitions(
currentViewFields, currentViewFields,
pipelineAvailableFieldDefinitions, pipelineAvailableFieldDefinitions,
), ),

View File

@ -16,12 +16,11 @@ import { tableFiltersScopedState } from '@/ui/object/record-table/states/tableFi
import { tableSortsScopedState } from '@/ui/object/record-table/states/tableSortsScopedState'; import { tableSortsScopedState } from '@/ui/object/record-table/states/tableSortsScopedState';
import { ViewBar } from '@/views/components/ViewBar'; import { ViewBar } from '@/views/components/ViewBar';
import { useViewFields } from '@/views/hooks/internal/useViewFields'; import { useViewFields } from '@/views/hooks/internal/useViewFields';
import { useView } from '@/views/hooks/useView';
import { ViewScope } from '@/views/scopes/ViewScope'; import { ViewScope } from '@/views/scopes/ViewScope';
import { columnDefinitionsToViewFields } from '@/views/utils/columnDefinitionToViewField'; import { mapColumnDefinitionsToViewFields } from '@/views/utils/mapColumnDefinitionToViewField';
import { viewFieldsToColumnDefinitions } from '@/views/utils/viewFieldsToColumnDefinitions'; import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions';
import { viewFiltersToFilters } from '@/views/utils/viewFiltersToFilters'; import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
import { viewSortsToSorts } from '@/views/utils/viewSortsToSorts'; import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
import { import {
UpdateOneCompanyMutationVariables, UpdateOneCompanyMutationVariables,
useGetCompaniesQuery, useGetCompaniesQuery,
@ -58,9 +57,6 @@ export const CompanyTable = () => {
const [getWorkspaceMember] = useGetWorkspaceMembersLazyQuery(); const [getWorkspaceMember] = useGetWorkspaceMembersLazyQuery();
const { persistViewFields } = useViewFields(viewScopeId); const { persistViewFields } = useViewFields(viewScopeId);
const { setCurrentViewFields } = useView({
viewScopeId,
});
const { setContextMenuEntries, setActionBarEntries } = const { setContextMenuEntries, setActionBarEntries } =
useCompanyTableContextMenuEntries(); useCompanyTableContextMenuEntries();
@ -102,25 +98,24 @@ export const CompanyTable = () => {
viewScopeId={viewScopeId} viewScopeId={viewScopeId}
onViewFieldsChange={(viewFields) => { onViewFieldsChange={(viewFields) => {
setTableColumns( setTableColumns(
viewFieldsToColumnDefinitions( mapViewFieldsToColumnDefinitions(
viewFields, viewFields,
companiesAvailableFieldDefinitions, companiesAvailableFieldDefinitions,
), ),
); );
}} }}
onViewFiltersChange={(viewFilters) => { onViewFiltersChange={(viewFilters) => {
setTableFilters(viewFiltersToFilters(viewFilters)); setTableFilters(mapViewFiltersToFilters(viewFilters));
}} }}
onViewSortsChange={(viewSorts) => { onViewSortsChange={(viewSorts) => {
setTableSorts(viewSortsToSorts(viewSorts)); setTableSorts(mapViewSortsToSorts(viewSorts));
}} }}
> >
<StyledContainer> <StyledContainer>
<TableContext.Provider <TableContext.Provider
value={{ value={{
onColumnsChange: useRecoilCallback(() => (columns) => { onColumnsChange: useRecoilCallback(() => (columns) => {
setCurrentViewFields?.(columnDefinitionsToViewFields(columns)); persistViewFields(mapColumnDefinitionsToViewFields(columns));
persistViewFields(columnDefinitionsToViewFields(columns));
}), }),
}} }}
> >

View File

@ -10,12 +10,11 @@ import { tableFiltersScopedState } from '@/ui/object/record-table/states/tableFi
import { tableSortsScopedState } from '@/ui/object/record-table/states/tableSortsScopedState'; import { tableSortsScopedState } from '@/ui/object/record-table/states/tableSortsScopedState';
import { ViewBar } from '@/views/components/ViewBar'; import { ViewBar } from '@/views/components/ViewBar';
import { useViewFields } from '@/views/hooks/internal/useViewFields'; import { useViewFields } from '@/views/hooks/internal/useViewFields';
import { useView } from '@/views/hooks/useView';
import { ViewScope } from '@/views/scopes/ViewScope'; import { ViewScope } from '@/views/scopes/ViewScope';
import { columnDefinitionsToViewFields } from '@/views/utils/columnDefinitionToViewField'; import { mapColumnDefinitionsToViewFields } from '@/views/utils/mapColumnDefinitionToViewField';
import { viewFieldsToColumnDefinitions } from '@/views/utils/viewFieldsToColumnDefinitions'; import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions';
import { viewFiltersToFilters } from '@/views/utils/viewFiltersToFilters'; import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
import { viewSortsToSorts } from '@/views/utils/viewSortsToSorts'; import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
import { useObjectMetadataItemInContext } from '../hooks/useObjectMetadataItemInContext'; import { useObjectMetadataItemInContext } from '../hooks/useObjectMetadataItemInContext';
import { useUpdateOneObject } from '../hooks/useUpdateOneObject'; import { useUpdateOneObject } from '../hooks/useUpdateOneObject';
@ -46,9 +45,6 @@ export const ObjectTable = ({ objectNamePlural }: ObjectTableProps) => {
const viewScopeId = objectNamePlural ?? ''; const viewScopeId = objectNamePlural ?? '';
const { persistViewFields } = useViewFields(viewScopeId); const { persistViewFields } = useViewFields(viewScopeId);
const { setCurrentViewFields } = useView({
viewScopeId,
});
const setTableColumns = useSetRecoilState( const setTableColumns = useSetRecoilState(
tableColumnsScopedState(tableScopeId), tableColumnsScopedState(tableScopeId),
@ -81,22 +77,21 @@ export const ObjectTable = ({ objectNamePlural }: ObjectTableProps) => {
viewScopeId={viewScopeId} viewScopeId={viewScopeId}
onViewFieldsChange={(viewFields) => { onViewFieldsChange={(viewFields) => {
setTableColumns( setTableColumns(
viewFieldsToColumnDefinitions(viewFields, columnDefinitions), mapViewFieldsToColumnDefinitions(viewFields, columnDefinitions),
); );
}} }}
onViewFiltersChange={(viewFilters) => { onViewFiltersChange={(viewFilters) => {
setTableFilters(viewFiltersToFilters(viewFilters)); setTableFilters(mapViewFiltersToFilters(viewFilters));
}} }}
onViewSortsChange={(viewSorts) => { onViewSortsChange={(viewSorts) => {
setTableSorts(viewSortsToSorts(viewSorts)); setTableSorts(mapViewSortsToSorts(viewSorts));
}} }}
> >
<StyledContainer> <StyledContainer>
<TableContext.Provider <TableContext.Provider
value={{ value={{
onColumnsChange: useRecoilCallback(() => (columns) => { onColumnsChange: useRecoilCallback(() => (columns) => {
setCurrentViewFields?.(columnDefinitionsToViewFields(columns)); persistViewFields(mapColumnDefinitionsToViewFields(columns));
persistViewFields(columnDefinitionsToViewFields(columns));
}), }),
}} }}
> >

View File

@ -1,10 +1,11 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useRecoilCallback, useSetRecoilState } from 'recoil'; import { useSetRecoilState } from 'recoil';
import { peopleAvailableFieldDefinitions } from '@/people/constants/peopleAvailableFieldDefinitions'; import { peopleAvailableFieldDefinitions } from '@/people/constants/peopleAvailableFieldDefinitions';
import { getPeopleOptimisticEffectDefinition } from '@/people/graphql/optimistic-effect-definitions/getPeopleOptimisticEffectDefinition'; import { getPeopleOptimisticEffectDefinition } from '@/people/graphql/optimistic-effect-definitions/getPeopleOptimisticEffectDefinition';
import { usePersonTableContextMenuEntries } from '@/people/hooks/usePersonTableContextMenuEntries'; import { usePersonTableContextMenuEntries } from '@/people/hooks/usePersonTableContextMenuEntries';
import { useSpreadsheetPersonImport } from '@/people/hooks/useSpreadsheetPersonImport'; import { useSpreadsheetPersonImport } from '@/people/hooks/useSpreadsheetPersonImport';
import { FieldMetadata } from '@/ui/object/field/types/FieldMetadata';
import { RecordTable } from '@/ui/object/record-table/components/RecordTable'; import { RecordTable } from '@/ui/object/record-table/components/RecordTable';
import { RecordTableEffect } from '@/ui/object/record-table/components/RecordTableEffect'; import { RecordTableEffect } from '@/ui/object/record-table/components/RecordTableEffect';
import { TableOptionsDropdownId } from '@/ui/object/record-table/constants/TableOptionsDropdownId'; 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 { tableColumnsScopedState } from '@/ui/object/record-table/states/tableColumnsScopedState';
import { tableFiltersScopedState } from '@/ui/object/record-table/states/tableFiltersScopedState'; import { tableFiltersScopedState } from '@/ui/object/record-table/states/tableFiltersScopedState';
import { tableSortsScopedState } from '@/ui/object/record-table/states/tableSortsScopedState'; 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 { ViewBar } from '@/views/components/ViewBar';
import { useViewFields } from '@/views/hooks/internal/useViewFields'; import { useViewFields } from '@/views/hooks/internal/useViewFields';
import { useView } from '@/views/hooks/useView';
import { ViewScope } from '@/views/scopes/ViewScope'; import { ViewScope } from '@/views/scopes/ViewScope';
import { columnDefinitionsToViewFields } from '@/views/utils/columnDefinitionToViewField'; import { mapColumnDefinitionsToViewFields } from '@/views/utils/mapColumnDefinitionToViewField';
import { viewFieldsToColumnDefinitions } from '@/views/utils/viewFieldsToColumnDefinitions'; import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions';
import { viewFiltersToFilters } from '@/views/utils/viewFiltersToFilters'; import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
import { viewSortsToSorts } from '@/views/utils/viewSortsToSorts'; import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
import { import {
UpdateOnePersonMutationVariables, UpdateOnePersonMutationVariables,
useGetPeopleQuery, useGetPeopleQuery,
@ -49,9 +50,6 @@ export const PersonTable = () => {
const upsertRecordTableItem = useUpsertRecordTableItem(); const upsertRecordTableItem = useUpsertRecordTableItem();
const { persistViewFields } = useViewFields(viewScopeId); const { persistViewFields } = useViewFields(viewScopeId);
const { setCurrentViewFields } = useView({
viewScopeId,
});
const { setContextMenuEntries, setActionBarEntries } = const { setContextMenuEntries, setActionBarEntries } =
usePersonTableContextMenuEntries(); usePersonTableContextMenuEntries();
@ -68,6 +66,10 @@ export const PersonTable = () => {
}); });
}; };
const handleColumnChange = (columns: ColumnDefinition<FieldMetadata>[]) => {
persistViewFields(mapColumnDefinitionsToViewFields(columns));
};
const { openPersonSpreadsheetImport: onImport } = const { openPersonSpreadsheetImport: onImport } =
useSpreadsheetPersonImport(); useSpreadsheetPersonImport();
@ -82,26 +84,23 @@ export const PersonTable = () => {
viewScopeId={viewScopeId} viewScopeId={viewScopeId}
onViewFieldsChange={(viewFields) => { onViewFieldsChange={(viewFields) => {
setTableColumns( setTableColumns(
viewFieldsToColumnDefinitions( mapViewFieldsToColumnDefinitions(
viewFields, viewFields,
peopleAvailableFieldDefinitions, peopleAvailableFieldDefinitions,
), ),
); );
}} }}
onViewFiltersChange={(viewFilters) => { onViewFiltersChange={(viewFilters) => {
setTableFilters(viewFiltersToFilters(viewFilters)); setTableFilters(mapViewFiltersToFilters(viewFilters));
}} }}
onViewSortsChange={(viewSorts) => { onViewSortsChange={(viewSorts) => {
setTableSorts(viewSortsToSorts(viewSorts)); setTableSorts(mapViewSortsToSorts(viewSorts));
}} }}
> >
<StyledContainer> <StyledContainer>
<TableContext.Provider <TableContext.Provider
value={{ value={{
onColumnsChange: useRecoilCallback(() => (columns) => { onColumnsChange: handleColumnChange,
setCurrentViewFields?.(columnDefinitionsToViewFields(columns));
persistViewFields(columnDefinitionsToViewFields(columns));
}),
}} }}
> >
<ViewBar <ViewBar

View File

@ -1,5 +1,5 @@
import { useContext, useRef, useState } from 'react'; import { useContext, useRef, useState } from 'react';
import { useRecoilState } from 'recoil'; import { useRecoilState, useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum'; import { Key } from 'ts-key-enum';
import { v4 } from 'uuid'; import { v4 } from 'uuid';
@ -24,8 +24,8 @@ import { ThemeColor } from '@/ui/theme/constants/colors';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection'; import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection';
import { useViewScopedStates } from '@/views/hooks/internal/useViewScopedStates';
import { useView } from '@/views/hooks/useView'; import { useView } from '@/views/hooks/useView';
import { useViewGetStates } from '@/views/hooks/useViewGetStates';
import { useBoardCardFields } from '../hooks/useBoardCardFields'; import { useBoardCardFields } from '../hooks/useBoardCardFields';
import { boardColumnsState } from '../states/boardColumnsState'; import { boardColumnsState } from '../states/boardColumnsState';
@ -52,9 +52,12 @@ export const BoardOptionsDropdownContent = ({
onStageAdd, onStageAdd,
}: BoardOptionsDropdownContentProps) => { }: BoardOptionsDropdownContentProps) => {
const { setViewEditMode, handleViewNameSubmit } = useView(); const { setViewEditMode, handleViewNameSubmit } = useView();
const { viewEditMode, currentView } = useViewGetStates(); const { viewEditModeState, currentViewSelector } = useViewScopedStates();
const { BoardRecoilScopeContext } = useContext(BoardContext); const { BoardRecoilScopeContext } = useContext(BoardContext);
const viewEditMode = useRecoilValue(viewEditModeState);
const currentView = useRecoilValue(currentViewSelector);
const stageInputRef = useRef<HTMLInputElement>(null); const stageInputRef = useRef<HTMLInputElement>(null);
const viewEditInputRef = useRef<HTMLInputElement>(null); const viewEditInputRef = useRef<HTMLInputElement>(null);

View File

@ -10,6 +10,7 @@ import { isFieldEmail } from '../../types/guards/isFieldEmail';
import { isFieldMoney } from '../../types/guards/isFieldMoney'; import { isFieldMoney } from '../../types/guards/isFieldMoney';
import { isFieldNumber } from '../../types/guards/isFieldNumber'; import { isFieldNumber } from '../../types/guards/isFieldNumber';
import { isFieldPhone } from '../../types/guards/isFieldPhone'; import { isFieldPhone } from '../../types/guards/isFieldPhone';
import { isFieldProbability } from '../../types/guards/isFieldProbability';
import { isFieldRelation } from '../../types/guards/isFieldRelation'; import { isFieldRelation } from '../../types/guards/isFieldRelation';
import { isFieldRelationValue } from '../../types/guards/isFieldRelationValue'; import { isFieldRelationValue } from '../../types/guards/isFieldRelationValue';
import { isFieldText } from '../../types/guards/isFieldText'; import { isFieldText } from '../../types/guards/isFieldText';
@ -34,6 +35,7 @@ export const isEntityFieldEmptyFamilySelector = selectorFamily({
isFieldURL(fieldDefinition) || isFieldURL(fieldDefinition) ||
isFieldDate(fieldDefinition) || isFieldDate(fieldDefinition) ||
isFieldNumber(fieldDefinition) || isFieldNumber(fieldDefinition) ||
isFieldProbability(fieldDefinition) ||
isFieldMoney(fieldDefinition) || isFieldMoney(fieldDefinition) ||
isFieldEmail(fieldDefinition) || isFieldEmail(fieldDefinition) ||
isFieldBoolean(fieldDefinition) || isFieldBoolean(fieldDefinition) ||

View File

@ -1,5 +1,6 @@
import { useCallback, useRef, useState } from 'react'; import { useCallback, useRef, useState } from 'react';
import { OnDragEndResponder } from '@hello-pangea/dnd'; import { OnDragEndResponder } from '@hello-pangea/dnd';
import { useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum'; import { Key } from 'ts-key-enum';
import { IconChevronLeft, IconFileImport, IconTag } from '@/ui/display/icon'; 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 { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection'; import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection';
import { useViewScopedStates } from '@/views/hooks/internal/useViewScopedStates';
import { useView } from '@/views/hooks/useView'; import { useView } from '@/views/hooks/useView';
import { useViewGetStates } from '@/views/hooks/useViewGetStates';
import { useTableColumns } from '../../hooks/useTableColumns'; import { useTableColumns } from '../../hooks/useTableColumns';
import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext'; import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
@ -29,7 +30,10 @@ export const TableOptionsDropdownContent = ({
onImport?: () => void; onImport?: () => void;
}) => { }) => {
const { setViewEditMode, handleViewNameSubmit } = useView(); const { setViewEditMode, handleViewNameSubmit } = useView();
const { viewEditMode, currentView } = useViewGetStates(); const { viewEditModeState, currentViewSelector } = useViewScopedStates();
const viewEditMode = useRecoilValue(viewEditModeState);
const currentView = useRecoilValue(currentViewSelector);
const { closeDropdown } = useDropdown(); const { closeDropdown } = useDropdown();

View File

@ -0,0 +1,7 @@
import { RecoilValueReadOnly } from 'recoil';
import { ScopedStateKey } from '../scopes-internal/types/ScopedStateKey';
export type RecoilScopedSelector<StateType> = (
scopedKey: ScopedStateKey,
) => RecoilValueReadOnly<StateType>;

View File

@ -0,0 +1,7 @@
import { RecoilState } from 'recoil';
import { ScopedStateKey } from '../scopes-internal/types/ScopedStateKey';
export type RecoilScopedState<StateType> = (
scopedKey: ScopedStateKey,
) => RecoilState<StateType>;

View File

@ -0,0 +1,30 @@
import {
GetCallback,
GetRecoilValue,
Loadable,
RecoilValue,
selectorFamily,
WrappedValue,
} from 'recoil';
import { ScopedStateKey } from '../scopes-internal/types/ScopedStateKey';
type SelectorGetter<T, P> = (
param: P,
) => (opts: {
get: GetRecoilValue;
getCallback: GetCallback;
}) => Promise<T> | RecoilValue<T> | Loadable<T> | WrappedValue<T> | T;
export const createScopedSelector = <ValueType>({
key,
get,
}: {
key: string;
get: SelectorGetter<ValueType, ScopedStateKey>;
}) => {
return selectorFamily<ValueType, ScopedStateKey>({
key,
get,
});
};

View File

@ -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<FamilyKey>,
) => RecoilState<StateType>,
scopeId: string,
familyKey: FamilyKey,
) => {
return recoilState({
scopeId,
familyKey: familyKey || ('' as FamilyKey),
});
};

View File

@ -0,0 +1,10 @@
import { RecoilScopedSelector } from '../types/RecoilScopedSelector';
export const getScopedSelector = <StateType>(
recoilScopedState: RecoilScopedSelector<StateType>,
scopeId: string,
) => {
return recoilScopedState({
scopeId,
});
};

View File

@ -0,0 +1,10 @@
import { RecoilScopedState } from '../types/RecoilScopedState';
export const getScopedState = <StateType>(
recoilScopedState: RecoilScopedState<StateType>,
scopeId: string,
) => {
return recoilScopedState({
scopeId,
});
};

View File

@ -0,0 +1,15 @@
import { Snapshot } from 'recoil';
import { RecoilScopedSelector } from '../types/RecoilScopedSelector';
import { getScopedSelector } from './getScopedSelector';
export const getSnapshotScopedSelector = <StateType>(
snapshot: Snapshot,
scopedState: RecoilScopedSelector<StateType>,
scopeId: string,
) => {
return snapshot
.getLoadable(getScopedSelector(scopedState, scopeId))
.getValue();
};

View File

@ -0,0 +1,13 @@
import { Snapshot } from 'recoil';
import { RecoilScopedState } from '../types/RecoilScopedState';
import { getScopedState } from './getScopedState';
export const getSnapshotScopedValue = <StateType>(
snapshot: Snapshot,
scopedState: RecoilScopedState<StateType>,
scopeId: string,
) => {
return snapshot.getLoadable(getScopedState(scopedState, scopeId)).getValue();
};

View File

@ -0,0 +1,8 @@
import { RecoilState, RecoilValueReadOnly, Snapshot } from 'recoil';
export const getSnapshotValue = <StateType>(
snapshot: Snapshot,
state: RecoilState<StateType> | RecoilValueReadOnly<StateType>,
) => {
return snapshot.getLoadable(state).getValue();
};

View File

@ -1,5 +1,6 @@
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum'; import { Key } from 'ts-key-enum';
import { IconChevronDown, IconPlus } from '@/ui/display/icon'; 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 { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useView } from '@/views/hooks/useView'; import { useView } from '@/views/hooks/useView';
import { useViewGetStates } from '../hooks/useViewGetStates'; import { useViewScopedStates } from '../hooks/internal/useViewScopedStates';
const StyledContainer = styled.div` const StyledContainer = styled.div`
display: inline-flex; display: inline-flex;
margin-right: ${({ theme }) => theme.spacing(2)}; margin-right: ${({ theme }) => theme.spacing(2)};
position: relative; position: relative;
`; `;
export type UpdateViewButtonGroupProps = { export type UpdateViewButtonGroupProps = {
hotkeyScope: string; hotkeyScope: string;
onViewEditModeChange?: () => void; onViewEditModeChange?: () => void;
@ -28,7 +30,11 @@ export const UpdateViewButtonGroup = ({
}: UpdateViewButtonGroupProps) => { }: UpdateViewButtonGroupProps) => {
const [isDropdownOpen, setIsDropdownOpen] = useState(false); const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const { updateCurrentView, setViewEditMode } = useView(); const { updateCurrentView, setViewEditMode } = useView();
const { canPersistFilters, canPersistSorts } = useViewGetStates(); const { canPersistFiltersSelector, canPersistSortsSelector } =
useViewScopedStates();
const canPersistFilters = useRecoilValue(canPersistFiltersSelector);
const canPersistSorts = useRecoilValue(canPersistSortsSelector);
const canPersistView = canPersistFilters || canPersistSorts; const canPersistView = canPersistFilters || canPersistSorts;

View File

@ -1,4 +1,5 @@
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { useRecoilValue } from 'recoil';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { TopBar } from '@/ui/layout/top-bar/TopBar'; 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 { ObjectSortDropdownButton } from '@/ui/object/object-sort-dropdown/components/ObjectSortDropdownButton';
import { ObjectSortDropdownScope } from '@/ui/object/object-sort-dropdown/scopes/ObjectSortDropdownScope'; import { ObjectSortDropdownScope } from '@/ui/object/object-sort-dropdown/scopes/ObjectSortDropdownScope';
import { useViewScopedStates } from '../hooks/internal/useViewScopedStates';
import { useView } from '../hooks/useView'; import { useView } from '../hooks/useView';
import { useViewGetStates } from '../hooks/useViewGetStates';
import { ViewsHotkeyScope } from '../types/ViewsHotkeyScope'; import { ViewsHotkeyScope } from '../types/ViewsHotkeyScope';
import { UpdateViewButtonGroup } from './UpdateViewButtonGroup'; import { UpdateViewButtonGroup } from './UpdateViewButtonGroup';
@ -32,8 +33,16 @@ export const ViewBar = ({
dropdownScopeId: optionsDropdownScopeId, dropdownScopeId: optionsDropdownScopeId,
}); });
const { upsertViewSort, upsertViewFilter } = useView(); const { upsertViewSort, upsertViewFilter } = useView();
const { availableFilterDefinitions, availableSortDefinitions } =
useViewGetStates(); const { availableFilterDefinitionsState, availableSortDefinitionsState } =
useViewScopedStates();
const availableFilterDefinitions = useRecoilValue(
availableFilterDefinitionsState,
);
const availableSortDefinitions = useRecoilValue(
availableSortDefinitionsState,
);
return ( return (
<ObjectFilterDropdownScope <ObjectFilterDropdownScope

View File

@ -1,12 +1,13 @@
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil';
import { IconArrowDown, IconArrowUp } from '@/ui/display/icon/index'; import { IconArrowDown, IconArrowUp } from '@/ui/display/icon/index';
import { AddObjectFilterFromDetailsButton } from '@/ui/object/object-filter-dropdown/components/AddObjectFilterFromDetailsButton'; import { AddObjectFilterFromDetailsButton } from '@/ui/object/object-filter-dropdown/components/AddObjectFilterFromDetailsButton';
import { getOperandLabelShort } from '@/ui/object/object-filter-dropdown/utils/getOperandLabel'; import { getOperandLabelShort } from '@/ui/object/object-filter-dropdown/utils/getOperandLabel';
import { useViewScopedStates } from '../hooks/internal/useViewScopedStates';
import { useView } from '../hooks/useView'; import { useView } from '../hooks/useView';
import { useViewGetStates } from '../hooks/useViewGetStates';
import SortOrFilterChip from './SortOrFilterChip'; import SortOrFilterChip from './SortOrFilterChip';
@ -88,12 +89,18 @@ export const ViewBarDetails = ({
rightComponent, rightComponent,
}: ViewBarDetailsProps) => { }: ViewBarDetailsProps) => {
const { const {
currentViewSorts, currentViewSortsState,
currentViewFilters, currentViewFiltersState,
canPersistFilters, canPersistFiltersSelector,
canPersistSorts, canPersistSortsSelector,
isViewBarExpanded, isViewBarExpandedState,
} = useViewGetStates(); } = 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(); const { resetViewBar, removeViewSort, removeViewFilter } = useView();

View File

@ -1,66 +1,58 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
import { useRecoilCallback } from 'recoil'; import { useRecoilCallback, useRecoilValue } from 'recoil';
import { useFindManyObjects } from '@/metadata/hooks/useFindManyObjects'; import { useFindManyObjects } from '@/metadata/hooks/useFindManyObjects';
import { PaginatedObjectTypeResults } from '@/metadata/types/PaginatedObjectTypeResults'; import { PaginatedObjectTypeResults } from '@/metadata/types/PaginatedObjectTypeResults';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { assertNotNull } from '~/utils/assert'; import { assertNotNull } from '~/utils/assert';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
import { useViewScopedStates } from '../hooks/internal/useViewScopedStates';
import { useView } from '../hooks/useView'; 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 { View } from '../types/View';
import { ViewField } from '../types/ViewField'; import { ViewField } from '../types/ViewField';
import { ViewFilter } from '../types/ViewFilter'; import { ViewFilter } from '../types/ViewFilter';
import { ViewSort } from '../types/ViewSort'; import { ViewSort } from '../types/ViewSort';
import { getViewScopedStatesFromSnapshot } from '../utils/getViewScopedStatesFromSnapshot';
import { getViewScopedStateValuesFromSnapshot } from '../utils/getViewScopedStateValuesFromSnapshot';
export const ViewBarEffect = () => { export const ViewBarEffect = () => {
const { const {
scopeId: viewScopeId, scopeId: viewScopeId,
setCurrentViewFields,
setSavedViewFields,
setCurrentViewFilters,
setSavedViewFilters,
setCurrentViewSorts,
setSavedViewSorts,
currentViewId, currentViewId,
setViews,
loadView, loadView,
changeViewInUrl, changeViewInUrl,
setCurrentViewId,
} = useView(); } = useView();
const [searchParams] = useSearchParams(); const [searchParams] = useSearchParams();
const currentViewIdFromUrl = searchParams.get('view'); const currentViewIdFromUrl = searchParams.get('view');
const { viewType, viewObjectId } = useViewGetStates(viewScopeId); const { viewTypeState, viewObjectIdState } = useViewScopedStates();
const viewType = useRecoilValue(viewTypeState);
const viewObjectId = useRecoilValue(viewObjectIdState);
useFindManyObjects({ useFindManyObjects({
objectNamePlural: 'viewsV2', objectNamePlural: 'viewsV2',
filter: { type: { eq: viewType }, objectId: { eq: viewObjectId } }, filter: { type: { eq: viewType }, objectId: { eq: viewObjectId } },
onCompleted: useRecoilCallback( onCompleted: useRecoilCallback(
({ snapshot }) => ({ snapshot, set }) =>
async (data: PaginatedObjectTypeResults<View>) => { async (data: PaginatedObjectTypeResults<View>) => {
const nextViews = data.edges.map((view) => ({ const nextViews = data.edges.map((view) => ({
id: view.node.id, id: view.node.id,
name: view.node.name, name: view.node.name,
objectId: view.node.objectId, 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; if (!nextViews.length) return;
@ -74,43 +66,39 @@ export const ViewBarEffect = () => {
objectNamePlural: 'viewFieldsV2', objectNamePlural: 'viewFieldsV2',
filter: { viewId: { eq: currentViewId } }, filter: { viewId: { eq: currentViewId } },
onCompleted: useRecoilCallback( onCompleted: useRecoilCallback(
({ snapshot }) => ({ snapshot, set }) =>
async (data: PaginatedObjectTypeResults<ViewField>) => { async (data: PaginatedObjectTypeResults<ViewField>) => {
const availableFields = snapshot const {
.getLoadable( availableFieldDefinitions,
availableFieldDefinitionsScopedState({ scopeId: viewScopeId }), onViewFieldsChange,
) savedViewFields,
.getValue(); currentViewId,
} = getViewScopedStateValuesFromSnapshot({
snapshot,
viewScopeId,
});
const onViewFieldsChange = snapshot const { savedViewFieldsState, currentViewFieldsState } =
.getLoadable( getViewScopedStatesFromSnapshot({
onViewFieldsChangeScopedState({ scopeId: viewScopeId }), snapshot,
) viewScopeId,
.getValue(); });
if (!availableFields || !currentViewId) { if (!availableFieldDefinitions || !currentViewId) {
return; return;
} }
const savedViewFields = snapshot
.getLoadable(
savedViewFieldsScopedFamilyState({
scopeId: viewScopeId,
familyKey: currentViewId,
}),
)
.getValue();
const queriedViewFields = data.edges const queriedViewFields = data.edges
.map((viewField) => viewField.node) .map((viewField) => viewField.node)
.filter(assertNotNull); .filter(assertNotNull);
if (!isDeeplyEqual(savedViewFields, queriedViewFields)) { if (!isDeeplyEqual(savedViewFields, queriedViewFields)) {
setCurrentViewFields?.(queriedViewFields); set(currentViewFieldsState, queriedViewFields);
setSavedViewFields?.(queriedViewFields); set(savedViewFieldsState, queriedViewFields);
onViewFieldsChange?.(queriedViewFields); onViewFieldsChange?.(queriedViewFields);
} }
}, },
[viewScopeId],
), ),
}); });
@ -119,33 +107,28 @@ export const ViewBarEffect = () => {
objectNamePlural: 'viewFiltersV2', objectNamePlural: 'viewFiltersV2',
filter: { viewId: { eq: currentViewId } }, filter: { viewId: { eq: currentViewId } },
onCompleted: useRecoilCallback( onCompleted: useRecoilCallback(
({ snapshot }) => ({ snapshot, set }) =>
async (data: PaginatedObjectTypeResults<Required<ViewFilter>>) => { async (data: PaginatedObjectTypeResults<Required<ViewFilter>>) => {
const availableFilterDefinitions = snapshot const {
.getLoadable( availableFilterDefinitions,
availableFilterDefinitionsScopedState({ scopeId: viewScopeId }), savedViewFilters,
) onViewFiltersChange,
.getValue(); currentViewId,
} = getViewScopedStateValuesFromSnapshot({
snapshot,
viewScopeId,
});
const { savedViewFiltersState, currentViewFiltersState } =
getViewScopedStatesFromSnapshot({
snapshot,
viewScopeId,
});
if (!availableFilterDefinitions || !currentViewId) { if (!availableFilterDefinitions || !currentViewId) {
return; return;
} }
const savedViewFilters = snapshot
.getLoadable(
savedViewFiltersScopedFamilyState({
scopeId: viewScopeId,
familyKey: currentViewId,
}),
)
.getValue();
const onViewFiltersChange = snapshot
.getLoadable(
onViewFiltersChangeScopedState({ scopeId: viewScopeId }),
)
.getValue();
const queriedViewFilters = data.edges const queriedViewFilters = data.edges
.map(({ node }) => { .map(({ node }) => {
const availableFilterDefinition = availableFilterDefinitions.find( const availableFilterDefinition = availableFilterDefinitions.find(
@ -163,11 +146,12 @@ export const ViewBarEffect = () => {
.filter(assertNotNull); .filter(assertNotNull);
if (!isDeeplyEqual(savedViewFilters, queriedViewFilters)) { if (!isDeeplyEqual(savedViewFilters, queriedViewFilters)) {
setSavedViewFilters?.(queriedViewFilters); set(savedViewFiltersState, queriedViewFilters);
setCurrentViewFilters?.(queriedViewFilters); set(currentViewFiltersState, queriedViewFilters);
onViewFiltersChange?.(queriedViewFilters); onViewFiltersChange?.(queriedViewFilters);
} }
}, },
[viewScopeId],
), ),
}); });
@ -176,31 +160,28 @@ export const ViewBarEffect = () => {
objectNamePlural: 'viewSortsV2', objectNamePlural: 'viewSortsV2',
filter: { viewId: { eq: currentViewId } }, filter: { viewId: { eq: currentViewId } },
onCompleted: useRecoilCallback( onCompleted: useRecoilCallback(
({ snapshot }) => ({ snapshot, set }) =>
async (data: PaginatedObjectTypeResults<Required<ViewSort>>) => { async (data: PaginatedObjectTypeResults<Required<ViewSort>>) => {
const availableSortDefinitions = snapshot const {
.getLoadable( availableSortDefinitions,
availableSortDefinitionsScopedState({ scopeId: viewScopeId }), savedViewSorts,
) onViewSortsChange,
.getValue(); currentViewId,
} = getViewScopedStateValuesFromSnapshot({
snapshot,
viewScopeId,
});
const { savedViewSortsState, currentViewSortsState } =
getViewScopedStatesFromSnapshot({
snapshot,
viewScopeId,
});
if (!availableSortDefinitions || !currentViewId) { if (!availableSortDefinitions || !currentViewId) {
return; return;
} }
const savedViewSorts = snapshot
.getLoadable(
savedViewSortsScopedFamilyState({
scopeId: viewScopeId,
familyKey: currentViewId,
}),
)
.getValue();
const onViewSortsChange = snapshot
.getLoadable(onViewSortsChangeScopedState({ scopeId: viewScopeId }))
.getValue();
const queriedViewSorts = data.edges const queriedViewSorts = data.edges
.map(({ node }) => { .map(({ node }) => {
const availableSortDefinition = availableSortDefinitions.find( const availableSortDefinition = availableSortDefinitions.find(
@ -219,18 +200,20 @@ export const ViewBarEffect = () => {
.filter(assertNotNull); .filter(assertNotNull);
if (!isDeeplyEqual(savedViewSorts, queriedViewSorts)) { if (!isDeeplyEqual(savedViewSorts, queriedViewSorts)) {
setSavedViewSorts?.(queriedViewSorts); set(savedViewSortsState, queriedViewSorts);
setCurrentViewSorts?.(queriedViewSorts); set(currentViewSortsState, queriedViewSorts);
onViewSortsChange?.(queriedViewSorts); onViewSortsChange?.(queriedViewSorts);
} }
}, },
[viewScopeId],
), ),
}); });
useEffect(() => { useEffect(() => {
if (!currentViewIdFromUrl) return; if (!currentViewIdFromUrl) return;
loadView(currentViewIdFromUrl); loadView(currentViewIdFromUrl);
}, [currentViewIdFromUrl, loadView, setCurrentViewId]); }, [currentViewIdFromUrl, loadView]);
return <></>; return <></>;
}; };

View File

@ -1,7 +1,7 @@
import { MouseEvent } from 'react'; import { MouseEvent } from 'react';
import { useTheme } from '@emotion/react'; import { useTheme } from '@emotion/react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useRecoilCallback } from 'recoil'; import { useRecoilCallback, useRecoilValue } from 'recoil';
import { import {
IconChevronDown, IconChevronDown,
@ -22,8 +22,8 @@ import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { assertNotNull } from '~/utils/assert'; import { assertNotNull } from '~/utils/assert';
import { ViewsDropdownId } from '../constants/ViewsDropdownId'; import { ViewsDropdownId } from '../constants/ViewsDropdownId';
import { useViewScopedStates } from '../hooks/internal/useViewScopedStates';
import { useView } from '../hooks/useView'; import { useView } from '../hooks/useView';
import { useViewGetStates } from '../hooks/useViewGetStates';
const StyledBoldDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)` const StyledBoldDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)`
font-weight: ${({ theme }) => theme.font.weight.regular}; font-weight: ${({ theme }) => theme.font.weight.regular};
@ -68,12 +68,17 @@ export const ViewsDropdownButton = ({
optionsDropdownScopeId, optionsDropdownScopeId,
}: ViewsDropdownButtonProps) => { }: ViewsDropdownButtonProps) => {
const theme = useTheme(); const theme = useTheme();
const { scopeId, removeView, currentViewId, changeViewInUrl } = useView(); const { removeView, changeViewInUrl } = useView();
const { views, currentView, entityCountInCurrentView } = useViewGetStates( const { viewsState, currentViewSelector, entityCountInCurrentViewState } =
scopeId, useViewScopedStates();
currentViewId,
const views = useRecoilValue(viewsState);
const currentView = useRecoilValue(currentViewSelector);
const entityCountInCurrentView = useRecoilValue(
entityCountInCurrentViewState,
); );
const { setViewEditMode } = useView(); const { setViewEditMode } = useView();
const { const {

View File

@ -0,0 +1,2 @@
// TODO: find a better pattern than using '' as a fallback
export const UNDEFINED_FAMILY_ITEM_ID = '';

View File

@ -2,37 +2,28 @@ import { useApolloClient } from '@apollo/client';
import { useRecoilCallback } from 'recoil'; import { useRecoilCallback } from 'recoil';
import { useFindOneObjectMetadataItem } from '@/metadata/hooks/useFindOneObjectMetadataItem'; 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 { ViewField } from '@/views/types/ViewField';
import { getViewScopedStateValuesFromSnapshot } from '@/views/utils/getViewScopedStateValuesFromSnapshot';
export const useViewFields = (viewScopeId: string) => { export const useViewFields = (viewScopeId: string) => {
const { updateOneMutation, createOneMutation, findManyQuery } = const { updateOneMutation, createOneMutation, findManyQuery } =
useFindOneObjectMetadataItem({ useFindOneObjectMetadataItem({
objectNameSingular: 'viewFieldV2', objectNameSingular: 'viewFieldV2',
}); });
const apolloClient = useApolloClient(); const apolloClient = useApolloClient();
const persistViewFields = useRecoilCallback( const persistViewFields = useRecoilCallback(
({ snapshot }) => ({ snapshot }) =>
async (viewFieldsToPersist: ViewField[], viewId?: string) => { async (viewFieldsToPersist: ViewField[], viewId?: string) => {
const currentViewId = snapshot const { viewObjectId, currentViewId, savedViewFieldsByKey } =
.getLoadable(currentViewIdScopedState({ scopeId: viewScopeId })) getViewScopedStateValuesFromSnapshot({
.getValue(); snapshot,
viewScopeId,
viewId,
});
const viewObjectId = snapshot const viewIdToPersist = viewId ?? currentViewId;
.getLoadable(viewObjectIdScopeState({ scopeId: viewScopeId }))
.getValue();
const savedViewFieldsByKey = snapshot
.getLoadable(
savedViewFieldByKeyScopedFamilySelector({
viewScopeId: viewScopeId,
viewId: viewId ?? currentViewId,
}),
)
.getValue();
if (!currentViewId || !savedViewFieldsByKey || !viewObjectId) { if (!currentViewId || !savedViewFieldsByKey || !viewObjectId) {
return; return;
@ -50,7 +41,7 @@ export const useViewFields = (viewScopeId: string) => {
variables: { variables: {
input: { input: {
fieldId: viewField.fieldId, fieldId: viewField.fieldId,
viewId: viewId, viewId: viewIdToPersist,
isVisible: viewField.isVisible, isVisible: viewField.isVisible,
size: viewField.size, size: viewField.size,
position: viewField.position, position: viewField.position,
@ -87,7 +78,6 @@ export const useViewFields = (viewScopeId: string) => {
const viewFieldsToCreate = viewFieldsToPersist.filter( const viewFieldsToCreate = viewFieldsToPersist.filter(
(viewField) => !savedViewFieldsByKey[viewField.fieldId], (viewField) => !savedViewFieldsByKey[viewField.fieldId],
); );
await _createViewFields(viewFieldsToCreate);
const viewFieldsToUpdate = viewFieldsToPersist.filter( const viewFieldsToUpdate = viewFieldsToPersist.filter(
(viewFieldToPersit) => (viewFieldToPersit) =>
@ -100,8 +90,17 @@ export const useViewFields = (viewScopeId: string) => {
viewFieldToPersit.isVisible), viewFieldToPersit.isVisible),
); );
await _createViewFields(viewFieldsToCreate);
await _updateViewFields(viewFieldsToUpdate); await _updateViewFields(viewFieldsToUpdate);
}, },
[
apolloClient,
createOneMutation,
findManyQuery,
updateOneMutation,
viewScopeId,
],
); );
return { persistViewFields }; return { persistViewFields };

View File

@ -4,14 +4,11 @@ import { useRecoilCallback } from 'recoil';
import { useFindOneObjectMetadataItem } from '@/metadata/hooks/useFindOneObjectMetadataItem'; import { useFindOneObjectMetadataItem } from '@/metadata/hooks/useFindOneObjectMetadataItem';
import { Filter } from '@/ui/object/object-filter-dropdown/types/Filter'; 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 { savedViewFiltersScopedFamilyState } from '@/views/states/savedViewFiltersScopedFamilyState';
import { savedViewFiltersByKeyScopedFamilySelector } from '@/views/states/selectors/savedViewFiltersByKeyScopedFamilySelector';
import { ViewFilter } from '@/views/types/ViewFilter'; 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) => { export const useViewFilters = (viewScopeId: string) => {
const { const {
@ -23,17 +20,27 @@ export const useViewFilters = (viewScopeId: string) => {
objectNameSingular: 'viewFilterV2', objectNameSingular: 'viewFilterV2',
}); });
const apolloClient = useApolloClient(); const apolloClient = useApolloClient();
const { setCurrentViewFilters } = useViewSetStates(viewScopeId);
const { currentViewFiltersState } = useViewScopedStates();
const persistViewFilters = useRecoilCallback( const persistViewFilters = useRecoilCallback(
({ snapshot, set }) => ({ snapshot, set }) =>
async (viewId?: string) => { async (viewId?: string) => {
const currentViewId = snapshot const { currentViewId, currentViewFilters, savedViewFiltersByKey } =
.getLoadable(currentViewIdScopedState({ scopeId: viewScopeId })) getViewScopedStateValuesFromSnapshot({
.getValue(); snapshot,
viewScopeId,
});
if (!currentViewId) { if (!currentViewId) {
return; return;
} }
if (!currentViewFilters) {
return;
}
if (!savedViewFiltersByKey) {
return;
}
const createViewFilters = (viewFiltersToCreate: ViewFilter[]) => { const createViewFilters = (viewFiltersToCreate: ViewFilter[]) => {
if (!viewFiltersToCreate.length) return; 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( const filtersToCreate = currentViewFilters.filter(
(filter) => !savedViewFiltersByKey[filter.fieldId], (filter) => !savedViewFiltersByKey[filter.fieldId],
); );
@ -158,37 +140,26 @@ export const useViewFilters = (viewScopeId: string) => {
); );
const upsertViewFilter = useRecoilCallback( const upsertViewFilter = useRecoilCallback(
({ snapshot }) => ({ snapshot, set }) =>
(filterToUpsert: Filter) => { (filterToUpsert: Filter) => {
const currentViewId = snapshot const { currentViewId, savedViewFiltersByKey, onViewFiltersChange } =
.getLoadable(currentViewIdScopedState({ scopeId: viewScopeId })) getViewScopedStateValuesFromSnapshot({
.getValue(); snapshot,
viewScopeId,
});
if (!currentViewId) { if (!currentViewId) {
return; return;
} }
const savedViewFiltersByKey = snapshot
.getLoadable(
savedViewFiltersByKeyScopedFamilySelector({
scopeId: viewScopeId,
viewId: currentViewId,
}),
)
.getValue();
if (!savedViewFiltersByKey) { if (!savedViewFiltersByKey) {
return; return;
} }
const onViewFiltersChange = snapshot
.getLoadable(onViewFiltersChangeScopedState({ scopeId: viewScopeId }))
.getValue();
const existingSavedFilterId = const existingSavedFilterId =
savedViewFiltersByKey[filterToUpsert.fieldId]?.id; savedViewFiltersByKey[filterToUpsert.fieldId]?.id;
setCurrentViewFilters?.((filters) => { set(currentViewFiltersState, (filters) => {
const newViewFilters = produce(filters, (filtersDraft) => { const newViewFilters = produce(filters, (filtersDraft) => {
const existingFilterIndex = filtersDraft.findIndex( const existingFilterIndex = filtersDraft.findIndex(
(filter) => filter.fieldId === filterToUpsert.fieldId, (filter) => filter.fieldId === filterToUpsert.fieldId,
@ -211,38 +182,29 @@ export const useViewFilters = (viewScopeId: string) => {
return newViewFilters; return newViewFilters;
}); });
}, },
[currentViewFiltersState, viewScopeId],
); );
const removeViewFilter = useRecoilCallback( const removeViewFilter = useRecoilCallback(
({ snapshot }) => ({ snapshot, set }) =>
(fieldId: string) => { (fieldId: string) => {
const currentViewId = snapshot const { currentViewId, currentViewFilters, onViewFiltersChange } =
.getLoadable(currentViewIdScopedState({ scopeId: viewScopeId })) getViewScopedStateValuesFromSnapshot({
.getValue(); snapshot,
viewScopeId,
});
if (!currentViewId) { if (!currentViewId) {
return; return;
} }
const onViewFiltersChange = snapshot
.getLoadable(onViewFiltersChangeScopedState({ scopeId: viewScopeId }))
.getValue();
const currentViewFilters = snapshot
.getLoadable(
currentViewFiltersScopedFamilyState({
scopeId: viewScopeId,
familyKey: currentViewId,
}),
)
.getValue();
const newViewFilters = currentViewFilters.filter((filter) => { const newViewFilters = currentViewFilters.filter((filter) => {
return filter.fieldId !== fieldId; return filter.fieldId !== fieldId;
}); });
setCurrentViewFilters?.(newViewFilters); set(currentViewFiltersState, newViewFilters);
onViewFiltersChange?.(newViewFilters); onViewFiltersChange?.(newViewFilters);
}, },
[currentViewFiltersState, viewScopeId],
); );
return { persistViewFilters, removeViewFilter, upsertViewFilter }; return { persistViewFilters, removeViewFilter, upsertViewFilter };

View File

@ -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,
};
};

View File

@ -4,14 +4,11 @@ import { useRecoilCallback } from 'recoil';
import { useFindOneObjectMetadataItem } from '@/metadata/hooks/useFindOneObjectMetadataItem'; import { useFindOneObjectMetadataItem } from '@/metadata/hooks/useFindOneObjectMetadataItem';
import { Sort } from '@/ui/object/object-sort-dropdown/types/Sort'; 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 { savedViewSortsScopedFamilyState } from '@/views/states/savedViewSortsScopedFamilyState';
import { savedViewSortsByKeyScopedFamilySelector } from '@/views/states/selectors/savedViewSortsByKeyScopedFamilySelector';
import { ViewSort } from '@/views/types/ViewSort'; 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) => { export const useViewSorts = (viewScopeId: string) => {
const { const {
@ -23,18 +20,29 @@ export const useViewSorts = (viewScopeId: string) => {
objectNameSingular: 'viewSortV2', objectNameSingular: 'viewSortV2',
}); });
const apolloClient = useApolloClient(); const apolloClient = useApolloClient();
const { setCurrentViewSorts } = useViewSetStates(viewScopeId);
const { currentViewSortsState } = useViewScopedStates();
const persistViewSorts = useRecoilCallback( const persistViewSorts = useRecoilCallback(
({ snapshot, set }) => ({ snapshot, set }) =>
async (viewId?: string) => { async (viewId?: string) => {
const currentViewId = snapshot const { currentViewId, currentViewSorts, savedViewSortsByKey } =
.getLoadable(currentViewIdScopedState({ scopeId: viewScopeId })) getViewScopedStateValuesFromSnapshot({
.getValue(); snapshot,
viewScopeId,
});
if (!currentViewId) { if (!currentViewId) {
return; return;
} }
if (!currentViewSorts) {
return;
}
if (!savedViewSortsByKey) {
return;
}
const createViewSorts = (viewSortsToCreate: ViewSort[]) => { const createViewSorts = (viewSortsToCreate: ViewSort[]) => {
if (!viewSortsToCreate.length) return; 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( const sortsToCreate = currentViewSorts.filter(
(sort) => !savedViewSortsByKey[sort.fieldId], (sort) => !savedViewSortsByKey[sort.fieldId],
); );
@ -153,37 +136,26 @@ export const useViewSorts = (viewScopeId: string) => {
); );
const upsertViewSort = useRecoilCallback( const upsertViewSort = useRecoilCallback(
({ snapshot }) => ({ snapshot, set }) =>
(sortToUpsert: Sort) => { (sortToUpsert: Sort) => {
const currentViewId = snapshot const { currentViewId, onViewSortsChange, savedViewSortsByKey } =
.getLoadable(currentViewIdScopedState({ scopeId: viewScopeId })) getViewScopedStateValuesFromSnapshot({
.getValue(); snapshot,
viewScopeId,
});
if (!currentViewId) { if (!currentViewId) {
return; return;
} }
const savedViewSortsByKey = snapshot
.getLoadable(
savedViewSortsByKeyScopedFamilySelector({
scopeId: viewScopeId,
viewId: currentViewId,
}),
)
.getValue();
if (!savedViewSortsByKey) { if (!savedViewSortsByKey) {
return; return;
} }
const onViewSortsChange = snapshot
.getLoadable(onViewSortsChangeScopedState({ scopeId: viewScopeId }))
.getValue();
const existingSavedSortId = const existingSavedSortId =
savedViewSortsByKey[sortToUpsert.fieldId]?.id; savedViewSortsByKey[sortToUpsert.fieldId]?.id;
setCurrentViewSorts?.((sorts) => { set(currentViewSortsState, (sorts) => {
const newViewSorts = produce(sorts, (sortsDraft) => { const newViewSorts = produce(sorts, (sortsDraft) => {
const existingSortIndex = sortsDraft.findIndex( const existingSortIndex = sortsDraft.findIndex(
(sort) => sort.fieldId === sortToUpsert.fieldId, (sort) => sort.fieldId === sortToUpsert.fieldId,
@ -203,38 +175,29 @@ export const useViewSorts = (viewScopeId: string) => {
return newViewSorts; return newViewSorts;
}); });
}, },
[currentViewSortsState, viewScopeId],
); );
const removeViewSort = useRecoilCallback( const removeViewSort = useRecoilCallback(
({ snapshot }) => ({ snapshot, set }) =>
(fieldId: string) => { (fieldId: string) => {
const currentViewId = snapshot const { currentViewId, onViewSortsChange, currentViewSorts } =
.getLoadable(currentViewIdScopedState({ scopeId: viewScopeId })) getViewScopedStateValuesFromSnapshot({
.getValue(); snapshot,
viewScopeId,
});
if (!currentViewId) { if (!currentViewId) {
return; return;
} }
const onViewSortsChange = snapshot
.getLoadable(onViewSortsChangeScopedState({ scopeId: viewScopeId }))
.getValue();
const currentViewSorts = snapshot
.getLoadable(
currentViewSortsScopedFamilyState({
scopeId: viewScopeId,
familyKey: currentViewId,
}),
)
.getValue();
const newViewSorts = currentViewSorts.filter((filter) => { const newViewSorts = currentViewSorts.filter((filter) => {
return filter.fieldId !== fieldId; return filter.fieldId !== fieldId;
}); });
setCurrentViewSorts?.(newViewSorts); set(currentViewSortsState, newViewSorts);
onViewSortsChange?.(newViewSorts); onViewSortsChange?.(newViewSorts);
}, },
[currentViewSortsState, viewScopeId],
); );
return { persistViewSorts, upsertViewSort, removeViewSort }; return { persistViewSorts, upsertViewSort, removeViewSort };

View File

@ -2,9 +2,8 @@ import { useApolloClient } from '@apollo/client';
import { useRecoilCallback } from 'recoil'; import { useRecoilCallback } from 'recoil';
import { useFindOneObjectMetadataItem } from '@/metadata/hooks/useFindOneObjectMetadataItem'; 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 { View } from '@/views/types/View';
import { getViewScopedStateValuesFromSnapshot } from '@/views/utils/getViewScopedStateValuesFromSnapshot';
export const useViews = (scopeId: string) => { export const useViews = (scopeId: string) => {
const { const {
@ -20,13 +19,12 @@ export const useViews = (scopeId: string) => {
const createView = useRecoilCallback( const createView = useRecoilCallback(
({ snapshot }) => ({ snapshot }) =>
async (view: Pick<View, 'id' | 'name'>) => { async (view: Pick<View, 'id' | 'name'>) => {
const viewObjectId = await snapshot const { viewObjectId, viewType } = getViewScopedStateValuesFromSnapshot(
.getLoadable(viewObjectIdScopeState({ scopeId })) {
.getValue(); snapshot,
viewScopeId: scopeId,
const viewType = await snapshot },
.getLoadable(viewTypeScopedState({ scopeId })) );
.getValue();
if (!viewObjectId || !viewType) { if (!viewObjectId || !viewType) {
return; return;
@ -43,6 +41,7 @@ export const useViews = (scopeId: string) => {
refetchQueries: [findManyQuery], refetchQueries: [findManyQuery],
}); });
}, },
[scopeId, apolloClient, createOneMutation, findManyQuery],
); );
const updateView = async (view: View) => { const updateView = async (view: View) => {

View File

@ -1,6 +1,6 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
import { useRecoilCallback } from 'recoil'; import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil';
import { v4 } from 'uuid'; import { v4 } from 'uuid';
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; 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 { ViewScopeInternalContext } from '../scopes/scope-internal-context/ViewScopeInternalContext';
import { currentViewFieldsScopedFamilyState } from '../states/currentViewFieldsScopedFamilyState'; import { currentViewFieldsScopedFamilyState } from '../states/currentViewFieldsScopedFamilyState';
import { currentViewFiltersScopedFamilyState } from '../states/currentViewFiltersScopedFamilyState'; import { currentViewFiltersScopedFamilyState } from '../states/currentViewFiltersScopedFamilyState';
import { currentViewIdScopedState } from '../states/currentViewIdScopedState';
import { currentViewSortsScopedFamilyState } from '../states/currentViewSortsScopedFamilyState'; import { currentViewSortsScopedFamilyState } from '../states/currentViewSortsScopedFamilyState';
import { onViewFieldsChangeScopedState } from '../states/onViewFieldsChangeScopedState'; import { getViewScopedStatesFromSnapshot } from '../utils/getViewScopedStatesFromSnapshot';
import { onViewFiltersChangeScopedState } from '../states/onViewFiltersChangeScopedState'; import { getViewScopedStateValuesFromSnapshot } from '../utils/getViewScopedStateValuesFromSnapshot';
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 { useViewFields } from './internal/useViewFields'; import { useViewFields } from './internal/useViewFields';
import { useViewFilters } from './internal/useViewFilters'; import { useViewFilters } from './internal/useViewFilters';
import { useViews } from './internal/useViews'; import { useViews } from './internal/useViews';
import { useViewScopedStates } from './internal/useViewScopedStates';
import { useViewSorts } from './internal/useViewSorts'; import { useViewSorts } from './internal/useViewSorts';
import { useViewSetStates } from './useViewSetStates';
type UseViewProps = { type UseViewProps = {
viewScopeId?: string; viewScopeId?: string;
@ -36,32 +29,19 @@ export const useView = (props?: UseViewProps) => {
); );
const { const {
setCurrentViewId, currentViewFiltersState,
currentViewId, currentViewIdState,
currentViewSortsState,
setViews, viewEditModeState,
setViewEditMode, availableFieldDefinitionsState,
setViewObjectId, availableFilterDefinitionsState,
setViewType, availableSortDefinitionsState,
setEntityCountInCurrentView, entityCountInCurrentViewState,
setIsViewBarExpanded, viewObjectIdState,
viewTypeState,
setAvailableSortDefinitions, } = useViewScopedStates({
setCurrentViewSorts, customViewScopeId: scopeId,
setSavedViewSorts, });
setAvailableFilterDefinitions,
setCurrentViewFilters,
setSavedViewFilters,
setAvailableFieldDefinitions,
setCurrentViewFields,
setSavedViewFields,
setOnViewFieldsChange,
setOnViewFiltersChange,
setOnViewSortsChange,
} = useViewSetStates(scopeId);
const { persistViewSorts, upsertViewSort, removeViewSort } = const { persistViewSorts, upsertViewSort, removeViewSort } =
useViewSorts(scopeId); useViewSorts(scopeId);
@ -73,6 +53,28 @@ export const useView = (props?: UseViewProps) => {
updateView: internalUpdateView, updateView: internalUpdateView,
deleteView: internalDeleteView, deleteView: internalDeleteView,
} = useViews(scopeId); } = 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 [_, setSearchParams] = useSearchParams();
const changeViewInUrl = useCallback( const changeViewInUrl = useCallback(
@ -82,72 +84,62 @@ export const useView = (props?: UseViewProps) => {
[setSearchParams], [setSearchParams],
); );
const loadView = useRecoilCallback(({ snapshot }) => (viewId: string) => { const loadView = useRecoilCallback(
setCurrentViewId?.(viewId); ({ snapshot }) =>
const currentViewFields = snapshot (viewId: string) => {
.getLoadable( setCurrentViewId?.(viewId);
currentViewFieldsScopedFamilyState({ scopeId, familyKey: viewId }),
)
.getValue();
const onViewFieldsChange = snapshot const {
.getLoadable(onViewFieldsChangeScopedState({ scopeId })) currentViewFields,
.getValue(); onViewFieldsChange,
currentViewFilters,
onViewFiltersChange,
currentViewSorts,
onViewSortsChange,
} = getViewScopedStateValuesFromSnapshot({
snapshot,
viewScopeId: scopeId,
viewId,
});
onViewFieldsChange?.(currentViewFields); onViewFieldsChange?.(currentViewFields);
onViewFiltersChange?.(currentViewFilters);
onViewSortsChange?.(currentViewSorts);
},
[setCurrentViewId, scopeId],
);
const currentViewFilters = snapshot const resetViewBar = useRecoilCallback(
.getLoadable( ({ snapshot, set }) =>
currentViewFiltersScopedFamilyState({ scopeId, familyKey: viewId }), () => {
) const {
.getValue(); savedViewFilters,
savedViewSorts,
onViewFiltersChange,
onViewSortsChange,
} = getViewScopedStateValuesFromSnapshot({
snapshot,
viewScopeId: scopeId,
});
const onViewFiltersChange = snapshot if (savedViewFilters) {
.getLoadable(onViewFiltersChangeScopedState({ scopeId })) set(currentViewFiltersState, savedViewFilters);
.getValue(); onViewFiltersChange?.(savedViewFilters);
}
if (savedViewSorts) {
set(currentViewSortsState, savedViewSorts);
onViewSortsChange?.(savedViewSorts);
}
onViewFiltersChange?.(currentViewFilters); set(viewEditModeState, 'none');
},
const currentViewSorts = snapshot [
.getLoadable( currentViewFiltersState,
currentViewSortsScopedFamilyState({ scopeId, familyKey: viewId }), currentViewSortsState,
) scopeId,
.getValue(); viewEditModeState,
],
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');
});
const createView = useRecoilCallback( const createView = useRecoilCallback(
({ snapshot, set }) => ({ snapshot, set }) =>
@ -155,29 +147,17 @@ export const useView = (props?: UseViewProps) => {
const newViewId = v4(); const newViewId = v4();
await internalCreateView({ id: newViewId, name }); await internalCreateView({ id: newViewId, name });
const currentViewFields = snapshot const { currentViewFields, currentViewFilters, currentViewSorts } =
.getLoadable( getViewScopedStateValuesFromSnapshot({
currentViewFieldsScopedFamilyState({ snapshot,
scopeId, viewScopeId: scopeId,
familyKey: currentViewId || '', });
}),
)
.getValue();
set( set(
currentViewFieldsScopedFamilyState({ scopeId, familyKey: newViewId }), currentViewFieldsScopedFamilyState({ scopeId, familyKey: newViewId }),
currentViewFields, currentViewFields,
); );
const currentViewFilters = snapshot
.getLoadable(
currentViewFiltersScopedFamilyState({
scopeId,
familyKey: currentViewId || '',
}),
)
.getValue();
set( set(
currentViewFiltersScopedFamilyState({ currentViewFiltersScopedFamilyState({
scopeId, scopeId,
@ -186,15 +166,6 @@ export const useView = (props?: UseViewProps) => {
currentViewFilters, currentViewFilters,
); );
const currentViewSorts = snapshot
.getLoadable(
currentViewSortsScopedFamilyState({
scopeId,
familyKey: currentViewId || '',
}),
)
.getValue();
set( set(
currentViewSortsScopedFamilyState({ currentViewSortsScopedFamilyState({
scopeId, scopeId,
@ -211,7 +182,6 @@ export const useView = (props?: UseViewProps) => {
}, },
[ [
changeViewInUrl, changeViewInUrl,
currentViewId,
internalCreateView, internalCreateView,
persistViewFields, persistViewFields,
persistViewFilters, persistViewFilters,
@ -228,19 +198,30 @@ export const useView = (props?: UseViewProps) => {
const removeView = useRecoilCallback( const removeView = useRecoilCallback(
({ set, snapshot }) => ({ set, snapshot }) =>
async (viewIdToDelete: string) => { async (viewIdToDelete: string) => {
const currentViewId = await snapshot.getPromise( const { currentViewId } = getViewScopedStateValuesFromSnapshot({
currentViewIdScopedState({ scopeId }), snapshot,
); viewScopeId: scopeId,
});
if (currentViewId === viewIdToDelete) const { currentViewIdState, viewsState } =
set(currentViewIdScopedState({ scopeId }), undefined); getViewScopedStatesFromSnapshot({
snapshot,
viewScopeId: scopeId,
});
set(viewsScopedState({ scopeId }), (previousViews) => if (currentViewId === viewIdToDelete) {
set(currentViewIdState, undefined);
}
set(viewsState, (previousViews) =>
previousViews.filter((view) => view.id !== viewIdToDelete), previousViews.filter((view) => view.id !== viewIdToDelete),
); );
internalDeleteView(viewIdToDelete); internalDeleteView(viewIdToDelete);
if (currentViewId === viewIdToDelete) setSearchParams(); if (currentViewId === viewIdToDelete) {
setSearchParams();
}
}, },
[internalDeleteView, scopeId, setSearchParams], [internalDeleteView, scopeId, setSearchParams],
); );
@ -252,13 +233,11 @@ export const useView = (props?: UseViewProps) => {
return; return;
} }
const viewEditMode = snapshot const { viewEditMode, currentView } =
.getLoadable(viewEditModeScopedState({ scopeId })) getViewScopedStateValuesFromSnapshot({
.getValue(); snapshot,
viewScopeId: scopeId,
const currentView = snapshot });
.getLoadable(currentViewScopedSelector(scopeId))
.getValue();
if (!currentView) { if (!currentView) {
return; return;
@ -284,38 +263,25 @@ export const useView = (props?: UseViewProps) => {
updateCurrentView, updateCurrentView,
createView, createView,
removeView, removeView,
setIsViewBarExpanded,
resetViewBar, resetViewBar,
handleViewNameSubmit, handleViewNameSubmit,
setViews,
setViewEditMode, setViewEditMode,
setViewObjectId, setViewObjectId,
setViewType, setViewType,
setEntityCountInCurrentView, setEntityCountInCurrentView,
setAvailableFieldDefinitions,
setAvailableSortDefinitions, setAvailableSortDefinitions,
setCurrentViewSorts,
setSavedViewSorts,
upsertViewSort, upsertViewSort,
removeViewSort, removeViewSort,
setAvailableFilterDefinitions, setAvailableFilterDefinitions,
setCurrentViewFilters,
setSavedViewFilters,
upsertViewFilter, upsertViewFilter,
removeViewFilter, removeViewFilter,
setAvailableFieldDefinitions,
setCurrentViewFields,
setSavedViewFields,
persistViewFields, persistViewFields,
changeViewInUrl, changeViewInUrl,
loadView, loadView,
setOnViewFieldsChange,
setOnViewFiltersChange,
setOnViewSortsChange,
}; };
}; };

View File

@ -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,
};
};

View File

@ -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,
};
};

View File

@ -1,8 +1,9 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useSetRecoilState } from 'recoil';
import { Filter } from '@/ui/object/object-filter-dropdown/types/Filter'; import { Filter } from '@/ui/object/object-filter-dropdown/types/Filter';
import { Sort } from '@/ui/object/object-sort-dropdown/types/Sort'; 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'; import { ViewField } from '@/views/types/ViewField';
type ViewScopeInitEffectProps = { type ViewScopeInitEffectProps = {
@ -18,10 +19,14 @@ export const ViewScopeInitEffect = ({
onViewFieldsChange, onViewFieldsChange,
}: ViewScopeInitEffectProps) => { }: ViewScopeInitEffectProps) => {
const { const {
setOnViewSortsChange, onViewFieldsChangeState,
setOnViewFieldsChange, onViewFiltersChangeState,
setOnViewFiltersChange, onViewSortsChangeState,
} = useView(); } = useViewScopedStates();
const setOnViewSortsChange = useSetRecoilState(onViewSortsChangeState);
const setOnViewFiltersChange = useSetRecoilState(onViewFiltersChangeState);
const setOnViewFieldsChange = useSetRecoilState(onViewFieldsChangeState);
useEffect(() => { useEffect(() => {
setOnViewSortsChange(() => onViewSortsChange); setOnViewSortsChange(() => onViewSortsChange);

View File

@ -1,22 +1,23 @@
import { selectorFamily } from 'recoil'; import { createScopedSelector } from '@/ui/utilities/recoil-scope/utils/createScopedSelector';
import { View } from '@/views/types/View'; import { View } from '@/views/types/View';
import { currentViewIdScopedState } from '../currentViewIdScopedState'; import { currentViewIdScopedState } from '../currentViewIdScopedState';
import { viewsByIdScopedSelector } from './viewsByIdScopedSelector'; import { viewsByIdScopedSelector } from './viewsByIdScopedSelector';
export const currentViewScopedSelector = selectorFamily< export const currentViewScopedSelector = createScopedSelector<View | undefined>(
View | undefined, {
string key: 'currentViewScopedSelector',
>({ get:
key: 'currentViewScopedSelector', ({ scopeId }: { scopeId: string }) =>
get: ({ get }) => {
(scopeId) => const currentViewId = get(
({ get }) => { currentViewIdScopedState({ scopeId: scopeId }),
const currentViewId = get(currentViewIdScopedState({ scopeId: scopeId })); );
return currentViewId
? get(viewsByIdScopedSelector(scopeId))[currentViewId] return currentViewId
: undefined; ? get(viewsByIdScopedSelector(scopeId))[currentViewId]
}, : undefined;
}); },
},
);

View File

@ -18,6 +18,7 @@ export const savedViewFieldByKeyScopedFamilySelector = selectorFamily({
if (viewId === undefined) { if (viewId === undefined) {
return undefined; return undefined;
} }
return get( return get(
savedViewFieldsScopedFamilyState({ savedViewFieldsScopedFamilyState({
scopeId: viewScopeId, scopeId: viewScopeId,

View File

@ -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),
};
};

View File

@ -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,
};
};

View File

@ -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,
};
};

View File

@ -3,7 +3,7 @@ import { ColumnDefinition } from '@/ui/object/record-table/types/ColumnDefinitio
import { ViewField } from '../types/ViewField'; import { ViewField } from '../types/ViewField';
export const columnDefinitionsToViewFields = ( export const mapColumnDefinitionsToViewFields = (
columnDefinitions: ColumnDefinition<FieldMetadata>[], columnDefinitions: ColumnDefinition<FieldMetadata>[],
): ViewField[] => { ): ViewField[] => {
return columnDefinitions.map((columnDefinition) => ({ return columnDefinitions.map((columnDefinition) => ({

View File

@ -4,7 +4,7 @@ import { assertNotNull } from '~/utils/assert';
import { ViewField } from '../types/ViewField'; import { ViewField } from '../types/ViewField';
export const viewFieldsToBoardFieldDefinitions = ( export const mapViewFieldsToBoardFieldDefinitions = (
viewFields: ViewField[], viewFields: ViewField[],
fieldsMetadata: BoardFieldDefinition<FieldMetadata>[], fieldsMetadata: BoardFieldDefinition<FieldMetadata>[],
): BoardFieldDefinition<FieldMetadata>[] => { ): BoardFieldDefinition<FieldMetadata>[] => {

View File

@ -4,7 +4,7 @@ import { assertNotNull } from '~/utils/assert';
import { ViewField } from '../types/ViewField'; import { ViewField } from '../types/ViewField';
export const viewFieldsToColumnDefinitions = ( export const mapViewFieldsToColumnDefinitions = (
viewFields: ViewField[], viewFields: ViewField[],
fieldsMetadata: ColumnDefinition<FieldMetadata>[], fieldsMetadata: ColumnDefinition<FieldMetadata>[],
): ColumnDefinition<FieldMetadata>[] => { ): ColumnDefinition<FieldMetadata>[] => {

View File

@ -2,7 +2,9 @@ import { Filter } from '@/ui/object/object-filter-dropdown/types/Filter';
import { ViewFilter } from '../types/ViewFilter'; import { ViewFilter } from '../types/ViewFilter';
export const viewFiltersToFilters = (viewFilters: ViewFilter[]): Filter[] => { export const mapViewFiltersToFilters = (
viewFilters: ViewFilter[],
): Filter[] => {
return viewFilters.map((viewFilter) => { return viewFilters.map((viewFilter) => {
return { return {
fieldId: viewFilter.fieldId, fieldId: viewFilter.fieldId,

View File

@ -2,7 +2,7 @@ import { Sort } from '@/ui/object/object-sort-dropdown/types/Sort';
import { ViewSort } from '../types/ViewSort'; import { ViewSort } from '../types/ViewSort';
export const viewSortsToSorts = (viewSorts: ViewSort[]): Sort[] => { export const mapViewSortsToSorts = (viewSorts: ViewSort[]): Sort[] => {
return viewSorts.map((viewSort) => { return viewSorts.map((viewSort) => {
return { return {
fieldId: viewSort.fieldId, fieldId: viewSort.fieldId,

View File

@ -38,7 +38,7 @@ export const Email: Story = {
await canvas.findByText( await canvas.findByText(
mockedPeopleData[0].displayName, mockedPeopleData[0].displayName,
{}, {},
{ timeout: 3000 }, { timeout: 1000 },
); );
}); });
@ -82,7 +82,7 @@ export const Reset: Story = {
await canvas.findByText( await canvas.findByText(
mockedPeopleData[0].displayName, mockedPeopleData[0].displayName,
{}, {},
{ timeout: 3000 }, { timeout: 1000 },
); );
}); });