Migrate view field to new data model - Part 2 (#2270)

* Migrate view field to new data model

* Migrate view fields to new model
This commit is contained in:
Charles Bochet
2023-10-28 19:13:48 +02:00
committed by GitHub
parent b591023eb3
commit 685d342170
168 changed files with 960 additions and 4568 deletions

View File

@ -4,25 +4,14 @@ import { useRecoilCallback } from 'recoil';
import { useFindManyObjects } from '@/metadata/hooks/useFindManyObjects';
import { PaginatedObjectTypeResults } from '@/metadata/types/PaginatedObjectTypeResults';
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
import { Filter } from '@/ui/data/filter/types/Filter';
import { Sort } from '@/ui/data/sort/types/Sort';
import {
useGetViewFiltersQuery,
useGetViewSortsQuery,
} from '~/generated/graphql';
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 { availableFiltersScopedState } from '../states/availableFiltersScopedState';
import { availableSortsScopedState } from '../states/availableSortsScopedState';
import { onViewFieldsChangeScopedState } from '../states/onViewFieldsChangeScopedState';
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';
@ -32,10 +21,6 @@ export const ViewBarEffect = () => {
scopeId: viewScopeId,
setCurrentViewFields,
setSavedViewFields,
setCurrentViewSorts,
setSavedViewSorts,
setCurrentViewFilters,
setSavedViewFilters,
currentViewId,
setViews,
changeView,
@ -56,6 +41,12 @@ export const ViewBarEffect = () => {
.getLoadable(availableFieldsScopedState({ scopeId: viewScopeId }))
.getValue();
const onViewFieldsChange = snapshot
.getLoadable(
onViewFieldsChangeScopedState({ scopeId: viewScopeId }),
)
.getValue();
if (!availableFields || !currentViewId) {
return;
}
@ -70,27 +61,13 @@ export const ViewBarEffect = () => {
.getValue();
const queriedViewFields = data.edges
.map<ColumnDefinition<FieldMetadata> | null>((viewField) => {
const columnDefinition = availableFields.find(
({ key }) => viewField.node.fieldId === key,
);
return columnDefinition
? {
...columnDefinition,
key: viewField.node.fieldId,
name: viewField.node.fieldId,
index: viewField.node.position,
size: viewField.node.size ?? columnDefinition.size,
isVisible: viewField.node.isVisible,
}
: null;
})
.filter<ColumnDefinition<FieldMetadata>>(assertNotNull);
.map((viewField) => viewField.node)
.filter(assertNotNull);
if (!isDeeplyEqual(savedViewFields, queriedViewFields)) {
setCurrentViewFields?.(queriedViewFields);
setSavedViewFields?.(queriedViewFields);
onViewFieldsChange?.(queriedViewFields);
}
},
),
@ -115,108 +92,108 @@ export const ViewBarEffect = () => {
if (!nextViews.length) return;
if (!currentViewId) return setCurrentViewId(nextViews[0].id);
if (!currentViewId) return changeView(nextViews[0].id);
},
),
});
useGetViewSortsQuery({
skip: !currentViewId,
variables: {
where: {
viewId: { equals: currentViewId },
},
},
onCompleted: useRecoilCallback(({ snapshot }) => async (data) => {
const availableSorts = snapshot
.getLoadable(availableSortsScopedState({ scopeId: viewScopeId }))
.getValue();
// useGetViewSortsQuery({
// skip: !currentViewId,
// variables: {
// where: {
// viewId: { equals: currentViewId },
// },
// },
// onCompleted: useRecoilCallback(({ snapshot }) => async (data) => {
// const availableSorts = snapshot
// .getLoadable(availableSortsScopedState({ scopeId: viewScopeId }))
// .getValue();
if (!availableSorts || !currentViewId) {
return;
}
// if (!availableSorts || !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 queriedViewSorts = data.viewSorts
// .map((viewSort) => {
// const foundCorrespondingSortDefinition = availableSorts.find(
// (sort) => sort.key === viewSort.key,
// );
if (foundCorrespondingSortDefinition) {
return {
key: viewSort.key,
definition: foundCorrespondingSortDefinition,
direction: viewSort.direction.toLowerCase(),
} as Sort;
} else {
return undefined;
}
})
.filter((sort): sort is Sort => !!sort);
// if (foundCorrespondingSortDefinition) {
// return {
// key: viewSort.key,
// definition: foundCorrespondingSortDefinition,
// direction: viewSort.direction.toLowerCase(),
// } as Sort;
// } else {
// return undefined;
// }
// })
// .filter((sort): sort is Sort => !!sort);
if (!isDeeplyEqual(savedViewSorts, queriedViewSorts)) {
setSavedViewSorts?.(queriedViewSorts);
setCurrentViewSorts?.(queriedViewSorts);
}
}),
});
// if (!isDeeplyEqual(savedViewSorts, queriedViewSorts)) {
// setSavedViewSorts?.(queriedViewSorts);
// setCurrentViewSorts?.(queriedViewSorts);
// }
// }),
// });
useGetViewFiltersQuery({
skip: !currentViewId,
variables: {
where: {
viewId: { equals: currentViewId },
},
},
onCompleted: useRecoilCallback(({ snapshot }) => (data) => {
const availableFilters = snapshot
.getLoadable(availableFiltersScopedState({ scopeId: viewScopeId }))
.getValue();
// useGetViewFiltersQuery({
// skip: !currentViewId,
// variables: {
// where: {
// viewId: { equals: currentViewId },
// },
// },
// onCompleted: useRecoilCallback(({ snapshot }) => (data) => {
// const availableFilters = snapshot
// .getLoadable(availableFiltersScopedState({ scopeId: viewScopeId }))
// .getValue();
if (!availableFilters || !currentViewId) {
return;
}
// if (!availableFilters || !currentViewId) {
// return;
// }
const savedViewFilters = snapshot
.getLoadable(
savedViewFiltersScopedFamilyState({
scopeId: viewScopeId,
familyKey: currentViewId,
}),
)
.getValue();
// 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,
);
// 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);
// 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(savedViewFilters, queriedViewFilters)) {
// setSavedViewFilters?.(queriedViewFilters);
// setCurrentViewFilters?.(queriedViewFilters);
// }
// }),
// });
const currentViewIdFromUrl = searchParams.get('view');

View File

@ -6,6 +6,8 @@ import {
ResponderProvided,
} from '@hello-pangea/dnd';
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
import { IconMinus, IconPlus } from '@/ui/display/icon';
import { AppTooltip } from '@/ui/display/tooltip/AppTooltip';
import { IconInfoCircle } from '@/ui/input/constants/icons';
@ -18,11 +20,11 @@ import { MenuItemDraggable } from '@/ui/navigation/menu-item/components/MenuItem
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { isDefined } from '~/utils/isDefined';
import { ViewFieldForVisibility } from '../types/ViewFieldForVisibility';
type ViewFieldsVisibilityDropdownSectionProps = {
fields: ViewFieldForVisibility[];
onVisibilityChange: (field: ViewFieldForVisibility) => void;
fields: Omit<ColumnDefinition<FieldMetadata>, 'size'>[];
onVisibilityChange: (
field: Omit<ColumnDefinition<FieldMetadata>, 'size' | 'position'>,
) => void;
title: string;
isDraggable: boolean;
onDragEnd?: OnDragEndResponder;
@ -46,7 +48,10 @@ export const ViewFieldsVisibilityDropdownSection = ({
else setOpenToolTipIndex(index);
};
const getIconButtons = (index: number, field: ViewFieldForVisibility) => {
const getIconButtons = (
index: number,
field: Omit<ColumnDefinition<FieldMetadata>, 'size' | 'position'>,
) => {
if (field.infoTooltipContent) {
return [
{
@ -88,20 +93,20 @@ export const ViewFieldsVisibilityDropdownSection = ({
onDragEnd={handleOnDrag}
draggableItems={
<>
{fields
.filter(({ index, size }) => index !== 0 || !size)
{[...fields]
.sort((a, b) => a.position - b.position)
.map((field, index) => (
<DraggableItem
key={field.key}
draggableId={field.key}
key={field.fieldId}
draggableId={field.fieldId}
index={index + 1}
itemComponent={
<MenuItemDraggable
key={field.key}
key={field.fieldId}
LeftIcon={field.Icon}
iconButtons={getIconButtons(index + 1, field)}
isTooltipOpen={openToolTipIndex === index + 1}
text={field.name}
text={field.label}
className={`${title}-draggable-item-tooltip-anchor-${
index + 1
}`}
@ -115,11 +120,11 @@ export const ViewFieldsVisibilityDropdownSection = ({
) : (
fields.map((field, index) => (
<MenuItem
key={field.key}
key={field.fieldId}
LeftIcon={field.Icon}
iconButtons={getIconButtons(index, field)}
isTooltipOpen={openToolTipIndex === index}
text={field.name}
text={field.label}
className={`${title}-fixed-item-tooltip-anchor-${index}`}
/>
))

View File

@ -1,12 +0,0 @@
import { gql } from '@apollo/client';
export const VIEW_FIELD_FRAGMENT = gql`
fragment ViewFieldFragment on ViewField {
index
isVisible
key
name
size
viewId
}
`;

View File

@ -1,10 +0,0 @@
import { gql } from '@apollo/client';
export const CREATE_VIEW = gql`
mutation CreateView($data: ViewCreateInput!) {
view: createOneView(data: $data) {
id
name
}
}
`;

View File

@ -1,9 +0,0 @@
import { gql } from '@apollo/client';
export const CREATE_VIEW_FIELDS = gql`
mutation CreateViewFields($data: [ViewFieldCreateManyInput!]!) {
createManyViewField(data: $data) {
count
}
}
`;

View File

@ -1,9 +0,0 @@
import { gql } from '@apollo/client';
export const CREATE_VIEW_FILTERS = gql`
mutation CreateViewFilters($data: [ViewFilterCreateManyInput!]!) {
createManyViewFilter(data: $data) {
count
}
}
`;

View File

@ -1,9 +0,0 @@
import { gql } from '@apollo/client';
export const CREATE_VIEW_SORTS = gql`
mutation CreateViewSorts($data: [ViewSortCreateManyInput!]!) {
createManyViewSort(data: $data) {
count
}
}
`;

View File

@ -1,10 +0,0 @@
import { gql } from '@apollo/client';
export const DELETE_VIEW = gql`
mutation DeleteView($where: ViewWhereUniqueInput!) {
view: deleteOneView(where: $where) {
id
name
}
}
`;

View File

@ -1,9 +0,0 @@
import { gql } from '@apollo/client';
export const DELETE_VIEW_FILTERS = gql`
mutation DeleteViewFilters($where: ViewFilterWhereInput!) {
deleteManyViewFilter(where: $where) {
count
}
}
`;

View File

@ -1,9 +0,0 @@
import { gql } from '@apollo/client';
export const DELETE_VIEW_SORTS = gql`
mutation DeleteViewSorts($where: ViewSortWhereInput!) {
deleteManyViewSort(where: $where) {
count
}
}
`;

View File

@ -1,10 +0,0 @@
import { gql } from '@apollo/client';
export const UPDATE_VIEW = gql`
mutation UpdateView($data: ViewUpdateInput!, $where: ViewWhereUniqueInput!) {
view: updateOneView(data: $data, where: $where) {
id
name
}
}
`;

View File

@ -1,12 +0,0 @@
import { gql } from '@apollo/client';
export const UPDATE_VIEW_FIELD = gql`
mutation UpdateViewField(
$data: ViewFieldUpdateInput!
$where: ViewFieldWhereUniqueInput!
) {
updateOneViewField(data: $data, where: $where) {
...ViewFieldFragment
}
}
`;

View File

@ -1,16 +0,0 @@
import { gql } from '@apollo/client';
export const UPDATE_VIEW_FILTER = gql`
mutation UpdateViewFilter(
$data: ViewFilterUpdateInput!
$where: ViewFilterWhereUniqueInput!
) {
viewFilter: updateOneViewFilter(data: $data, where: $where) {
displayValue
key
name
operand
value
}
}
`;

View File

@ -1,14 +0,0 @@
import { gql } from '@apollo/client';
export const UPDATE_VIEW_SORT = gql`
mutation UpdateViewSort(
$data: ViewSortUpdateInput!
$where: ViewSortWhereUniqueInput!
) {
viewSort: updateOneViewSort(data: $data, where: $where) {
direction
key
name
}
}
`;

View File

@ -1,12 +0,0 @@
import { gql } from '@apollo/client';
export const GET_VIEW_FIELDS = gql`
query GetViewFields(
$where: ViewFieldWhereInput
$orderBy: [ViewFieldOrderByWithRelationInput!]
) {
viewFields: findManyViewField(where: $where, orderBy: $orderBy) {
...ViewFieldFragment
}
}
`;

View File

@ -1,13 +0,0 @@
import { gql } from '@apollo/client';
export const GET_VIEW_FILTERS = gql`
query GetViewFilters($where: ViewFilterWhereInput) {
viewFilters: findManyViewFilter(where: $where) {
displayValue
key
name
operand
value
}
}
`;

View File

@ -1,11 +0,0 @@
import { gql } from '@apollo/client';
export const GET_VIEW_SORTS = gql`
query GetViewSorts($where: ViewSortWhereInput) {
viewSorts: findManyViewSort(where: $where) {
direction
key
name
}
}
`;

View File

@ -1,10 +0,0 @@
import { gql } from '@apollo/client';
export const GET_VIEWS = gql`
query GetViews($where: ViewWhereInput) {
views: findManyView(where: $where) {
id
name
}
}
`;

View File

@ -1,37 +1,21 @@
import { useApolloClient } from '@apollo/client';
import { useRecoilCallback } from 'recoil';
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
import { useFindOneMetadataObject } from '@/metadata/hooks/useFindOneMetadataObject';
import { currentViewIdScopedState } from '@/views/states/currentViewIdScopedState';
import { savedViewFieldByKeyScopedFamilySelector } from '@/views/states/selectors/savedViewFieldByKeyScopedFamilySelector';
import { viewObjectIdScopeState } from '@/views/states/viewObjectIdScopeState';
import {
CreateViewFieldsDocument,
UpdateViewFieldDocument,
} from '~/generated/graphql';
export const toViewFieldInput = (
objectId: string,
fieldDefinition: ColumnDefinition<FieldMetadata>,
) => ({
key: fieldDefinition.key,
name: fieldDefinition.name,
index: fieldDefinition.index,
isVisible: fieldDefinition.isVisible ?? true,
objectId,
size: fieldDefinition.size,
});
import { ViewField } from '@/views/types/ViewField';
export const useViewFields = (viewScopeId: string) => {
const { updateOneMutation, createOneMutation } = useFindOneMetadataObject({
objectNameSingular: 'viewFieldV2',
});
const apolloClient = useApolloClient();
const persistViewFields = useRecoilCallback(
({ snapshot }) =>
async (
viewFieldsToPersist: ColumnDefinition<FieldMetadata>[],
viewId?: string,
) => {
async (viewFieldsToPersist: ViewField[], viewId?: string) => {
const currentViewId = snapshot
.getLoadable(currentViewIdScopedState({ scopeId: viewScopeId }))
.getValue();
@ -52,47 +36,45 @@ export const useViewFields = (viewScopeId: string) => {
if (!currentViewId || !savedViewFieldsByKey || !viewObjectId) {
return;
}
const _createViewFields = (
viewFieldsToCreate: ColumnDefinition<FieldMetadata>[],
objectId: string,
) => {
if (!currentViewId || !viewFieldsToCreate.length) {
const _createViewFields = (viewFieldsToCreate: ViewField[]) => {
if (!viewFieldsToCreate.length) {
return;
}
return apolloClient.mutate({
mutation: CreateViewFieldsDocument,
variables: {
data: viewFieldsToCreate.map((viewField) => ({
...toViewFieldInput(objectId, viewField),
viewId: viewId ?? currentViewId,
})),
},
});
return Promise.all(
viewFieldsToCreate.map((viewField) =>
apolloClient.mutate({
mutation: createOneMutation,
variables: {
input: {
fieldId: viewField.fieldId,
viewId: currentViewId,
isVisible: viewField.isVisible,
size: viewField.size,
position: viewField.position,
},
},
}),
),
);
};
const _updateViewFields = (
viewFieldsToUpdate: ColumnDefinition<FieldMetadata>[],
) => {
if (!currentViewId || !viewFieldsToUpdate.length) {
const _updateViewFields = (viewFieldsToUpdate: ViewField[]) => {
if (!viewFieldsToUpdate.length) {
return;
}
return Promise.all(
viewFieldsToUpdate.map((viewField) =>
apolloClient.mutate({
mutation: UpdateViewFieldDocument,
mutation: updateOneMutation,
variables: {
data: {
idToUpdate: viewField.id,
input: {
isVisible: viewField.isVisible,
size: viewField.size,
index: viewField.index,
},
where: {
viewId_key: {
key: viewField.key,
viewId: viewId ?? currentViewId,
},
position: viewField.position,
},
},
}),
@ -101,18 +83,18 @@ export const useViewFields = (viewScopeId: string) => {
};
const viewFieldsToCreate = viewFieldsToPersist.filter(
(viewField) => !savedViewFieldsByKey[viewField.key],
(viewField) => !savedViewFieldsByKey[viewField.fieldId],
);
await _createViewFields(viewFieldsToCreate, viewObjectId);
await _createViewFields(viewFieldsToCreate);
const viewFieldsToUpdate = viewFieldsToPersist.filter(
(viewFieldToPersit) =>
savedViewFieldsByKey[viewFieldToPersit.key] &&
(savedViewFieldsByKey[viewFieldToPersit.key].size !==
savedViewFieldsByKey[viewFieldToPersit.fieldId] &&
(savedViewFieldsByKey[viewFieldToPersit.fieldId].size !==
viewFieldToPersit.size ||
savedViewFieldsByKey[viewFieldToPersit.key].index !==
viewFieldToPersit.index ||
savedViewFieldsByKey[viewFieldToPersit.key].isVisible !==
savedViewFieldsByKey[viewFieldToPersit.fieldId].position !==
viewFieldToPersit.position ||
savedViewFieldsByKey[viewFieldToPersit.fieldId].isVisible !==
viewFieldToPersit.isVisible),
);

View File

@ -7,17 +7,8 @@ import { currentViewFiltersScopedFamilyState } from '@/views/states/currentViewF
import { currentViewIdScopedState } from '@/views/states/currentViewIdScopedState';
import { savedViewFiltersScopedFamilyState } from '@/views/states/savedViewFiltersScopedFamilyState';
import { savedViewFiltersByKeyScopedFamilySelector } from '@/views/states/selectors/savedViewFiltersByKeyScopedFamilySelector';
import {
useCreateViewFiltersMutation,
useDeleteViewFiltersMutation,
useUpdateViewFilterMutation,
} from '~/generated/graphql';
export const useViewFilters = (viewScopeId: string) => {
const [createViewFiltersMutation] = useCreateViewFiltersMutation();
const [updateViewFilterMutation] = useUpdateViewFilterMutation();
const [deleteViewFiltersMutation] = useDeleteViewFiltersMutation();
const persistViewFilters = useRecoilCallback(
({ snapshot, set }) =>
async (viewId?: string) => {
@ -40,57 +31,57 @@ export const useViewFilters = (viewScopeId: string) => {
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 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,
// })),
// },
// });
};
const _updateViewFilters = (filters: Filter[]) => {
if (!currentViewId || !filters.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(
// 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,
// },
// },
// },
// }),
// ),
// );
};
const _deleteViewFilters = (filterKeys: string[]) => {
if (!currentViewId || !filterKeys.length) return;
return deleteViewFiltersMutation({
variables: {
where: {
key: { in: filterKeys },
viewId: { equals: viewId ?? currentViewId },
},
},
});
// return deleteViewFiltersMutation({
// variables: {
// where: {
// key: { in: filterKeys },
// viewId: { equals: viewId ?? currentViewId },
// },
// },
// });
};
const currentViewFilters = snapshot
@ -152,12 +143,7 @@ export const useViewFilters = (viewScopeId: string) => {
currentViewFilters,
);
},
[
viewScopeId,
createViewFiltersMutation,
updateViewFilterMutation,
deleteViewFiltersMutation,
],
[viewScopeId],
);
return { persistViewFilters };

View File

@ -6,20 +6,11 @@ import { currentViewIdScopedState } from '@/views/states/currentViewIdScopedStat
import { currentViewSortsScopedFamilyState } from '@/views/states/currentViewSortsScopedFamilyState';
import { savedViewSortsScopedFamilyState } from '@/views/states/savedViewSortsScopedFamilyState';
import { savedViewSortsByKeyScopedFamilySelector } from '@/views/states/selectors/savedViewSortsByKeyScopedFamilySelector';
import {
useCreateViewSortsMutation,
useDeleteViewSortsMutation,
useUpdateViewSortMutation,
ViewSortDirection,
} from '~/generated/graphql';
import { useViewStates } from '../useViewStates';
export const useViewSorts = (viewScopeId: string) => {
const { setCurrentViewSorts } = useViewStates(viewScopeId);
const [createViewSortsMutation] = useCreateViewSortsMutation();
const [updateViewSortMutation] = useUpdateViewSortMutation();
const [deleteViewSortsMutation] = useDeleteViewSortsMutation();
const persistViewSorts = useRecoilCallback(
({ snapshot, set }) =>
@ -34,51 +25,51 @@ export const useViewSorts = (viewScopeId: string) => {
const _createViewSorts = (sorts: Sort[]) => {
if (!currentViewId || !sorts.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 createViewSortsMutation({
// variables: {
// data: sorts.map((sort) => ({
// key: sort.key,
// direction: sort.direction as ViewSortDirection,
// name: sort.definition.label,
// viewId: viewId ?? currentViewId,
// })),
// },
// });
};
const _updateViewSorts = (sorts: Sort[]) => {
if (!currentViewId || !sorts.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(
// sorts.map((sort) =>
// updateViewSortMutation({
// variables: {
// data: {
// direction: sort.direction as ViewSortDirection,
// },
// where: {
// viewId_key: {
// key: sort.key,
// viewId: viewId ?? currentViewId,
// },
// },
// },
// }),
// ),
// );
};
const _deleteViewSorts = (sortKeys: string[]) => {
if (!currentViewId || !sortKeys.length) return;
return deleteViewSortsMutation({
variables: {
where: {
key: { in: sortKeys },
viewId: { equals: viewId ?? currentViewId },
},
},
});
// return deleteViewSortsMutation({
// variables: {
// where: {
// key: { in: sortKeys },
// viewId: { equals: viewId ?? currentViewId },
// },
// },
// });
};
const currentViewSorts = snapshot
@ -131,12 +122,7 @@ export const useViewSorts = (viewScopeId: string) => {
currentViewSorts,
);
},
[
viewScopeId,
createViewSortsMutation,
updateViewSortMutation,
deleteViewSortsMutation,
],
[viewScopeId],
);
const upsertViewSort = (sortToUpsert: Sort) => {

View File

@ -1,25 +1,13 @@
import { getOperationName } from '@apollo/client/utilities';
import { useRecoilCallback } from 'recoil';
import { viewObjectIdScopeState } from '@/views/states/viewObjectIdScopeState';
import { viewTypeScopedState } from '@/views/states/viewTypeScopedState';
import { View } from '@/views/types/View';
import {
useCreateViewMutation,
useDeleteViewMutation,
useUpdateViewMutation,
} from '~/generated/graphql';
import { GET_VIEWS } from '../../graphql/queries/getViews';
export const useViews = (scopeId: string) => {
const [createViewMutation] = useCreateViewMutation();
const [updateViewMutation] = useUpdateViewMutation();
const [deleteViewMutation] = useDeleteViewMutation();
const createView = useRecoilCallback(
({ snapshot }) =>
async (view: Pick<View, 'id' | 'name'>) => {
async (_view: Pick<View, 'id' | 'name'>) => {
const viewObjectId = await snapshot
.getLoadable(viewObjectIdScopeState({ scopeId }))
.getValue();
@ -31,34 +19,34 @@ export const useViews = (scopeId: string) => {
if (!viewObjectId || !viewType) {
return;
}
await createViewMutation({
variables: {
data: {
...view,
objectId: viewObjectId,
type: viewType,
},
},
refetchQueries: [getOperationName(GET_VIEWS) ?? ''],
});
// await createViewMutation({
// variables: {
// data: {
// ...view,
// objectId: viewObjectId,
// type: viewType,
// },
// },
// refetchQueries: [getOperationName(GET_VIEWS) ?? ''],
// });
},
);
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 updateViewMutation({
// variables: {
// data: { name: view.name },
// where: { id: view.id },
// },
// refetchQueries: [getOperationName(GET_VIEWS) ?? ''],
// });
};
const deleteView = async (viewId: string) => {
await deleteViewMutation({
variables: { where: { id: viewId } },
refetchQueries: [getOperationName(GET_VIEWS) ?? ''],
});
const deleteView = async (_viewId: string) => {
// await deleteViewMutation({
// variables: { where: { id: viewId } },
// refetchQueries: [getOperationName(GET_VIEWS) ?? ''],
// });
};
return {

View File

@ -3,7 +3,6 @@ import { useSearchParams } from 'react-router-dom';
import { useRecoilCallback } from 'recoil';
import { v4 } from 'uuid';
import { savedTableColumnsFamilyState } from '@/ui/data/data-table/states/savedTableColumnsFamilyState';
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
import { ViewScopeInternalContext } from '../scopes/scope-internal-context/ViewScopeInternalContext';
@ -194,34 +193,23 @@ export const useView = (props?: UseViewProps) => {
);
const handleViewNameSubmit = useRecoilCallback(
({ snapshot, set }) =>
({ snapshot }) =>
async (name?: string) => {
const viewEditMode = snapshot
.getLoadable(viewEditModeScopedState({ scopeId }))
.getValue();
const currentViewFields = snapshot
.getLoadable(
currentViewFieldsScopedFamilyState({
scopeId,
familyKey: currentViewId || '',
}),
)
.getValue();
const isCreateModeOrEditMode = viewEditMode === 'create' || 'edit';
if (isCreateModeOrEditMode && name && currentViewFields) {
if (viewEditMode === 'create' && name) {
await createView(name);
set(savedTableColumnsFamilyState(currentViewId), currentViewFields);
}
},
[createView, currentViewId, scopeId],
[createView, scopeId],
);
return {
scopeId,
currentViewId,
setCurrentViewId,
updateCurrentView,
createView,

View File

@ -32,6 +32,13 @@ export const useViewStates = (viewScopeId?: string, viewId?: string) => {
scopeId,
);
const setViewObjectId = useSetRecoilScopedStateV2(
viewObjectIdScopeState,
scopeId,
);
const setViewType = useSetRecoilScopedStateV2(viewTypeScopedState, scopeId);
const familyItemId = viewId ? viewId : currentViewId;
const setViewEditMode = useSetRecoilScopedStateV2(
@ -41,13 +48,6 @@ export const useViewStates = (viewScopeId?: string, viewId?: string) => {
const setViews = useSetRecoilScopedStateV2(viewsScopedState, scopeId);
const setViewObjectId = useSetRecoilScopedStateV2(
viewObjectIdScopeState,
scopeId,
);
const setViewType = useSetRecoilScopedStateV2(viewTypeScopedState, scopeId);
const setEntityCountInCurrentView = useSetRecoilScopedStateV2(
entityCountInCurrentViewScopedState,
scopeId,
@ -116,11 +116,11 @@ export const useViewStates = (viewScopeId?: string, viewId?: string) => {
currentViewId,
setCurrentViewId,
setIsViewBarExpanded,
setViewObjectId,
setViewType,
setViews,
setViewEditMode,
setViewObjectId,
setViewType,
setEntityCountInCurrentView,
setAvailableSorts,

View File

@ -1,10 +1,10 @@
import { ReactNode } from 'react';
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
import { Filter } from '@/ui/data/filter/types/Filter';
import { Sort } from '@/ui/data/sort/types/Sort';
import { ViewField } from '../types/ViewField';
import { ViewScopeInitEffect } from './init-effect/ViewScopeInitEffect';
import { ViewScopeInternalContext } from './scope-internal-context/ViewScopeInternalContext';
@ -13,9 +13,7 @@ type ViewScopeProps = {
viewScopeId: string;
onViewSortsChange?: (sorts: Sort[]) => void | Promise<void>;
onViewFiltersChange?: (filters: Filter[]) => void | Promise<void>;
onViewFieldsChange?: (
fields: ColumnDefinition<FieldMetadata>[],
) => void | Promise<void>;
onViewFieldsChange?: (fields: ViewField[]) => void | Promise<void>;
};
export const ViewScope = ({

View File

@ -1,19 +1,16 @@
import { useEffect } from 'react';
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
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 = {
viewScopeId: string;
onViewSortsChange?: (sorts: Sort[]) => void | Promise<void>;
onViewFiltersChange?: (filters: Filter[]) => void | Promise<void>;
onViewFieldsChange?: (
fields: ColumnDefinition<FieldMetadata>[],
) => void | Promise<void>;
onViewFieldsChange?: (fields: ViewField[]) => void | Promise<void>;
};
export const ViewScopeInitEffect = ({
@ -30,9 +27,9 @@ export const ViewScopeInitEffect = ({
} = useViewInternalStates(viewScopeId, currentViewId);
useEffect(() => {
setOnViewSortsChange(onViewSortsChange);
setOnViewFiltersChange(onViewFiltersChange);
setOnViewFieldsChange(onViewFieldsChange);
setOnViewSortsChange(() => onViewSortsChange);
setOnViewFiltersChange(() => onViewFiltersChange);
setOnViewFieldsChange(() => onViewFieldsChange);
}, [
onViewFieldsChange,
onViewFiltersChange,

View File

@ -1,9 +1,9 @@
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
import { createScopedFamilyState } from '@/ui/utilities/recoil-scope/utils/createScopedFamilyState';
import { ViewField } from '../types/ViewField';
export const currentViewFieldsScopedFamilyState = createScopedFamilyState<
ColumnDefinition<FieldMetadata>[],
ViewField[],
string
>({
key: 'currentViewFieldsScopedFamilyState',

View File

@ -1,10 +1,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';
import { ViewField } from '../types/ViewField';
export const onViewFieldsChangeScopedState = createScopedState<
| ((fields: ColumnDefinition<FieldMetadata>[]) => void | Promise<void>)
| undefined
((fields: ViewField[]) => void | Promise<void>) | undefined
>({
key: 'onViewFieldsChangeScopedState',
defaultValue: undefined,

View File

@ -1,9 +1,9 @@
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
import { createScopedFamilyState } from '@/ui/utilities/recoil-scope/utils/createScopedFamilyState';
import { ViewField } from '../types/ViewField';
export const savedViewFieldsScopedFamilyState = createScopedFamilyState<
ColumnDefinition<FieldMetadata>[],
ViewField[],
string
>({
key: 'savedViewFieldsScopedFamilyState',

View File

@ -1,7 +1,6 @@
import { selectorFamily } from 'recoil';
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
import { ViewField } from '@/views/types/ViewField';
import { savedViewFieldsScopedFamilyState } from '../savedViewFieldsScopedFamilyState';
@ -24,8 +23,8 @@ export const savedViewFieldByKeyScopedFamilySelector = selectorFamily({
scopeId: viewScopeId,
familyKey: viewId,
}),
).reduce<Record<string, ColumnDefinition<FieldMetadata>>>(
(result, column) => ({ ...result, [column.key]: column }),
).reduce<Record<string, ViewField>>(
(result, column) => ({ ...result, [column.fieldId]: column }),
{},
);
},

View File

@ -1,5 +1,6 @@
import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
import { ViewType } from '~/generated/graphql';
import { ViewType } from '../types/ViewType';
export const viewTypeScopedState = createScopedState<ViewType>({
key: 'viewTypeScopedState',

View File

@ -1,8 +1,6 @@
export type ViewField = {
id: string;
objectId: string;
fieldId: string;
viewId: string;
position: number;
isVisible: boolean;
size: number;

View File

@ -1,11 +0,0 @@
import { FieldDefinition } from '@/ui/data/field/types/FieldDefinition';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
export type ViewFieldForVisibility = Pick<
FieldDefinition<FieldMetadata>,
'key' | 'name' | 'Icon' | 'infoTooltipContent'
> & {
isVisible?: boolean;
index: number;
size?: number | undefined;
};

View File

@ -0,0 +1,9 @@
export enum ViewFilterOperand {
Is = 'is',
IsNotNull = 'isNotNull',
IsNot = 'isNot',
LessThan = 'lessThan',
GreaterThan = 'greaterThan',
Contains = 'contains',
DoesNotContain = 'doesNotContain',
}

View File

@ -0,0 +1,4 @@
export enum ViewSortDirection {
Asc = 'asc',
Desc = 'desc',
}

View File

@ -0,0 +1,4 @@
export enum ViewType {
Table = 'table',
Kanban = 'kanban',
}

View File

@ -0,0 +1,16 @@
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
import { ViewField } from '../types/ViewField';
export const columnDefinitionsToViewFields = (
columnDefinitions: ColumnDefinition<FieldMetadata>[],
): ViewField[] => {
return columnDefinitions.map((columnDefinition) => ({
id: columnDefinition.viewFieldId || '',
fieldId: columnDefinition.fieldId,
position: columnDefinition.position,
size: columnDefinition.size,
isVisible: columnDefinition.isVisible ?? true,
}));
};

View File

@ -0,0 +1,36 @@
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
import { assertNotNull } from '~/utils/assert';
import { ViewField } from '../types/ViewField';
export const viewFieldsToColumnDefinitions = (
viewFields: ViewField[],
fieldsMetadata: ColumnDefinition<FieldMetadata>[],
): ColumnDefinition<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,
size: viewField.size ?? correspondingFieldMetadata.size,
isVisible: viewField.isVisible,
viewFieldId: viewField.id,
}
: null;
})
.filter(assertNotNull);
};