Complete Fix view work (#2272)

* Fix views

* Make view sorts and view filters functional

* Complete Company table view fix

* Fix model creation

* Start fixing board

* Complete work
This commit is contained in:
Charles Bochet
2023-10-29 16:29:00 +01:00
committed by GitHub
parent 685d342170
commit 9bab28912d
118 changed files with 1806 additions and 1413 deletions

View File

@ -10,7 +10,7 @@ import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useView } from '@/views/hooks/useView';
import { useViewInternalStates } from '../hooks/useViewInternalStates';
import { useViewGetStates } from '../hooks/useViewGetStates';
const StyledContainer = styled.div`
display: inline-flex;
@ -28,7 +28,7 @@ export const UpdateViewButtonGroup = ({
}: UpdateViewButtonGroupProps) => {
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const { updateCurrentView, setViewEditMode } = useView();
const { canPersistFilters, canPersistSorts } = useViewInternalStates();
const { canPersistFilters, canPersistSorts } = useViewGetStates();
const canPersistView = canPersistFilters || canPersistSorts;

View File

@ -9,7 +9,7 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { TopBar } from '@/ui/layout/top-bar/TopBar';
import { useView } from '../hooks/useView';
import { useViewInternalStates } from '../hooks/useViewInternalStates';
import { useViewGetStates } from '../hooks/useViewGetStates';
import { ViewsHotkeyScope } from '../types/ViewsHotkeyScope';
import { UpdateViewButtonGroup } from './UpdateViewButtonGroup';
@ -31,18 +31,20 @@ export const ViewBar = ({
const { openDropdown: openOptionsDropdownButton } = useDropdown({
dropdownScopeId: optionsDropdownScopeId,
});
const { upsertViewSort } = useView();
const { availableFilters, availableSorts } = useViewInternalStates();
const { upsertViewSort, upsertViewFilter } = useView();
const { availableFilterDefinitions, availableSortDefinitions } =
useViewGetStates();
return (
<FilterScope
filterScopeId="view-filter"
availableFilters={availableFilters}
availableFilterDefinitions={availableFilterDefinitions}
onFilterSelect={upsertViewFilter}
>
<SortScope
sortScopeId="view-sort"
availableSorts={availableSorts}
onSortAdd={upsertViewSort}
availableSortDefinitions={availableSortDefinitions}
onSortSelect={upsertViewSort}
>
<ViewBarEffect />
<TopBar
@ -51,6 +53,7 @@ export const ViewBar = ({
<ViewsDropdownButton
onViewEditModeChange={openOptionsDropdownButton}
hotkeyScope={{ scope: ViewsHotkeyScope.ListDropdown }}
optionsDropdownScopeId={optionsDropdownScopeId}
/>
}
displayBottomBorder={false}

View File

@ -5,9 +5,8 @@ import { AddFilterFromDropdownButton } from '@/ui/data/filter/components/AddFilt
import { getOperandLabelShort } from '@/ui/data/filter/utils/getOperandLabel';
import { IconArrowDown, IconArrowUp } from '@/ui/display/icon/index';
import { useRemoveFilter } from '../hooks/useRemoveFilter';
import { useView } from '../hooks/useView';
import { useViewInternalStates } from '../hooks/useViewInternalStates';
import { useViewGetStates } from '../hooks/useViewGetStates';
import SortOrFilterChip from './SortOrFilterChip';
@ -90,43 +89,23 @@ export const ViewBarDetails = ({
}: ViewBarDetailsProps) => {
const {
currentViewSorts,
setCurrentViewSorts,
availableFilters,
currentViewFilters,
canPersistFilters,
canPersistSorts,
isViewBarExpanded,
} = useViewInternalStates();
} = useViewGetStates();
const { resetViewBar } = useView();
const { resetViewBar, removeViewSort, removeViewFilter } = useView();
const canPersistView = canPersistFilters || canPersistSorts;
const filtersWithDefinition = currentViewFilters?.map((filter) => {
const filterDefinition = availableFilters.find((availableFilter) => {
return availableFilter.key === filter.key;
});
return {
...filter,
...filterDefinition,
};
});
const removeFilter = useRemoveFilter();
const handleCancelClick = () => {
resetViewBar();
};
const handleSortRemove = (sortKey: string) =>
setCurrentViewSorts?.((previousSorts) =>
previousSorts.filter((sort) => sort.key !== sortKey),
);
const shouldExpandViewBar =
canPersistView ||
((filtersWithDefinition?.length || currentViewSorts?.length) &&
((currentViewSorts?.length || currentViewFilters?.length) &&
isViewBarExpanded);
if (!shouldExpandViewBar) {
@ -140,32 +119,32 @@ export const ViewBarDetails = ({
{currentViewSorts?.map((sort) => {
return (
<SortOrFilterChip
key={sort.key}
testId={sort.key}
key={sort.fieldId}
testId={sort.fieldId}
labelValue={sort.definition.label}
Icon={sort.direction === 'desc' ? IconArrowDown : IconArrowUp}
isSort
onRemove={() => handleSortRemove(sort.key)}
onRemove={() => removeViewSort(sort.fieldId)}
/>
);
})}
{!!currentViewSorts?.length && !!filtersWithDefinition?.length && (
{!!currentViewSorts?.length && !!currentViewFilters?.length && (
<StyledSeperatorContainer>
<StyledSeperator />
</StyledSeperatorContainer>
)}
{filtersWithDefinition?.map((filter) => {
{currentViewFilters?.map((filter) => {
return (
<SortOrFilterChip
key={filter.key}
testId={filter.key}
labelKey={filter.label}
key={filter.fieldId}
testId={filter.fieldId}
labelKey={filter.definition.label}
labelValue={`${getOperandLabelShort(filter.operand)} ${
filter.displayValue
}`}
Icon={filter.Icon}
Icon={filter.definition.Icon}
onRemove={() => {
removeFilter(filter.key);
removeViewFilter(filter.fieldId);
}}
/>
);

View File

@ -8,28 +8,65 @@ import { assertNotNull } from '~/utils/assert';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
import { useView } from '../hooks/useView';
import { useViewInternalStates } from '../hooks/useViewInternalStates';
import { availableFieldsScopedState } from '../states/availableFieldsScopedState';
import { useViewGetStates } from '../hooks/useViewGetStates';
import { availableFieldDefinitionsScopedState } from '../states/availableFieldDefinitionsScopedState';
import { availableFilterDefinitionsScopedState } from '../states/availableFilterDefinitionsScopedState';
import { availableSortDefinitionsScopedState } from '../states/availableSortDefinitionsScopedState';
import { onViewFieldsChangeScopedState } from '../states/onViewFieldsChangeScopedState';
import { onViewFiltersChangeScopedState } from '../states/onViewFiltersChangeScopedState';
import { onViewSortsChangeScopedState } from '../states/onViewSortsChangeScopedState';
import { savedViewFieldsScopedFamilyState } from '../states/savedViewFieldsScopedFamilyState';
import { savedViewFiltersScopedFamilyState } from '../states/savedViewFiltersScopedFamilyState';
import { savedViewSortsScopedFamilyState } from '../states/savedViewSortsScopedFamilyState';
import { viewsScopedState } from '../states/viewsScopedState';
import { View } from '../types/View';
import { ViewField } from '../types/ViewField';
import { ViewFilter } from '../types/ViewFilter';
import { ViewSort } from '../types/ViewSort';
export const ViewBarEffect = () => {
const {
scopeId: viewScopeId,
setCurrentViewFields,
setSavedViewFields,
setCurrentViewFilters,
setSavedViewFilters,
setCurrentViewSorts,
setSavedViewSorts,
currentViewId,
setViews,
changeView,
loadView,
changeViewInUrl,
setCurrentViewId,
} = useView();
const [searchParams] = useSearchParams();
const { viewType, viewObjectId } = useViewInternalStates(viewScopeId);
const { viewType, viewObjectId } = useViewGetStates(viewScopeId);
useFindManyObjects({
objectNamePlural: 'viewsV2',
filter: { type: { eq: viewType }, objectId: { eq: viewObjectId } },
onCompleted: useRecoilCallback(
({ snapshot }) =>
async (data: PaginatedObjectTypeResults<View>) => {
const nextViews = data.edges.map((view) => ({
id: view.node.id,
name: view.node.name,
objectId: view.node.objectId,
}));
const views = snapshot
.getLoadable(viewsScopedState({ scopeId: viewScopeId }))
.getValue();
if (!isDeeplyEqual(views, nextViews)) setViews(nextViews);
if (!nextViews.length) return;
if (!currentViewId) return changeViewInUrl(nextViews[0].id);
},
),
});
useFindManyObjects({
objectNamePlural: 'viewFieldsV2',
@ -38,7 +75,9 @@ export const ViewBarEffect = () => {
({ snapshot }) =>
async (data: PaginatedObjectTypeResults<ViewField>) => {
const availableFields = snapshot
.getLoadable(availableFieldsScopedState({ scopeId: viewScopeId }))
.getLoadable(
availableFieldDefinitionsScopedState({ scopeId: viewScopeId }),
)
.getValue();
const onViewFieldsChange = snapshot
@ -74,133 +113,122 @@ export const ViewBarEffect = () => {
});
useFindManyObjects({
objectNamePlural: 'viewsV2',
filter: { type: { eq: viewType }, objectId: { eq: viewObjectId } },
objectNamePlural: 'viewFiltersV2',
filter: { viewId: { eq: currentViewId } },
onCompleted: useRecoilCallback(
({ snapshot }) =>
async (data: PaginatedObjectTypeResults<View>) => {
const nextViews = data.edges.map((view) => ({
id: view.node.id,
name: view.node.name,
objectId: view.node.objectId,
}));
const views = snapshot
.getLoadable(viewsScopedState({ scopeId: viewScopeId }))
async (data: PaginatedObjectTypeResults<Required<ViewFilter>>) => {
const availableFilterDefinitions = snapshot
.getLoadable(
availableFilterDefinitionsScopedState({ scopeId: viewScopeId }),
)
.getValue();
if (!isDeeplyEqual(views, nextViews)) setViews(nextViews);
if (!availableFilterDefinitions || !currentViewId) {
return;
}
if (!nextViews.length) return;
const savedViewFilters = snapshot
.getLoadable(
savedViewFiltersScopedFamilyState({
scopeId: viewScopeId,
familyKey: currentViewId,
}),
)
.getValue();
if (!currentViewId) return changeView(nextViews[0].id);
const onViewFiltersChange = snapshot
.getLoadable(
onViewFiltersChangeScopedState({ scopeId: viewScopeId }),
)
.getValue();
const queriedViewFilters = data.edges
.map(({ node }) => {
const availableFilterDefinition = availableFilterDefinitions.find(
(filterDefinition) => filterDefinition.fieldId === node.fieldId,
);
if (!availableFilterDefinition) return null;
return {
...node,
displayValue: node.displayValue ?? node.value,
definition: availableFilterDefinition,
};
})
.filter(assertNotNull);
if (!isDeeplyEqual(savedViewFilters, queriedViewFilters)) {
setSavedViewFilters?.(queriedViewFilters);
setCurrentViewFilters?.(queriedViewFilters);
onViewFiltersChange?.(queriedViewFilters);
}
},
),
});
// useGetViewSortsQuery({
// skip: !currentViewId,
// variables: {
// where: {
// viewId: { equals: currentViewId },
// },
// },
// onCompleted: useRecoilCallback(({ snapshot }) => async (data) => {
// const availableSorts = snapshot
// .getLoadable(availableSortsScopedState({ scopeId: viewScopeId }))
// .getValue();
useFindManyObjects({
objectNamePlural: 'viewSortsV2',
filter: { viewId: { eq: currentViewId } },
onCompleted: useRecoilCallback(
({ snapshot }) =>
async (data: PaginatedObjectTypeResults<Required<ViewSort>>) => {
const availableSortDefinitions = snapshot
.getLoadable(
availableSortDefinitionsScopedState({ scopeId: viewScopeId }),
)
.getValue();
// if (!availableSorts || !currentViewId) {
// return;
// }
if (!availableSortDefinitions || !currentViewId) {
return;
}
// const savedViewSorts = snapshot
// .getLoadable(
// savedViewSortsScopedFamilyState({
// scopeId: viewScopeId,
// familyKey: currentViewId,
// }),
// )
// .getValue();
const savedViewSorts = snapshot
.getLoadable(
savedViewSortsScopedFamilyState({
scopeId: viewScopeId,
familyKey: currentViewId,
}),
)
.getValue();
// const queriedViewSorts = data.viewSorts
// .map((viewSort) => {
// const foundCorrespondingSortDefinition = availableSorts.find(
// (sort) => sort.key === viewSort.key,
// );
const onViewSortsChange = snapshot
.getLoadable(onViewSortsChangeScopedState({ scopeId: viewScopeId }))
.getValue();
// if (foundCorrespondingSortDefinition) {
// return {
// key: viewSort.key,
// definition: foundCorrespondingSortDefinition,
// direction: viewSort.direction.toLowerCase(),
// } as Sort;
// } else {
// return undefined;
// }
// })
// .filter((sort): sort is Sort => !!sort);
const queriedViewSorts = data.edges
.map(({ node }) => {
const availableSortDefinition = availableSortDefinitions.find(
(sort) => sort.fieldId === node.fieldId,
);
// if (!isDeeplyEqual(savedViewSorts, queriedViewSorts)) {
// setSavedViewSorts?.(queriedViewSorts);
// setCurrentViewSorts?.(queriedViewSorts);
// }
// }),
// });
if (!availableSortDefinition) return null;
// useGetViewFiltersQuery({
// skip: !currentViewId,
// variables: {
// where: {
// viewId: { equals: currentViewId },
// },
// },
// onCompleted: useRecoilCallback(({ snapshot }) => (data) => {
// const availableFilters = snapshot
// .getLoadable(availableFiltersScopedState({ scopeId: viewScopeId }))
// .getValue();
return {
id: node.id,
fieldId: node.fieldId,
direction: node.direction,
definition: availableSortDefinition,
};
})
.filter(assertNotNull);
// if (!availableFilters || !currentViewId) {
// return;
// }
// const savedViewFilters = snapshot
// .getLoadable(
// savedViewFiltersScopedFamilyState({
// scopeId: viewScopeId,
// familyKey: currentViewId,
// }),
// )
// .getValue();
// const queriedViewFilters = data.viewFilters
// .map(({ __typename, name: _name, ...viewFilter }) => {
// const availableFilter = availableFilters.find(
// (filter) => filter.key === viewFilter.key,
// );
// return availableFilter
// ? {
// ...viewFilter,
// displayValue: viewFilter.displayValue ?? viewFilter.value,
// type: availableFilter.type,
// }
// : undefined;
// })
// .filter((filter): filter is Filter => !!filter);
// if (!isDeeplyEqual(savedViewFilters, queriedViewFilters)) {
// setSavedViewFilters?.(queriedViewFilters);
// setCurrentViewFilters?.(queriedViewFilters);
// }
// }),
// });
if (!isDeeplyEqual(savedViewSorts, queriedViewSorts)) {
setSavedViewSorts?.(queriedViewSorts);
setCurrentViewSorts?.(queriedViewSorts);
onViewSortsChange?.(queriedViewSorts);
}
},
),
});
const currentViewIdFromUrl = searchParams.get('view');
useEffect(() => {
if (!currentViewIdFromUrl) return;
setCurrentViewId(currentViewIdFromUrl);
}, [currentViewIdFromUrl, setCurrentViewId]);
loadView(currentViewIdFromUrl);
}, [currentViewIdFromUrl, loadView, setCurrentViewId]);
return <></>;
};

View File

@ -3,7 +3,6 @@ import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useRecoilCallback } from 'recoil';
import { TableOptionsDropdownId } from '@/ui/data/data-table/constants/TableOptionsDropdownId';
import {
IconChevronDown,
IconList,
@ -24,7 +23,7 @@ import { assertNotNull } from '~/utils/assert';
import { ViewsDropdownId } from '../constants/ViewsDropdownId';
import { useView } from '../hooks/useView';
import { useViewInternalStates } from '../hooks/useViewInternalStates';
import { useViewGetStates } from '../hooks/useViewGetStates';
const StyledBoldDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)`
font-weight: ${({ theme }) => theme.font.weight.regular};
@ -60,17 +59,22 @@ const StyledViewName = styled.span`
export type ViewsDropdownButtonProps = {
hotkeyScope: HotkeyScope;
onViewEditModeChange?: () => void;
optionsDropdownScopeId: string;
};
export const ViewsDropdownButton = ({
hotkeyScope,
onViewEditModeChange,
optionsDropdownScopeId,
}: ViewsDropdownButtonProps) => {
const theme = useTheme();
const { scopeId, removeView, currentViewId, changeView } = useView();
const { scopeId, removeView, currentViewId, changeViewInUrl } = useView();
const { views, currentView, setViewEditMode, entityCountInCurrentView } =
useViewInternalStates(scopeId, currentViewId);
const { views, currentView, entityCountInCurrentView } = useViewGetStates(
scopeId,
currentViewId,
);
const { setViewEditMode } = useView();
const {
isDropdownOpen: isViewsDropdownOpen,
@ -80,16 +84,16 @@ export const ViewsDropdownButton = ({
});
const { openDropdown: openOptionsDropdown } = useDropdown({
dropdownScopeId: TableOptionsDropdownId,
dropdownScopeId: optionsDropdownScopeId,
});
const handleViewSelect = useRecoilCallback(
() => async (viewId: string) => {
changeView(viewId);
changeViewInUrl(viewId);
closeViewsDropdown();
},
[changeView, closeViewsDropdown],
[changeViewInUrl, closeViewsDropdown],
);
const handleAddViewButtonClick = () => {
@ -104,7 +108,7 @@ export const ViewsDropdownButton = ({
viewId: string,
) => {
event.stopPropagation();
changeView(viewId);
changeViewInUrl(viewId);
setViewEditMode('edit');
onViewEditModeChange?.();
closeViewsDropdown();

View File

@ -8,9 +8,10 @@ import { viewObjectIdScopeState } from '@/views/states/viewObjectIdScopeState';
import { ViewField } from '@/views/types/ViewField';
export const useViewFields = (viewScopeId: string) => {
const { updateOneMutation, createOneMutation } = useFindOneMetadataObject({
objectNameSingular: 'viewFieldV2',
});
const { updateOneMutation, createOneMutation, findManyQuery } =
useFindOneMetadataObject({
objectNameSingular: 'viewFieldV2',
});
const apolloClient = useApolloClient();
const persistViewFields = useRecoilCallback(
@ -49,12 +50,13 @@ export const useViewFields = (viewScopeId: string) => {
variables: {
input: {
fieldId: viewField.fieldId,
viewId: currentViewId,
viewId: viewId,
isVisible: viewField.isVisible,
size: viewField.size,
position: viewField.position,
},
},
refetchQueries: [findManyQuery],
}),
),
);

View File

@ -1,14 +1,26 @@
import { useApolloClient } from '@apollo/client';
import { produce } from 'immer';
import { useRecoilCallback } from 'recoil';
import { useFindOneMetadataObject } from '@/metadata/hooks/useFindOneMetadataObject';
import { Filter } from '@/ui/data/filter/types/Filter';
import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition';
import { availableFiltersScopedState } from '@/views/states/availableFiltersScopedState';
import { currentViewFiltersScopedFamilyState } from '@/views/states/currentViewFiltersScopedFamilyState';
import { currentViewIdScopedState } from '@/views/states/currentViewIdScopedState';
import { onViewFiltersChangeScopedState } from '@/views/states/onViewFiltersChangeScopedState';
import { savedViewFiltersScopedFamilyState } from '@/views/states/savedViewFiltersScopedFamilyState';
import { savedViewFiltersByKeyScopedFamilySelector } from '@/views/states/selectors/savedViewFiltersByKeyScopedFamilySelector';
import { ViewFilter } from '@/views/types/ViewFilter';
import { useViewSetStates } from '../useViewSetStates';
export const useViewFilters = (viewScopeId: string) => {
const { updateOneMutation, createOneMutation, findManyQuery } =
useFindOneMetadataObject({
objectNameSingular: 'viewFilterV2',
});
const apolloClient = useApolloClient();
const { setCurrentViewFilters } = useViewSetStates(viewScopeId);
const persistViewFilters = useRecoilCallback(
({ snapshot, set }) =>
async (viewId?: string) => {
@ -19,69 +31,52 @@ export const useViewFilters = (viewScopeId: string) => {
return;
}
const _createViewFilters = (
filters: Filter[],
availableFilters: FilterDefinition[] = [],
) => {
if (!currentViewId || !filters.length) {
return;
}
const createViewFilters = (viewFiltersToCreate: ViewFilter[]) => {
if (!viewFiltersToCreate.length) return;
if (!availableFilters) {
return;
}
// return createViewFiltersMutation({
// variables: {
// data: filters.map((filter) => ({
// displayValue: filter.displayValue ?? filter.value,
// key: filter.key,
// name:
// availableFilters.find(({ key }) => key === filter.key)
// ?.label ?? '',
// operand: filter.operand,
// value: filter.value,
// viewId: viewId ?? currentViewId,
// })),
// },
// });
return Promise.all(
viewFiltersToCreate.map((viewFilter) =>
apolloClient.mutate({
mutation: createOneMutation,
variables: {
input: {
fieldId: viewFilter.fieldId,
viewId: viewId ?? currentViewId,
value: viewFilter.value,
displayValue: viewFilter.displayValue,
operand: viewFilter.operand,
},
},
refetchQueries: [findManyQuery],
}),
),
);
};
const _updateViewFilters = (filters: Filter[]) => {
if (!currentViewId || !filters.length) return;
const updateViewFilters = (viewFiltersToUpdate: ViewFilter[]) => {
if (!viewFiltersToUpdate.length) return;
// return Promise.all(
// filters.map((filter) =>
// updateViewFilterMutation({
// variables: {
// data: {
// displayValue: filter.displayValue ?? filter.value,
// operand: filter.operand,
// value: filter.value,
// },
// where: {
// viewId_key: {
// key: filter.key,
// viewId: viewId ?? currentViewId,
// },
// },
// },
// }),
// ),
// );
return Promise.all(
viewFiltersToUpdate.map((viewFilter) =>
apolloClient.mutate({
mutation: updateOneMutation,
variables: {
idToUpdate: viewFilter.id,
input: {
value: viewFilter.value,
displayValue: viewFilter.displayValue,
operand: viewFilter.operand,
},
},
}),
),
);
};
const _deleteViewFilters = (filterKeys: string[]) => {
if (!currentViewId || !filterKeys.length) return;
const deleteViewFilters = (viewFilterIdsToDelete: string[]) => {
if (!viewFilterIdsToDelete.length) return;
// return deleteViewFiltersMutation({
// variables: {
// where: {
// key: { in: filterKeys },
// viewId: { equals: viewId ?? currentViewId },
// },
// },
// });
// Todo
};
const currentViewFilters = snapshot
@ -97,7 +92,7 @@ export const useViewFilters = (viewScopeId: string) => {
.getLoadable(
savedViewFiltersByKeyScopedFamilySelector({
scopeId: viewScopeId,
viewId: currentViewId,
viewId: viewId ?? currentViewId,
}),
)
.getValue();
@ -109,32 +104,24 @@ export const useViewFilters = (viewScopeId: string) => {
return;
}
const availableFilters = snapshot
.getLoadable(
availableFiltersScopedState({
scopeId: viewScopeId,
}),
)
.getValue();
const filtersToCreate = currentViewFilters.filter(
(filter) => !savedViewFiltersByKey[filter.key],
(filter) => !savedViewFiltersByKey[filter.fieldId],
);
await _createViewFilters(filtersToCreate, availableFilters);
await createViewFilters(filtersToCreate);
const filtersToUpdate = currentViewFilters.filter(
(filter) =>
savedViewFiltersByKey[filter.key] &&
(savedViewFiltersByKey[filter.key].operand !== filter.operand ||
savedViewFiltersByKey[filter.key].value !== filter.value),
savedViewFiltersByKey[filter.fieldId] &&
(savedViewFiltersByKey[filter.fieldId].operand !== filter.operand ||
savedViewFiltersByKey[filter.fieldId].value !== filter.value),
);
await _updateViewFilters(filtersToUpdate);
await updateViewFilters(filtersToUpdate);
const filterKeys = currentViewFilters.map((filter) => filter.key);
const filterKeys = currentViewFilters.map((filter) => filter.fieldId);
const filterKeysToDelete = Object.keys(savedViewFiltersByKey).filter(
(previousFilterKey) => !filterKeys.includes(previousFilterKey),
);
await _deleteViewFilters(filterKeysToDelete);
await deleteViewFilters(filterKeysToDelete);
set(
savedViewFiltersScopedFamilyState({
scopeId: viewScopeId,
@ -143,8 +130,102 @@ export const useViewFilters = (viewScopeId: string) => {
currentViewFilters,
);
},
[viewScopeId],
[
apolloClient,
createOneMutation,
findManyQuery,
updateOneMutation,
viewScopeId,
],
);
return { persistViewFilters };
const upsertViewFilter = useRecoilCallback(
({ snapshot }) =>
(filterToUpsert: Filter) => {
const currentViewId = snapshot
.getLoadable(currentViewIdScopedState({ scopeId: viewScopeId }))
.getValue();
if (!currentViewId) {
return;
}
const savedViewFiltersByKey = snapshot
.getLoadable(
savedViewFiltersByKeyScopedFamilySelector({
scopeId: viewScopeId,
viewId: currentViewId,
}),
)
.getValue();
if (!savedViewFiltersByKey) {
return;
}
const onViewFiltersChange = snapshot
.getLoadable(onViewFiltersChangeScopedState({ scopeId: viewScopeId }))
.getValue();
const existingSavedFilterId =
savedViewFiltersByKey[filterToUpsert.fieldId]?.id;
setCurrentViewFilters?.((filters) => {
const newViewFilters = produce(filters, (filtersDraft) => {
const existingFilterIndex = filtersDraft.findIndex(
(filter) => filter.fieldId === filterToUpsert.fieldId,
);
if (existingFilterIndex === -1) {
filtersDraft.push({
...filterToUpsert,
id: existingSavedFilterId,
});
return filtersDraft;
}
filtersDraft[existingFilterIndex] = {
...filterToUpsert,
id: existingSavedFilterId,
};
});
onViewFiltersChange?.(newViewFilters);
return newViewFilters;
});
},
);
const removeViewFilter = useRecoilCallback(
({ snapshot }) =>
(fieldId: string) => {
const currentViewId = snapshot
.getLoadable(currentViewIdScopedState({ scopeId: viewScopeId }))
.getValue();
if (!currentViewId) {
return;
}
const onViewFiltersChange = snapshot
.getLoadable(onViewFiltersChangeScopedState({ scopeId: viewScopeId }))
.getValue();
const currentViewFilters = snapshot
.getLoadable(
currentViewFiltersScopedFamilyState({
scopeId: viewScopeId,
familyKey: currentViewId,
}),
)
.getValue();
const newViewFilters = currentViewFilters.filter((filter) => {
return filter.fieldId !== fieldId;
});
setCurrentViewFilters?.(newViewFilters);
onViewFiltersChange?.(newViewFilters);
},
);
return { persistViewFilters, removeViewFilter, upsertViewFilter };
};

View File

@ -1,16 +1,25 @@
import { useApolloClient } from '@apollo/client';
import { produce } from 'immer';
import { useRecoilCallback } from 'recoil';
import { useFindOneMetadataObject } from '@/metadata/hooks/useFindOneMetadataObject';
import { Sort } from '@/ui/data/sort/types/Sort';
import { currentViewIdScopedState } from '@/views/states/currentViewIdScopedState';
import { currentViewSortsScopedFamilyState } from '@/views/states/currentViewSortsScopedFamilyState';
import { onViewSortsChangeScopedState } from '@/views/states/onViewSortsChangeScopedState';
import { savedViewSortsScopedFamilyState } from '@/views/states/savedViewSortsScopedFamilyState';
import { savedViewSortsByKeyScopedFamilySelector } from '@/views/states/selectors/savedViewSortsByKeyScopedFamilySelector';
import { ViewSort } from '@/views/types/ViewSort';
import { useViewStates } from '../useViewStates';
import { useViewSetStates } from '../useViewSetStates';
export const useViewSorts = (viewScopeId: string) => {
const { setCurrentViewSorts } = useViewStates(viewScopeId);
const { updateOneMutation, createOneMutation, findManyQuery } =
useFindOneMetadataObject({
objectNameSingular: 'viewSortV2',
});
const apolloClient = useApolloClient();
const { setCurrentViewSorts } = useViewSetStates(viewScopeId);
const persistViewSorts = useRecoilCallback(
({ snapshot, set }) =>
@ -22,54 +31,48 @@ export const useViewSorts = (viewScopeId: string) => {
return;
}
const _createViewSorts = (sorts: Sort[]) => {
if (!currentViewId || !sorts.length) return;
const createViewSorts = (viewSortsToCreate: ViewSort[]) => {
if (!viewSortsToCreate.length) return;
// return createViewSortsMutation({
// variables: {
// data: sorts.map((sort) => ({
// key: sort.key,
// direction: sort.direction as ViewSortDirection,
// name: sort.definition.label,
// viewId: viewId ?? currentViewId,
// })),
// },
// });
return Promise.all(
viewSortsToCreate.map((viewSort) =>
apolloClient.mutate({
mutation: createOneMutation,
variables: {
input: {
fieldId: viewSort.fieldId,
viewId: viewId ?? currentViewId,
direction: viewSort.direction,
},
},
refetchQueries: [findManyQuery],
}),
),
);
};
const _updateViewSorts = (sorts: Sort[]) => {
if (!currentViewId || !sorts.length) return;
const updateViewSorts = (viewSortsToUpdate: ViewSort[]) => {
if (!viewSortsToUpdate.length) return;
// return Promise.all(
// sorts.map((sort) =>
// updateViewSortMutation({
// variables: {
// data: {
// direction: sort.direction as ViewSortDirection,
// },
// where: {
// viewId_key: {
// key: sort.key,
// viewId: viewId ?? currentViewId,
// },
// },
// },
// }),
// ),
// );
return Promise.all(
viewSortsToUpdate.map((viewSort) =>
apolloClient.mutate({
mutation: updateOneMutation,
variables: {
idToUpdate: viewSort.id,
input: {
direction: viewSort.direction,
},
},
}),
),
);
};
const _deleteViewSorts = (sortKeys: string[]) => {
if (!currentViewId || !sortKeys.length) return;
const deleteViewSorts = (viewSortIdsToDelete: string[]) => {
if (!viewSortIdsToDelete.length) return;
// return deleteViewSortsMutation({
// variables: {
// where: {
// key: { in: sortKeys },
// viewId: { equals: viewId ?? currentViewId },
// },
// },
// });
// Todo
};
const currentViewSorts = snapshot
@ -85,7 +88,7 @@ export const useViewSorts = (viewScopeId: string) => {
.getLoadable(
savedViewSortsByKeyScopedFamilySelector({
scopeId: viewScopeId,
viewId: currentViewId,
viewId: viewId ?? currentViewId,
}),
)
.getValue();
@ -98,22 +101,23 @@ export const useViewSorts = (viewScopeId: string) => {
}
const sortsToCreate = currentViewSorts.filter(
(sort) => !savedViewSortsByKey[sort.key],
(sort) => !savedViewSortsByKey[sort.fieldId],
);
await _createViewSorts(sortsToCreate);
await createViewSorts(sortsToCreate);
const sortsToUpdate = currentViewSorts.filter(
(sort) =>
savedViewSortsByKey[sort.key] &&
savedViewSortsByKey[sort.key].direction !== sort.direction,
savedViewSortsByKey[sort.fieldId] &&
savedViewSortsByKey[sort.fieldId].direction !== sort.direction,
);
await _updateViewSorts(sortsToUpdate);
await updateViewSorts(sortsToUpdate);
const sortKeys = currentViewSorts.map((sort) => sort.key);
const sortKeys = currentViewSorts.map((sort) => sort.fieldId);
const sortKeysToDelete = Object.keys(savedViewSortsByKey).filter(
(previousSortKey) => !sortKeys.includes(previousSortKey),
);
await _deleteViewSorts(sortKeysToDelete);
await deleteViewSorts(sortKeysToDelete);
set(
savedViewSortsScopedFamilyState({
scopeId: viewScopeId,
@ -122,24 +126,99 @@ export const useViewSorts = (viewScopeId: string) => {
currentViewSorts,
);
},
[viewScopeId],
[
apolloClient,
createOneMutation,
findManyQuery,
updateOneMutation,
viewScopeId,
],
);
const upsertViewSort = (sortToUpsert: Sort) => {
setCurrentViewSorts?.((sorts) => {
return produce(sorts, (sortsDraft) => {
const index = sortsDraft.findIndex(
(sort) => sort.key === sortToUpsert.key,
);
const upsertViewSort = useRecoilCallback(
({ snapshot }) =>
(sortToUpsert: Sort) => {
const currentViewId = snapshot
.getLoadable(currentViewIdScopedState({ scopeId: viewScopeId }))
.getValue();
if (index === -1) {
sortsDraft.push(sortToUpsert);
} else {
sortsDraft[index] = sortToUpsert;
if (!currentViewId) {
return;
}
});
});
};
return { persistViewSorts, upsertViewSort };
const savedViewSortsByKey = snapshot
.getLoadable(
savedViewSortsByKeyScopedFamilySelector({
scopeId: viewScopeId,
viewId: currentViewId,
}),
)
.getValue();
if (!savedViewSortsByKey) {
return;
}
const onViewSortsChange = snapshot
.getLoadable(onViewSortsChangeScopedState({ scopeId: viewScopeId }))
.getValue();
const existingSavedSortId =
savedViewSortsByKey[sortToUpsert.fieldId]?.id;
setCurrentViewSorts?.((sorts) => {
const newViewSorts = produce(sorts, (sortsDraft) => {
const existingSortIndex = sortsDraft.findIndex(
(sort) => sort.fieldId === sortToUpsert.fieldId,
);
if (existingSortIndex === -1) {
sortsDraft.push({ ...sortToUpsert, id: existingSavedSortId });
return sortsDraft;
}
sortsDraft[existingSortIndex] = {
...sortToUpsert,
id: existingSavedSortId,
};
});
onViewSortsChange?.(newViewSorts);
return newViewSorts;
});
},
);
const removeViewSort = useRecoilCallback(
({ snapshot }) =>
(fieldId: string) => {
const currentViewId = snapshot
.getLoadable(currentViewIdScopedState({ scopeId: viewScopeId }))
.getValue();
if (!currentViewId) {
return;
}
const onViewSortsChange = snapshot
.getLoadable(onViewSortsChangeScopedState({ scopeId: viewScopeId }))
.getValue();
const currentViewSorts = snapshot
.getLoadable(
currentViewSortsScopedFamilyState({
scopeId: viewScopeId,
familyKey: currentViewId,
}),
)
.getValue();
const newViewSorts = currentViewSorts.filter((filter) => {
return filter.fieldId !== fieldId;
});
setCurrentViewSorts?.(newViewSorts);
onViewSortsChange?.(newViewSorts);
},
);
return { persistViewSorts, upsertViewSort, removeViewSort };
};

View File

@ -1,13 +1,21 @@
import { useApolloClient } from '@apollo/client';
import { useRecoilCallback } from 'recoil';
import { useFindOneMetadataObject } from '@/metadata/hooks/useFindOneMetadataObject';
import { viewObjectIdScopeState } from '@/views/states/viewObjectIdScopeState';
import { viewTypeScopedState } from '@/views/states/viewTypeScopedState';
import { View } from '@/views/types/View';
export const useViews = (scopeId: string) => {
const { updateOneMutation, createOneMutation, findManyQuery } =
useFindOneMetadataObject({
objectNameSingular: 'viewV2',
});
const apolloClient = useApolloClient();
const createView = useRecoilCallback(
({ snapshot }) =>
async (_view: Pick<View, 'id' | 'name'>) => {
async (view: Pick<View, 'id' | 'name'>) => {
const viewObjectId = await snapshot
.getLoadable(viewObjectIdScopeState({ scopeId }))
.getValue();
@ -19,27 +27,31 @@ export const useViews = (scopeId: string) => {
if (!viewObjectId || !viewType) {
return;
}
// await createViewMutation({
// variables: {
// data: {
// ...view,
// objectId: viewObjectId,
// type: viewType,
// },
// },
// refetchQueries: [getOperationName(GET_VIEWS) ?? ''],
// });
await apolloClient.mutate({
mutation: createOneMutation,
variables: {
input: {
...view,
objectId: viewObjectId,
type: viewType,
},
},
refetchQueries: [findManyQuery],
});
},
);
const updateView = async (_view: View) => {
// await updateViewMutation({
// variables: {
// data: { name: view.name },
// where: { id: view.id },
// },
// refetchQueries: [getOperationName(GET_VIEWS) ?? ''],
// });
const updateView = async (view: View) => {
await apolloClient.mutate({
mutation: updateOneMutation,
variables: {
idToUpdate: view.id,
input: {
...view,
},
},
refetchQueries: [findManyQuery],
});
};
const deleteView = async (_viewId: string) => {

View File

@ -1,15 +0,0 @@
import { useView } from '@/views/hooks/useView';
export const useRemoveFilter = () => {
const { setCurrentViewFilters } = useView();
const removeFilter = (filterKey: string) => {
setCurrentViewFilters?.((filters) => {
return filters.filter((filter) => {
return filter.key !== filterKey;
});
});
};
return removeFilter;
};

View File

@ -1,26 +0,0 @@
import { produce } from 'immer';
import { Filter } from '@/ui/data/filter/types/Filter';
import { useView } from '@/views/hooks/useView';
export const useUpsertFilter = () => {
const { setCurrentViewFilters } = useView();
const upsertFilter = (filterToUpsert: Filter) => {
setCurrentViewFilters?.((filters) => {
return produce(filters, (filtersDraft) => {
const index = filtersDraft.findIndex(
(filter) => filter.key === filterToUpsert.key,
);
if (index === -1) {
filtersDraft.push(filterToUpsert);
} else {
filtersDraft[index] = filterToUpsert;
}
});
});
};
return upsertFilter;
};

View File

@ -10,8 +10,12 @@ import { currentViewFieldsScopedFamilyState } from '../states/currentViewFieldsS
import { currentViewFiltersScopedFamilyState } from '../states/currentViewFiltersScopedFamilyState';
import { currentViewIdScopedState } from '../states/currentViewIdScopedState';
import { currentViewSortsScopedFamilyState } from '../states/currentViewSortsScopedFamilyState';
import { onViewFieldsChangeScopedState } from '../states/onViewFieldsChangeScopedState';
import { onViewFiltersChangeScopedState } from '../states/onViewFiltersChangeScopedState';
import { onViewSortsChangeScopedState } from '../states/onViewSortsChangeScopedState';
import { savedViewFiltersScopedFamilyState } from '../states/savedViewFiltersScopedFamilyState';
import { savedViewSortsScopedFamilyState } from '../states/savedViewSortsScopedFamilyState';
import { currentViewScopedSelector } from '../states/selectors/currentViewScopedSelector';
import { viewEditModeScopedState } from '../states/viewEditModeScopedState';
import { viewsScopedState } from '../states/viewsScopedState';
@ -19,7 +23,7 @@ import { useViewFields } from './internal/useViewFields';
import { useViewFilters } from './internal/useViewFilters';
import { useViews } from './internal/useViews';
import { useViewSorts } from './internal/useViewSorts';
import { useViewStates } from './useViewStates';
import { useViewSetStates } from './useViewSetStates';
type UseViewProps = {
viewScopeId?: string;
@ -42,33 +46,81 @@ export const useView = (props?: UseViewProps) => {
setEntityCountInCurrentView,
setIsViewBarExpanded,
setAvailableSorts,
setAvailableSortDefinitions,
setCurrentViewSorts,
setSavedViewSorts,
setAvailableFilters,
setAvailableFilterDefinitions,
setCurrentViewFilters,
setSavedViewFilters,
setAvailableFields,
setAvailableFieldDefinitions,
setCurrentViewFields,
setSavedViewFields,
} = useViewStates(scopeId);
const { persistViewSorts, upsertViewSort } = useViewSorts(scopeId);
const { persistViewFilters } = useViewFilters(scopeId);
setOnViewFieldsChange,
setOnViewFiltersChange,
setOnViewSortsChange,
} = useViewSetStates(scopeId);
const { persistViewSorts, upsertViewSort, removeViewSort } =
useViewSorts(scopeId);
const { persistViewFilters, upsertViewFilter, removeViewFilter } =
useViewFilters(scopeId);
const { persistViewFields } = useViewFields(scopeId);
const { createView: internalCreateView, deleteView: internalDeleteView } =
useViews(scopeId);
const {
createView: internalCreateView,
updateView: internalUpdateView,
deleteView: internalDeleteView,
} = useViews(scopeId);
const [_, setSearchParams] = useSearchParams();
const changeView = useCallback(
const changeViewInUrl = useCallback(
(viewId: string) => {
setSearchParams({ view: viewId });
},
[setSearchParams],
);
const loadView = useRecoilCallback(({ snapshot }) => (viewId: string) => {
setCurrentViewId?.(viewId);
const currentViewFields = snapshot
.getLoadable(
currentViewFieldsScopedFamilyState({ scopeId, familyKey: viewId }),
)
.getValue();
const onViewFieldsChange = snapshot
.getLoadable(onViewFieldsChangeScopedState({ scopeId }))
.getValue();
onViewFieldsChange?.(currentViewFields);
const currentViewFilters = snapshot
.getLoadable(
currentViewFiltersScopedFamilyState({ scopeId, familyKey: viewId }),
)
.getValue();
const onViewFiltersChange = snapshot
.getLoadable(onViewFiltersChangeScopedState({ scopeId }))
.getValue();
onViewFiltersChange?.(currentViewFilters);
const currentViewSorts = snapshot
.getLoadable(
currentViewSortsScopedFamilyState({ scopeId, familyKey: viewId }),
)
.getValue();
const onViewSortsChange = snapshot
.getLoadable(onViewSortsChangeScopedState({ scopeId }))
.getValue();
onViewSortsChange?.(currentViewSorts);
});
const resetViewBar = useRecoilCallback(({ snapshot }) => () => {
const savedViewFilters = snapshot
.getLoadable(
@ -95,7 +147,6 @@ export const useView = (props?: UseViewProps) => {
setCurrentViewSorts?.(savedViewSorts);
}
setViewEditMode?.('none');
setIsViewBarExpanded?.(false);
});
const createView = useRecoilCallback(
@ -156,10 +207,10 @@ export const useView = (props?: UseViewProps) => {
await persistViewFilters(newViewId);
await persistViewSorts(newViewId);
changeView(newViewId);
changeViewInUrl(newViewId);
},
[
changeView,
changeViewInUrl,
currentViewId,
internalCreateView,
persistViewFields,
@ -195,15 +246,32 @@ export const useView = (props?: UseViewProps) => {
const handleViewNameSubmit = useRecoilCallback(
({ snapshot }) =>
async (name?: string) => {
if (!name) {
return;
}
const viewEditMode = snapshot
.getLoadable(viewEditModeScopedState({ scopeId }))
.getValue();
const currentView = snapshot
.getLoadable(currentViewScopedSelector(scopeId))
.getValue();
if (!currentView) {
return;
}
if (viewEditMode === 'create' && name) {
await createView(name);
} else {
await internalUpdateView({
...currentView,
name,
});
}
},
[createView, scopeId],
[createView, internalUpdateView, scopeId],
);
return {
@ -224,20 +292,28 @@ export const useView = (props?: UseViewProps) => {
setViewType,
setEntityCountInCurrentView,
setAvailableSorts,
setAvailableSortDefinitions,
setCurrentViewSorts,
setSavedViewSorts,
upsertViewSort,
removeViewSort,
setAvailableFilters,
setAvailableFilterDefinitions,
setCurrentViewFilters,
setSavedViewFilters,
upsertViewFilter,
removeViewFilter,
setAvailableFields,
setAvailableFieldDefinitions,
setCurrentViewFields,
setSavedViewFields,
persistViewFields,
changeView,
changeViewInUrl,
loadView,
setOnViewFieldsChange,
setOnViewFiltersChange,
setOnViewSortsChange,
};
};

View File

@ -5,9 +5,9 @@ import { useRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/useRec
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
import { ViewScopeInternalContext } from '../scopes/scope-internal-context/ViewScopeInternalContext';
import { availableFieldsScopedState } from '../states/availableFieldsScopedState';
import { availableFiltersScopedState } from '../states/availableFiltersScopedState';
import { availableSortsScopedState } from '../states/availableSortsScopedState';
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';
@ -31,17 +31,14 @@ import { viewObjectIdScopeState } from '../states/viewObjectIdScopeState';
import { viewsScopedState } from '../states/viewsScopedState';
import { viewTypeScopedState } from '../states/viewTypeScopedState';
export const useViewInternalStates = (
viewScopeId?: string,
viewId?: string,
) => {
export const useViewGetStates = (viewScopeId?: string, viewId?: string) => {
const scopeId = useAvailableScopeIdOrThrow(
ViewScopeInternalContext,
viewScopeId,
);
// View
const [currentViewId, setCurrentViewId] = useRecoilScopedStateV2(
const [currentViewId] = useRecoilScopedStateV2(
currentViewIdScopedState,
scopeId,
);
@ -50,39 +47,38 @@ export const useViewInternalStates = (
const currentView = useRecoilValue(currentViewScopedSelector(scopeId));
const [viewEditMode, setViewEditMode] = useRecoilScopedStateV2(
const [viewEditMode] = useRecoilScopedStateV2(
viewEditModeScopedState,
scopeId,
);
const [views, setViews] = useRecoilScopedStateV2(viewsScopedState, scopeId);
const [views] = useRecoilScopedStateV2(viewsScopedState, scopeId);
const [viewObjectId, setViewObjectId] = useRecoilScopedStateV2(
const [viewObjectId] = useRecoilScopedStateV2(
viewObjectIdScopeState,
scopeId,
);
const [viewType, setViewType] = useRecoilScopedStateV2(
viewTypeScopedState,
const [viewType] = useRecoilScopedStateV2(viewTypeScopedState, scopeId);
const [entityCountInCurrentView] = useRecoilScopedStateV2(
entityCountInCurrentViewScopedState,
scopeId,
);
const [entityCountInCurrentView, setEntityCountInCurrentView] =
useRecoilScopedStateV2(entityCountInCurrentViewScopedState, scopeId);
const [isViewBarExpanded, setIsViewBarExpanded] = useRecoilScopedStateV2(
const [isViewBarExpanded] = useRecoilScopedStateV2(
isViewBarExpandedScopedState,
scopeId,
);
// ViewSorts
const [currentViewSorts, setCurrentViewSorts] = useRecoilScopedFamilyState(
const [currentViewSorts] = useRecoilScopedFamilyState(
currentViewSortsScopedFamilyState,
scopeId,
familyItemId,
);
const [savedViewSorts, setSavedViewSorts] = useRecoilScopedFamilyState(
const [savedViewSorts] = useRecoilScopedFamilyState(
savedViewSortsScopedFamilyState,
scopeId,
familyItemId,
@ -95,8 +91,8 @@ export const useViewInternalStates = (
}),
);
const [availableSorts, setAvailableSorts] = useRecoilScopedStateV2(
availableSortsScopedState,
const [availableSortDefinitions] = useRecoilScopedStateV2(
availableSortDefinitionsScopedState,
scopeId,
);
@ -108,14 +104,13 @@ export const useViewInternalStates = (
);
// ViewFilters
const [currentViewFilters, setCurrentViewFilters] =
useRecoilScopedFamilyState(
currentViewFiltersScopedFamilyState,
scopeId,
familyItemId,
);
const [currentViewFilters] = useRecoilScopedFamilyState(
currentViewFiltersScopedFamilyState,
scopeId,
familyItemId,
);
const [savedViewFilters, setSavedViewFilters] = useRecoilScopedFamilyState(
const [savedViewFilters] = useRecoilScopedFamilyState(
savedViewFiltersScopedFamilyState,
scopeId,
familyItemId,
@ -128,8 +123,8 @@ export const useViewInternalStates = (
}),
);
const [availableFilters, setAvailableFilters] = useRecoilScopedStateV2(
availableFiltersScopedState,
const [availableFilterDefinitions] = useRecoilScopedStateV2(
availableFilterDefinitionsScopedState,
scopeId,
);
@ -141,18 +136,18 @@ export const useViewInternalStates = (
);
// ViewFields
const [availableFields, setAvailableFields] = useRecoilScopedStateV2(
availableFieldsScopedState,
const [availableFieldDefinitions] = useRecoilScopedStateV2(
availableFieldDefinitionsScopedState,
scopeId,
);
const [currentViewFields, setCurrentViewFields] = useRecoilScopedFamilyState(
const [currentViewFields] = useRecoilScopedFamilyState(
currentViewFieldsScopedFamilyState,
scopeId,
familyItemId,
);
const [savedViewFields, setSavedViewFields] = useRecoilScopedFamilyState(
const [savedViewFields] = useRecoilScopedFamilyState(
savedViewFieldsScopedFamilyState,
scopeId,
familyItemId,
@ -166,17 +161,17 @@ export const useViewInternalStates = (
);
// ViewChangeHandlers
const [onViewSortsChange, setOnViewSortsChange] = useRecoilScopedStateV2(
const [onViewSortsChange] = useRecoilScopedStateV2(
onViewSortsChangeScopedState,
scopeId,
);
const [onViewFiltersChange, setOnViewFiltersChange] = useRecoilScopedStateV2(
const [onViewFiltersChange] = useRecoilScopedStateV2(
onViewFiltersChangeScopedState,
scopeId,
);
const [onViewFieldsChange, setOnViewFieldsChange] = useRecoilScopedStateV2(
const [onViewFieldsChange] = useRecoilScopedStateV2(
onViewFieldsChangeScopedState,
scopeId,
);
@ -184,52 +179,33 @@ export const useViewInternalStates = (
return {
currentViewId,
currentView,
setCurrentViewId,
isViewBarExpanded,
setIsViewBarExpanded,
views,
setViews,
viewEditMode,
setViewEditMode,
viewObjectId,
setViewObjectId,
viewType,
setViewType,
entityCountInCurrentView,
setEntityCountInCurrentView,
availableSorts,
setAvailableSorts,
availableSortDefinitions,
currentViewSorts,
setCurrentViewSorts,
savedViewSorts,
savedViewSortsByKey,
setSavedViewSorts,
canPersistSorts,
availableFilters,
setAvailableFilters,
availableFilterDefinitions,
currentViewFilters,
setCurrentViewFilters,
savedViewFilters,
savedViewFiltersByKey,
setSavedViewFilters,
canPersistFilters,
availableFields,
setAvailableFields,
availableFieldDefinitions,
currentViewFields,
savedViewFieldsByKey,
setCurrentViewFields,
savedViewFields,
setSavedViewFields,
onViewSortsChange,
setOnViewSortsChange,
onViewFiltersChange,
setOnViewFiltersChange,
onViewFieldsChange,
setOnViewFieldsChange,
};
};

View File

@ -4,15 +4,18 @@ import { useSetRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/use
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
import { ViewScopeInternalContext } from '../scopes/scope-internal-context/ViewScopeInternalContext';
import { availableFieldsScopedState } from '../states/availableFieldsScopedState';
import { availableFiltersScopedState } from '../states/availableFiltersScopedState';
import { availableSortsScopedState } from '../states/availableSortsScopedState';
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';
@ -21,7 +24,7 @@ import { viewObjectIdScopeState } from '../states/viewObjectIdScopeState';
import { viewsScopedState } from '../states/viewsScopedState';
import { viewTypeScopedState } from '../states/viewTypeScopedState';
export const useViewStates = (viewScopeId?: string, viewId?: string) => {
export const useViewSetStates = (viewScopeId?: string, viewId?: string) => {
const scopeId = useAvailableScopeIdOrThrow(
ViewScopeInternalContext,
viewScopeId,
@ -71,8 +74,8 @@ export const useViewStates = (viewScopeId?: string, viewId?: string) => {
familyItemId,
);
const setAvailableSorts = useSetRecoilScopedStateV2(
availableSortsScopedState,
const setAvailableSortDefinitions = useSetRecoilScopedStateV2(
availableSortDefinitionsScopedState,
scopeId,
);
@ -89,14 +92,14 @@ export const useViewStates = (viewScopeId?: string, viewId?: string) => {
familyItemId,
);
const setAvailableFilters = useSetRecoilScopedStateV2(
availableFiltersScopedState,
const setAvailableFilterDefinitions = useSetRecoilScopedStateV2(
availableFilterDefinitionsScopedState,
scopeId,
);
// ViewFields
const setAvailableFields = useSetRecoilScopedStateV2(
availableFieldsScopedState,
const setAvailableFieldDefinitions = useSetRecoilScopedStateV2(
availableFieldDefinitionsScopedState,
scopeId,
);
@ -112,6 +115,21 @@ export const useViewStates = (viewScopeId?: string, viewId?: string) => {
familyItemId,
);
const setOnViewFieldsChange = useSetRecoilScopedStateV2(
onViewFieldsChangeScopedState,
scopeId,
);
const setOnViewFiltersChange = useSetRecoilScopedStateV2(
onViewFiltersChangeScopedState,
scopeId,
);
const setOnViewSortsChange = useSetRecoilScopedStateV2(
onViewSortsChangeScopedState,
scopeId,
);
return {
currentViewId,
setCurrentViewId,
@ -123,16 +141,20 @@ export const useViewStates = (viewScopeId?: string, viewId?: string) => {
setViewEditMode,
setEntityCountInCurrentView,
setAvailableSorts,
setAvailableSortDefinitions,
setCurrentViewSorts,
setSavedViewSorts,
setAvailableFilters,
setAvailableFilterDefinitions,
setCurrentViewFilters,
setSavedViewFilters,
setAvailableFields,
setAvailableFieldDefinitions,
setCurrentViewFields,
setSavedViewFields,
setOnViewFieldsChange,
setOnViewFiltersChange,
setOnViewSortsChange,
};
};

View File

@ -3,7 +3,6 @@ import { useEffect } from 'react';
import { Filter } from '@/ui/data/filter/types/Filter';
import { Sort } from '@/ui/data/sort/types/Sort';
import { useView } from '@/views/hooks/useView';
import { useViewInternalStates } from '@/views/hooks/useViewInternalStates';
import { ViewField } from '@/views/types/ViewField';
type ViewScopeInitEffectProps = {
@ -14,17 +13,15 @@ type ViewScopeInitEffectProps = {
};
export const ViewScopeInitEffect = ({
viewScopeId,
onViewSortsChange,
onViewFiltersChange,
onViewFieldsChange,
}: ViewScopeInitEffectProps) => {
const { currentViewId } = useView();
const {
setOnViewSortsChange,
setOnViewFieldsChange,
setOnViewFiltersChange,
} = useViewInternalStates(viewScopeId, currentViewId);
} = useView();
useEffect(() => {
setOnViewSortsChange(() => onViewSortsChange);

View File

@ -2,9 +2,9 @@ import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
export const availableFieldsScopedState = createScopedState<
export const availableFieldDefinitionsScopedState = createScopedState<
ColumnDefinition<FieldMetadata>[]
>({
key: 'availableFieldsScopedState',
key: 'availableFieldDefinitionsScopedState',
defaultValue: [],
});

View File

@ -1,9 +1,9 @@
import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition';
import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
export const availableFiltersScopedState = createScopedState<
export const availableFilterDefinitionsScopedState = createScopedState<
FilterDefinition[]
>({
key: 'availableFiltersScopedState',
key: 'availableFilterDefinitionsScopedState',
defaultValue: [],
});

View File

@ -1,7 +1,9 @@
import { SortDefinition } from '@/ui/data/sort/types/SortDefinition';
import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
export const availableSortsScopedState = createScopedState<SortDefinition[]>({
key: 'availableSortsScopedState',
export const availableSortDefinitionsScopedState = createScopedState<
SortDefinition[]
>({
key: 'availableSortDefinitionsScopedState',
defaultValue: [],
});

View File

@ -1,8 +1,9 @@
import { Filter } from '@/ui/data/filter/types/Filter';
import { createScopedFamilyState } from '@/ui/utilities/recoil-scope/utils/createScopedFamilyState';
import { ViewFilter } from '../types/ViewFilter';
export const currentViewFiltersScopedFamilyState = createScopedFamilyState<
Filter[],
ViewFilter[],
string
>({
key: 'currentViewFiltersScopedFamilyState',

View File

@ -1,8 +1,9 @@
import { Sort } from '@/ui/data/sort/types/Sort';
import { createScopedFamilyState } from '@/ui/utilities/recoil-scope/utils/createScopedFamilyState';
import { ViewSort } from '../types/ViewSort';
export const currentViewSortsScopedFamilyState = createScopedFamilyState<
Sort[],
ViewSort[],
string
>({
key: 'currentViewSortsScopedFamilyState',

View File

@ -1,8 +1,9 @@
import { Filter } from '@/ui/data/filter/types/Filter';
import { createScopedFamilyState } from '@/ui/utilities/recoil-scope/utils/createScopedFamilyState';
import { ViewFilter } from '../types/ViewFilter';
export const savedViewFiltersScopedFamilyState = createScopedFamilyState<
Filter[],
ViewFilter[],
string
>({
key: 'savedViewFiltersScopedFamilyState',

View File

@ -1,8 +1,9 @@
import { Sort } from '@/ui/data/sort/types/Sort';
import { createScopedFamilyState } from '@/ui/utilities/recoil-scope/utils/createScopedFamilyState';
import { ViewSort } from '../types/ViewSort';
export const savedViewSortsScopedFamilyState = createScopedFamilyState<
Sort[],
ViewSort[],
string
>({
key: 'savedViewSortsScopedFamilyState',

View File

@ -1,6 +1,6 @@
import { selectorFamily } from 'recoil';
import { Filter } from '@/ui/data/filter/types/Filter';
import { ViewFilter } from '@/views/types/ViewFilter';
import { savedViewFiltersScopedFamilyState } from '../savedViewFiltersScopedFamilyState';
@ -17,8 +17,8 @@ export const savedViewFiltersByKeyScopedFamilySelector = selectorFamily({
scopeId: scopeId,
familyKey: viewId,
}),
).reduce<Record<string, Filter>>(
(result, filter) => ({ ...result, [filter.key]: filter }),
).reduce<Record<string, ViewFilter>>(
(result, filter) => ({ ...result, [filter.fieldId]: filter }),
{},
);
},

View File

@ -1,6 +1,6 @@
import { selectorFamily } from 'recoil';
import { Sort } from '@/ui/data/sort/types/Sort';
import { ViewSort } from '@/views/types/ViewSort';
import { savedViewSortsScopedFamilyState } from '../savedViewSortsScopedFamilyState';
@ -17,8 +17,8 @@ export const savedViewSortsByKeyScopedFamilySelector = selectorFamily({
scopeId: scopeId,
familyKey: viewId,
}),
).reduce<Record<string, Sort>>(
(result, sort) => ({ ...result, [sort.key]: sort }),
).reduce<Record<string, ViewSort>>(
(result, sort) => ({ ...result, [sort.fieldId]: sort }),
{},
);
},

View File

@ -1,7 +1,11 @@
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
export type ViewField = {
id: string;
fieldId: string;
position: number;
isVisible: boolean;
size: number;
definition: ColumnDefinition<FieldMetadata>;
};

View File

@ -0,0 +1,12 @@
import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition';
import { ViewFilterOperand } from './ViewFilterOperand';
export type ViewFilter = {
id?: string;
fieldId: string;
operand: ViewFilterOperand;
value: string;
displayValue: string;
definition: FilterDefinition;
};

View File

@ -0,0 +1,9 @@
import { SortDefinition } from '@/ui/data/sort/types/SortDefinition';
import { SortDirection } from '@/ui/data/sort/types/SortDirection';
export type ViewSort = {
id?: string;
fieldId: string;
direction: SortDirection;
definition: SortDefinition;
};

View File

@ -12,5 +12,6 @@ export const columnDefinitionsToViewFields = (
position: columnDefinition.position,
size: columnDefinition.size,
isVisible: columnDefinition.isVisible ?? true,
definition: columnDefinition,
}));
};

View File

@ -0,0 +1,35 @@
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
import { BoardFieldDefinition } from '@/ui/layout/board/types/BoardFieldDefinition';
import { assertNotNull } from '~/utils/assert';
import { ViewField } from '../types/ViewField';
export const viewFieldsToBoardFieldDefinitions = (
viewFields: ViewField[],
fieldsMetadata: BoardFieldDefinition<FieldMetadata>[],
): BoardFieldDefinition<FieldMetadata>[] => {
return viewFields
.map((viewField) => {
const correspondingFieldMetadata = fieldsMetadata.find(
({ fieldId }) => viewField.fieldId === fieldId,
);
return correspondingFieldMetadata
? {
fieldId: viewField.fieldId,
label: correspondingFieldMetadata.label,
metadata: correspondingFieldMetadata.metadata,
entityChipDisplayMapper:
correspondingFieldMetadata.entityChipDisplayMapper,
infoTooltipContent: correspondingFieldMetadata.infoTooltipContent,
basePathToShowPage: correspondingFieldMetadata.basePathToShowPage,
Icon: correspondingFieldMetadata.Icon,
type: correspondingFieldMetadata.type,
position: viewField.position,
isVisible: viewField.isVisible,
viewFieldId: viewField.id,
}
: null;
})
.filter(assertNotNull);
};

View File

@ -0,0 +1,15 @@
import { Filter } from '@/ui/data/filter/types/Filter';
import { ViewFilter } from '../types/ViewFilter';
export const viewFiltersToFilters = (viewFilters: ViewFilter[]): Filter[] => {
return viewFilters.map((viewFilter) => {
return {
fieldId: viewFilter.fieldId,
value: viewFilter.value,
displayValue: viewFilter.displayValue,
operand: viewFilter.operand,
definition: viewFilter.definition,
};
});
};

View File

@ -0,0 +1,13 @@
import { Sort } from '@/ui/data/sort/types/Sort';
import { ViewSort } from '../types/ViewSort';
export const viewSortsToSorts = (viewSorts: ViewSort[]): Sort[] => {
return viewSorts.map((viewSort) => {
return {
fieldId: viewSort.fieldId,
direction: viewSort.direction,
definition: viewSort.definition,
};
});
};