Various fixes on core views (#14093)
- Fix fragments - Add id to create inputs - Refresh core views - Fix kanban loading - Fix core views creation from current view --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
import { sortFavorites } from '@/favorites/utils/sortFavorites';
|
||||
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { FeatureFlagKey } from '~/generated/graphql';
|
||||
import { useFavoritesMetadata } from './useFavoritesMetadata';
|
||||
import { usePrefetchedFavoritesData } from './usePrefetchedFavoritesData';
|
||||
import { usePrefetchedFavoritesFoldersData } from './usePrefetchedFavoritesFoldersData';
|
||||
@@ -15,6 +18,13 @@ export const useFavoritesByFolder = () => {
|
||||
} = useFavoritesMetadata();
|
||||
|
||||
const prefetchViews = useRecoilValue(prefetchViewsState);
|
||||
const coreViews = useRecoilValue(coreViewsState);
|
||||
|
||||
const isCoreViewEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_CORE_VIEW_ENABLED,
|
||||
);
|
||||
|
||||
const views = isCoreViewEnabled ? coreViews : prefetchViews;
|
||||
|
||||
const favoritesByFolder = favoriteFolders.map((folder) => ({
|
||||
folderId: folder.id,
|
||||
@@ -24,7 +34,7 @@ export const useFavoritesByFolder = () => {
|
||||
favoriteRelationFields,
|
||||
getObjectRecordIdentifierByNameSingular,
|
||||
true,
|
||||
prefetchViews,
|
||||
views,
|
||||
objectMetadataItems,
|
||||
),
|
||||
}));
|
||||
|
||||
@@ -5,14 +5,23 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useMemo } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import {
|
||||
FeatureFlagKey,
|
||||
FieldMetadataType,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { usePrefetchedFavoritesData } from './usePrefetchedFavoritesData';
|
||||
|
||||
export const useWorkspaceFavorites = () => {
|
||||
const { workspaceFavorites } = usePrefetchedFavoritesData();
|
||||
const isCoreViewEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_CORE_VIEW_ENABLED,
|
||||
);
|
||||
const prefetchViews = useRecoilValue(prefetchViewsState);
|
||||
const coreViews = useRecoilValue(coreViewsState);
|
||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||
const { objectMetadataItem: favoriteObjectMetadataItem } =
|
||||
useObjectMetadataItem({
|
||||
@@ -32,6 +41,8 @@ export const useWorkspaceFavorites = () => {
|
||||
[favoriteObjectMetadataItem.fields],
|
||||
);
|
||||
|
||||
const views = isCoreViewEnabled ? coreViews : prefetchViews;
|
||||
|
||||
const sortedWorkspaceFavorites = useMemo(
|
||||
() =>
|
||||
sortFavorites(
|
||||
@@ -39,14 +50,14 @@ export const useWorkspaceFavorites = () => {
|
||||
favoriteRelationFieldMetadataItems,
|
||||
getObjectRecordIdentifierByNameSingular,
|
||||
false,
|
||||
prefetchViews,
|
||||
views,
|
||||
objectMetadataItems,
|
||||
),
|
||||
[
|
||||
workspaceFavorites,
|
||||
favoriteRelationFieldMetadataItems,
|
||||
getObjectRecordIdentifierByNameSingular,
|
||||
prefetchViews,
|
||||
views,
|
||||
objectMetadataItems,
|
||||
],
|
||||
);
|
||||
@@ -56,7 +67,7 @@ export const useWorkspaceFavorites = () => {
|
||||
);
|
||||
|
||||
const favoriteViewObjectMetadataIds = new Set(
|
||||
prefetchViews.reduce<string[]>((acc, view) => {
|
||||
views.reduce<string[]>((acc, view) => {
|
||||
if (workspaceFavoriteIds.has(view.id)) {
|
||||
acc.push(view.objectMetadataId);
|
||||
}
|
||||
|
||||
+16
-1
@@ -1,13 +1,28 @@
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { type View } from '@/views/types/View';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
import { extractFeatureFlagMapFromWorkspace } from '@/workspace/utils/extractFeatureFlagMapFromWorkspace';
|
||||
import { selector } from 'recoil';
|
||||
import { FeatureFlagKey } from '~/generated/graphql';
|
||||
|
||||
export const favoriteViewsWithMinimalDataSelector = selector<
|
||||
Pick<View, 'id' | 'name' | 'objectMetadataId' | 'icon'>[]
|
||||
>({
|
||||
key: 'favoriteViewsWithMinimalDataSelector',
|
||||
get: ({ get }) => {
|
||||
const views = get(prefetchViewsState);
|
||||
const prefetchedViews = get(prefetchViewsState);
|
||||
const coreViews = get(coreViewsState);
|
||||
|
||||
const currentWorkspace = get(currentWorkspaceState);
|
||||
const featureFlags = extractFeatureFlagMapFromWorkspace(currentWorkspace);
|
||||
|
||||
const isCoreViewEnabled = featureFlags[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
|
||||
|
||||
const views = isCoreViewEnabled
|
||||
? coreViews.map(convertCoreViewToView)
|
||||
: prefetchedViews;
|
||||
return views.map((view) => ({
|
||||
id: view.id,
|
||||
name: view.name,
|
||||
|
||||
@@ -27,10 +27,7 @@ export const sortFavorites = (
|
||||
): ProcessedFavorite[] => {
|
||||
return favorites
|
||||
.map((favorite) => {
|
||||
if (
|
||||
isDefined(favorite.viewId) &&
|
||||
isDefined(favorite.forWorkspaceMemberId)
|
||||
) {
|
||||
if (isDefined(favorite.viewId)) {
|
||||
const view = views.find((view) => view.id === favorite.viewId);
|
||||
|
||||
if (!isDefined(view)) {
|
||||
|
||||
+7
-5
@@ -16,15 +16,17 @@ const ORDERED_STANDARD_OBJECTS = [
|
||||
'note',
|
||||
];
|
||||
|
||||
type NavigationDrawerSectionForObjectMetadataItemsProps = {
|
||||
sectionTitle: string;
|
||||
isRemote: boolean;
|
||||
objectMetadataItems: ObjectMetadataItem[];
|
||||
};
|
||||
|
||||
export const NavigationDrawerSectionForObjectMetadataItems = ({
|
||||
sectionTitle,
|
||||
isRemote,
|
||||
objectMetadataItems,
|
||||
}: {
|
||||
sectionTitle: string;
|
||||
isRemote: boolean;
|
||||
objectMetadataItems: ObjectMetadataItem[];
|
||||
}) => {
|
||||
}: NavigationDrawerSectionForObjectMetadataItemsProps) => {
|
||||
const { toggleNavigationSection, isNavigationSectionOpenState } =
|
||||
useNavigationSection('Objects' + (isRemote ? 'Remote' : 'Workspace'));
|
||||
const isNavigationSectionOpen = useRecoilValue(isNavigationSectionOpenState);
|
||||
|
||||
+4
-4
@@ -95,8 +95,8 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
}
|
||||
const previouslySelectedKanbanField = availableFieldsForKanban.find(
|
||||
(fieldsForKanban) =>
|
||||
// TODO: replace with viewGroups.fieldMetadataId
|
||||
fieldsForKanban.id === currentView.kanbanFieldMetadataId,
|
||||
fieldsForKanban.id ===
|
||||
currentView.viewGroups[0].fieldMetadataId,
|
||||
);
|
||||
|
||||
const kanbanField = isDefined(previouslySelectedKanbanField)
|
||||
@@ -104,8 +104,8 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
: availableFieldsForKanban[0];
|
||||
|
||||
if (!isDefined(previouslySelectedKanbanField)) {
|
||||
// TODO: replace with viewGroups.fieldMetadataId
|
||||
updateCurrentViewParams.kanbanFieldMetadataId = kanbanField.id;
|
||||
updateCurrentViewParams.kanbanFieldMetadataId =
|
||||
currentView.viewGroups[0].fieldMetadataId;
|
||||
}
|
||||
|
||||
const hasViewGroups = currentView.viewGroups.some(
|
||||
|
||||
+1
-2
@@ -180,8 +180,7 @@ export const useLoadRecordIndexStates = () => {
|
||||
setRecordIndexViewType(view.type);
|
||||
setRecordIndexOpenRecordIn(view.openRecordIn);
|
||||
setRecordIndexViewKanbanFieldMetadataIdState(
|
||||
// TODO: replace with viewGroups.fieldMetadataId
|
||||
view.kanbanFieldMetadataId,
|
||||
view.viewGroups?.[0]?.fieldMetadataId,
|
||||
);
|
||||
const kanbanAggregateOperationFieldMetadataType =
|
||||
objectMetadataItem.fields?.find(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
@@ -15,6 +16,7 @@ import { useAreViewFiltersDifferentFromRecordFilters } from '@/views/hooks/useAr
|
||||
import { useAreViewSortsDifferentFromRecordSorts } from '@/views/hooks/useAreViewSortsDifferentFromRecordSorts';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { useIsViewAnyFieldFilterDifferentFromCurrentAnyFieldFilter } from '@/views/hooks/useIsViewAnyFieldFilterDifferentFromCurrentAnyFieldFilter';
|
||||
import { useRefreshCoreViews } from '@/views/hooks/useRefreshCoreViews';
|
||||
import { useSaveCurrentViewFiltersAndSorts } from '@/views/hooks/useSaveCurrentViewFiltersAndSorts';
|
||||
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
|
||||
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
||||
@@ -34,6 +36,10 @@ const StyledContainer = styled.div`
|
||||
export const UpdateViewButtonGroup = () => {
|
||||
const { saveCurrentViewFilterAndSorts } = useSaveCurrentViewFiltersAndSorts();
|
||||
|
||||
const { refreshCoreViews } = useRefreshCoreViews();
|
||||
|
||||
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||
|
||||
const { setViewPickerMode } = useViewPickerMode();
|
||||
|
||||
const currentViewId = useRecoilComponentValue(
|
||||
@@ -72,6 +78,7 @@ export const UpdateViewButtonGroup = () => {
|
||||
|
||||
const handleUpdateViewClick = async () => {
|
||||
await saveCurrentViewFilterAndSorts();
|
||||
await refreshCoreViews(objectMetadataItem.id);
|
||||
};
|
||||
|
||||
const { hasFiltersQueryParams } = useViewFromQueryParams();
|
||||
|
||||
@@ -9,7 +9,5 @@ export const VIEW_FIELD_FRAGMENT = gql`
|
||||
position
|
||||
size
|
||||
aggregateOperation
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -10,7 +10,5 @@ export const VIEW_FILTER_FRAGMENT = gql`
|
||||
positionInViewFilterGroup
|
||||
subFieldName
|
||||
viewId
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -7,7 +7,5 @@ export const VIEW_FILTER_GROUP_FRAGMENT = gql`
|
||||
logicalOperator
|
||||
positionInViewFilterGroup
|
||||
viewId
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -24,8 +24,6 @@ export const VIEW_FRAGMENT = gql`
|
||||
openRecordIn
|
||||
kanbanAggregateOperation
|
||||
kanbanAggregateOperationFieldMetadataId
|
||||
createdAt
|
||||
updatedAt
|
||||
anyFieldFilterValue
|
||||
viewFields {
|
||||
...ViewFieldFragment
|
||||
|
||||
@@ -8,7 +8,5 @@ export const VIEW_GROUP_FRAGMENT = gql`
|
||||
fieldValue
|
||||
position
|
||||
viewId
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -6,7 +6,5 @@ export const VIEW_SORT_FRAGMENT = gql`
|
||||
fieldMetadataId
|
||||
direction
|
||||
viewId
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
`;
|
||||
|
||||
+3
-2
@@ -100,7 +100,7 @@ export const usePersistViewFieldRecords = () => {
|
||||
apolloCoreClient.mutate({
|
||||
mutation: updateOneRecordMutation,
|
||||
variables: {
|
||||
idToUpdate: viewField.id,
|
||||
id: viewField.id,
|
||||
input: {
|
||||
isVisible: viewField.isVisible,
|
||||
position: viewField.position,
|
||||
@@ -151,6 +151,7 @@ export const usePersistViewFieldRecords = () => {
|
||||
mutation: CREATE_CORE_VIEW_FIELD,
|
||||
variables: {
|
||||
input: {
|
||||
id: viewField.id,
|
||||
fieldMetadataId: viewField.fieldMetadataId,
|
||||
viewId: view.id,
|
||||
isVisible: viewField.isVisible,
|
||||
@@ -191,7 +192,7 @@ export const usePersistViewFieldRecords = () => {
|
||||
apolloClient.mutate({
|
||||
mutation: UPDATE_CORE_VIEW_FIELD,
|
||||
variables: {
|
||||
idToUpdate: viewField.id,
|
||||
id: viewField.id,
|
||||
input: {
|
||||
isVisible: viewField.isVisible,
|
||||
position: viewField.position,
|
||||
|
||||
+5
-4
@@ -146,7 +146,7 @@ export const usePersistViewFilterGroupRecords = () => {
|
||||
apolloCoreClient.mutate<{ updateViewFilterGroup: ViewFilterGroup }>({
|
||||
mutation: updateOneRecordMutation,
|
||||
variables: {
|
||||
idToUpdate: viewFilterGroup.id,
|
||||
id: viewFilterGroup.id,
|
||||
input: {
|
||||
parentViewFilterGroupId:
|
||||
viewFilterGroup.parentViewFilterGroupId,
|
||||
@@ -194,7 +194,7 @@ export const usePersistViewFilterGroupRecords = () => {
|
||||
apolloCoreClient.mutate<{ destroyViewFilterGroup: ViewFilterGroup }>({
|
||||
mutation: destroyOneRecordMutation,
|
||||
variables: {
|
||||
idToDestroy: viewFilterGroupId,
|
||||
id: viewFilterGroupId,
|
||||
},
|
||||
update: (cache, { data }) => {
|
||||
const record = data?.destroyViewFilterGroup;
|
||||
@@ -231,6 +231,7 @@ export const usePersistViewFilterGroupRecords = () => {
|
||||
mutation: CREATE_CORE_VIEW_FILTER_GROUP,
|
||||
variables: {
|
||||
input: {
|
||||
id: viewFilterGroup.id,
|
||||
viewId: view.id,
|
||||
parentViewFilterGroupId: viewFilterGroup.parentViewFilterGroupId,
|
||||
logicalOperator: viewFilterGroup.logicalOperator,
|
||||
@@ -315,7 +316,7 @@ export const usePersistViewFilterGroupRecords = () => {
|
||||
apolloClient.mutate<{ updateCoreViewFilterGroup: ViewFilterGroup }>({
|
||||
mutation: UPDATE_CORE_VIEW_FILTER_GROUP,
|
||||
variables: {
|
||||
idToUpdate: viewFilterGroup.id,
|
||||
id: viewFilterGroup.id,
|
||||
input: {
|
||||
parentViewFilterGroupId:
|
||||
viewFilterGroup.parentViewFilterGroupId,
|
||||
@@ -357,7 +358,7 @@ export const usePersistViewFilterGroupRecords = () => {
|
||||
apolloClient.mutate<{ destroyCoreViewFilterGroup: ViewFilterGroup }>({
|
||||
mutation: DESTROY_CORE_VIEW_FILTER_GROUP,
|
||||
variables: {
|
||||
idToDestroy: viewFilterGroupId,
|
||||
id: viewFilterGroupId,
|
||||
},
|
||||
update: (cache, { data }) => {
|
||||
const record = data?.destroyCoreViewFilterGroup;
|
||||
|
||||
+5
-4
@@ -106,7 +106,7 @@ export const usePersistViewFilterRecords = () => {
|
||||
apolloCoreClient.mutate({
|
||||
mutation: updateOneRecordMutation,
|
||||
variables: {
|
||||
idToUpdate: viewFilter.id,
|
||||
id: viewFilter.id,
|
||||
input: {
|
||||
value: viewFilter.value,
|
||||
displayValue: viewFilter.displayValue,
|
||||
@@ -155,7 +155,7 @@ export const usePersistViewFilterRecords = () => {
|
||||
apolloCoreClient.mutate({
|
||||
mutation: destroyOneRecordMutation,
|
||||
variables: {
|
||||
idToDestroy: viewFilterId,
|
||||
id: viewFilterId,
|
||||
},
|
||||
update: (cache, { data }) => {
|
||||
const record = data?.['destroyViewFilter'];
|
||||
@@ -197,6 +197,7 @@ export const usePersistViewFilterRecords = () => {
|
||||
mutation: CREATE_CORE_VIEW_FILTER,
|
||||
variables: {
|
||||
input: {
|
||||
id: viewFilter.id,
|
||||
fieldMetadataId: viewFilter.fieldMetadataId,
|
||||
viewId: view.id,
|
||||
value: viewFilter.value,
|
||||
@@ -238,7 +239,7 @@ export const usePersistViewFilterRecords = () => {
|
||||
apolloClient.mutate({
|
||||
mutation: UPDATE_CORE_VIEW_FILTER,
|
||||
variables: {
|
||||
idToUpdate: viewFilter.id,
|
||||
id: viewFilter.id,
|
||||
input: {
|
||||
value: viewFilter.value,
|
||||
operand: convertViewFilterOperandToCore(viewFilter.operand),
|
||||
@@ -280,7 +281,7 @@ export const usePersistViewFilterRecords = () => {
|
||||
apolloClient.mutate({
|
||||
mutation: DESTROY_CORE_VIEW_FILTER,
|
||||
variables: {
|
||||
idToDestroy: viewFilterId,
|
||||
id: viewFilterId,
|
||||
},
|
||||
update: (cache, { data }) => {
|
||||
const record = data?.['destroyCoreViewFilter'];
|
||||
|
||||
+5
-2
@@ -60,7 +60,7 @@ export const usePersistViewGroupRecords = () => {
|
||||
apolloCoreClient.mutate<{ updateViewGroup: ViewGroup }>({
|
||||
mutation: updateOneRecordMutation,
|
||||
variables: {
|
||||
idToUpdate: viewGroup.id,
|
||||
id: viewGroup.id,
|
||||
input: {
|
||||
isVisible: viewGroup.isVisible,
|
||||
position: viewGroup.position,
|
||||
@@ -119,7 +119,10 @@ export const usePersistViewGroupRecords = () => {
|
||||
mutation: CREATE_CORE_VIEW_GROUP,
|
||||
variables: {
|
||||
input: {
|
||||
id: viewGroup.id,
|
||||
viewId,
|
||||
fieldMetadataId: viewGroup.fieldMetadataId,
|
||||
fieldValue: viewGroup.fieldValue,
|
||||
isVisible: viewGroup.isVisible,
|
||||
position: viewGroup.position,
|
||||
},
|
||||
@@ -183,7 +186,7 @@ export const usePersistViewGroupRecords = () => {
|
||||
apolloClient.mutate({
|
||||
mutation: DESTROY_CORE_VIEW_GROUP,
|
||||
variables: {
|
||||
idToDestroy: viewGroup.id,
|
||||
id: viewGroup.id,
|
||||
},
|
||||
}),
|
||||
),
|
||||
|
||||
@@ -100,7 +100,7 @@ export const usePersistViewSortRecords = () => {
|
||||
apolloCoreClient.mutate({
|
||||
mutation: updateOneRecordMutation,
|
||||
variables: {
|
||||
idToUpdate: viewSort.id,
|
||||
id: viewSort.id,
|
||||
input: {
|
||||
direction: viewSort.direction,
|
||||
},
|
||||
@@ -144,7 +144,7 @@ export const usePersistViewSortRecords = () => {
|
||||
apolloCoreClient.mutate({
|
||||
mutation: destroyOneRecordMutation,
|
||||
variables: {
|
||||
idToDestroy: viewSortId,
|
||||
id: viewSortId,
|
||||
},
|
||||
update: (cache, { data }) => {
|
||||
const record = data?.['destroyViewSort'];
|
||||
@@ -185,6 +185,7 @@ export const usePersistViewSortRecords = () => {
|
||||
mutation: CREATE_CORE_VIEW_SORT,
|
||||
variables: {
|
||||
input: {
|
||||
id: viewSort.id,
|
||||
fieldMetadataId: viewSort.fieldMetadataId,
|
||||
viewId: view.id,
|
||||
direction: convertViewSortDirectionToCore(viewSort.direction),
|
||||
@@ -222,7 +223,7 @@ export const usePersistViewSortRecords = () => {
|
||||
apolloClient.mutate({
|
||||
mutation: UPDATE_CORE_VIEW_SORT,
|
||||
variables: {
|
||||
idToUpdate: viewSort.id,
|
||||
id: viewSort.id,
|
||||
input: {
|
||||
direction: convertViewSortDirectionToCore(viewSort.direction),
|
||||
} satisfies Partial<CoreViewSort>,
|
||||
@@ -260,7 +261,7 @@ export const usePersistViewSortRecords = () => {
|
||||
apolloClient.mutate({
|
||||
mutation: DESTROY_CORE_VIEW_SORT,
|
||||
variables: {
|
||||
idToDestroy: viewSortId,
|
||||
id: viewSortId,
|
||||
},
|
||||
update: (cache, { data }) => {
|
||||
const record = data?.['destroyCoreViewSort'];
|
||||
|
||||
@@ -16,7 +16,7 @@ import { usePersistViewFilterGroupRecords } from '@/views/hooks/internal/usePers
|
||||
import { usePersistViewFilterRecords } from '@/views/hooks/internal/usePersistViewFilterRecords';
|
||||
import { usePersistViewGroupRecords } from '@/views/hooks/internal/usePersistViewGroupRecords';
|
||||
import { usePersistViewSortRecords } from '@/views/hooks/internal/usePersistViewSortRecords';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { useRefreshCoreViews } from '@/views/hooks/useRefreshCoreViews';
|
||||
import { isPersistingViewFieldsState } from '@/views/states/isPersistingViewFieldsState';
|
||||
import { type GraphQLView } from '@/views/types/GraphQLView';
|
||||
import { type View } from '@/views/types/View';
|
||||
@@ -33,12 +33,7 @@ import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
import {
|
||||
FeatureFlagKey,
|
||||
useCreateCoreViewMutation,
|
||||
useFindManyCoreViewsLazyQuery,
|
||||
} from '~/generated/graphql';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
import { FeatureFlagKey, useCreateCoreViewMutation } from '~/generated/graphql';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
@@ -70,7 +65,7 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
|
||||
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||
|
||||
const [findManyCoreViewsLazy] = useFindManyCoreViewsLazyQuery();
|
||||
const { refreshCoreViews } = useRefreshCoreViews();
|
||||
|
||||
const { findManyRecordsLazy } = useLazyFindManyRecords({
|
||||
objectNameSingular: CoreObjectNameSingular.View,
|
||||
@@ -135,6 +130,7 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
const result = await createCoreViewMutation({
|
||||
variables: {
|
||||
input: {
|
||||
id: id ?? v4(),
|
||||
name: name ?? sourceView.name,
|
||||
icon: icon ?? sourceView.icon,
|
||||
key: null,
|
||||
@@ -258,23 +254,7 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
}
|
||||
|
||||
if (isCoreViewEnabled) {
|
||||
const result = await findManyCoreViewsLazy({
|
||||
variables: {
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
},
|
||||
fetchPolicy: 'network-only',
|
||||
});
|
||||
|
||||
const existingCoreViews = snapshot
|
||||
.getLoadable(coreViewsState)
|
||||
.getValue();
|
||||
|
||||
if (
|
||||
isDefined(result.data?.getCoreViews) &&
|
||||
!isDeeplyEqual(existingCoreViews, result.data.getCoreViews)
|
||||
) {
|
||||
set(coreViewsState, result.data.getCoreViews);
|
||||
}
|
||||
await refreshCoreViews(objectMetadataItem.id);
|
||||
} else {
|
||||
await findManyRecordsLazy();
|
||||
}
|
||||
@@ -283,23 +263,23 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
return newViewId;
|
||||
},
|
||||
[
|
||||
anyFieldFilterValue,
|
||||
currentViewIdCallbackState,
|
||||
createOneRecord,
|
||||
isCoreViewEnabled,
|
||||
createViewFieldRecords,
|
||||
findManyRecordsLazy,
|
||||
createCoreViewMutation,
|
||||
anyFieldFilterValue,
|
||||
createOneRecord,
|
||||
objectMetadataItem.fields,
|
||||
objectMetadataItem.id,
|
||||
createViewGroupRecords,
|
||||
createViewSortRecords,
|
||||
createViewFilterRecords,
|
||||
createViewFilterGroupRecords,
|
||||
currentRecordFilterGroups,
|
||||
currentRecordFilters,
|
||||
currentRecordSorts,
|
||||
currentRecordFilterGroups,
|
||||
isCoreViewEnabled,
|
||||
createCoreViewMutation,
|
||||
findManyCoreViewsLazy,
|
||||
objectMetadataItem.id,
|
||||
createViewFilterGroupRecords,
|
||||
createViewFilterRecords,
|
||||
createViewSortRecords,
|
||||
refreshCoreViews,
|
||||
findManyRecordsLazy,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { coreViewsByObjectMetadataIdFamilySelector } from '@/views/states/coreViewsByObjectMetadataIdFamilySelector';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useFindManyCoreViewsLazyQuery } from '~/generated/graphql';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
export const useRefreshCoreViews = () => {
|
||||
const [findManyCoreViewsLazy] = useFindManyCoreViewsLazyQuery();
|
||||
|
||||
const refreshCoreViews = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (objectMetadataId: string) => {
|
||||
const result = await findManyCoreViewsLazy({
|
||||
variables: {
|
||||
objectMetadataId,
|
||||
},
|
||||
fetchPolicy: 'network-only',
|
||||
});
|
||||
|
||||
const coreViewsForObjectMetadataId = snapshot
|
||||
.getLoadable(
|
||||
coreViewsByObjectMetadataIdFamilySelector(objectMetadataId),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
if (
|
||||
isDefined(result.data?.getCoreViews) &&
|
||||
!isDeeplyEqual(coreViewsForObjectMetadataId, result.data.getCoreViews)
|
||||
) {
|
||||
set(
|
||||
coreViewsByObjectMetadataIdFamilySelector(objectMetadataId),
|
||||
result.data.getCoreViews,
|
||||
);
|
||||
}
|
||||
},
|
||||
[findManyCoreViewsLazy],
|
||||
);
|
||||
|
||||
return {
|
||||
refreshCoreViews,
|
||||
};
|
||||
};
|
||||
@@ -33,7 +33,7 @@ export const useSaveCurrentViewFields = () => {
|
||||
|
||||
set(isPersistingViewFieldsState, true);
|
||||
|
||||
const view = await getViewFromPrefetchState(currentViewId);
|
||||
const view = getViewFromPrefetchState(currentViewId);
|
||||
|
||||
if (isUndefinedOrNull(view)) {
|
||||
return;
|
||||
|
||||
+4
-4
@@ -71,11 +71,11 @@ export const useSaveRecordFilterGroupsToViewFilterGroups = () => {
|
||||
await deleteViewFilterGroupRecords(viewFilterGroupIdsToDelete);
|
||||
},
|
||||
[
|
||||
createViewFilterGroupRecords,
|
||||
deleteViewFilterGroupRecords,
|
||||
updateViewFilterGroupRecords,
|
||||
currentRecordFilterGroupsCallbackState,
|
||||
currentView,
|
||||
currentRecordFilterGroupsCallbackState,
|
||||
createViewFilterGroupRecords,
|
||||
updateViewFilterGroupRecords,
|
||||
deleteViewFilterGroupRecords,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@@ -65,11 +65,11 @@ export const useSaveRecordFiltersToViewFilters = () => {
|
||||
await deleteViewFilterRecords(viewFilterIdsToDelete);
|
||||
},
|
||||
[
|
||||
createViewFilterRecords,
|
||||
deleteViewFilterRecords,
|
||||
updateViewFilterRecords,
|
||||
currentRecordFiltersCallbackState,
|
||||
currentView,
|
||||
currentRecordFiltersCallbackState,
|
||||
createViewFilterRecords,
|
||||
updateViewFilterRecords,
|
||||
deleteViewFilterRecords,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@@ -63,11 +63,11 @@ export const useSaveRecordSortsToViewSorts = () => {
|
||||
await deleteViewSortRecords(viewSortIdsToDelete);
|
||||
},
|
||||
[
|
||||
createViewSortRecords,
|
||||
deleteViewSortRecords,
|
||||
updateViewSortRecords,
|
||||
currentRecordSortsCallbackState,
|
||||
currentView,
|
||||
currentRecordSortsCallbackState,
|
||||
createViewSortRecords,
|
||||
updateViewSortRecords,
|
||||
deleteViewSortRecords,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { type GraphQLView } from '@/views/types/GraphQLView';
|
||||
import { convertUpdateViewInputToCore } from '@/views/utils/convertUpdateViewInputToCore';
|
||||
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { FeatureFlagKey, useUpdateCoreViewMutation } from '~/generated/graphql';
|
||||
import { useRefreshCoreViews } from './useRefreshCoreViews';
|
||||
|
||||
export const useUpdateView = () => {
|
||||
const featureFlagMap = useFeatureFlagsMap();
|
||||
@@ -17,25 +19,39 @@ export const useUpdateView = () => {
|
||||
|
||||
const [updateOneCoreView] = useUpdateCoreViewMutation();
|
||||
|
||||
const { refreshCoreViews } = useRefreshCoreViews();
|
||||
|
||||
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||
|
||||
const updateView = useRecoilCallback(
|
||||
() => async (view: Partial<GraphQLView>) => {
|
||||
if (isDefined(view.id)) {
|
||||
if (isCoreViewEnabled) {
|
||||
await updateOneCoreView({
|
||||
variables: {
|
||||
id: view.id,
|
||||
input: convertUpdateViewInputToCore(view),
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await updateOneRecord({
|
||||
idToUpdate: view.id,
|
||||
updateOneRecordInput: view,
|
||||
});
|
||||
}
|
||||
if (!isDefined(view.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCoreViewEnabled) {
|
||||
await updateOneCoreView({
|
||||
variables: {
|
||||
id: view.id,
|
||||
input: convertUpdateViewInputToCore(view),
|
||||
},
|
||||
});
|
||||
|
||||
await refreshCoreViews(objectMetadataItem.id);
|
||||
} else {
|
||||
await updateOneRecord({
|
||||
idToUpdate: view.id,
|
||||
updateOneRecordInput: view,
|
||||
});
|
||||
}
|
||||
},
|
||||
[isCoreViewEnabled, updateOneCoreView, updateOneRecord],
|
||||
[
|
||||
isCoreViewEnabled,
|
||||
objectMetadataItem.id,
|
||||
refreshCoreViews,
|
||||
updateOneCoreView,
|
||||
updateOneRecord,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
import { selectorFamily } from 'recoil';
|
||||
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations';
|
||||
|
||||
export const coreViewsByObjectMetadataIdFamilySelector = selectorFamily<
|
||||
CoreViewWithRelations[],
|
||||
string
|
||||
>({
|
||||
key: 'coreViewsByObjectMetadataIdFamilySelector',
|
||||
get:
|
||||
(objectMetadataId: string) =>
|
||||
({ get }) => {
|
||||
const coreViews = get(coreViewsState);
|
||||
|
||||
return coreViews.filter(
|
||||
(view) => view.objectMetadataId === objectMetadataId,
|
||||
);
|
||||
},
|
||||
set:
|
||||
(objectMetadataId: string) =>
|
||||
({ get, set }, newViewsForObject) => {
|
||||
const currentCoreViews = get(coreViewsState);
|
||||
|
||||
const viewsFromOtherObjects = currentCoreViews.filter(
|
||||
(view) => view.objectMetadataId !== objectMetadataId,
|
||||
);
|
||||
|
||||
let updatedViewsForObject: CoreViewWithRelations[];
|
||||
|
||||
if (Array.isArray(newViewsForObject)) {
|
||||
updatedViewsForObject = newViewsForObject;
|
||||
} else {
|
||||
updatedViewsForObject = [];
|
||||
}
|
||||
|
||||
const newCoreViews = [...viewsFromOtherObjects, ...updatedViewsForObject];
|
||||
|
||||
set(coreViewsState, newCoreViews);
|
||||
},
|
||||
});
|
||||
@@ -17,11 +17,17 @@ export type CoreViewWithRelations = {
|
||||
key?: ViewKey | null;
|
||||
objectMetadataId: string;
|
||||
isCompact: boolean;
|
||||
viewFields: Omit<CoreViewField, 'workspaceId'>[];
|
||||
viewGroups: Omit<CoreViewGroup, 'workspaceId'>[];
|
||||
viewFilters: Omit<CoreViewFilter, 'workspaceId'>[];
|
||||
viewFilterGroups?: Omit<CoreViewFilterGroup, 'workspaceId'>[];
|
||||
viewSorts: Omit<CoreViewSort, 'workspaceId'>[];
|
||||
viewFields: Omit<CoreViewField, 'workspaceId' | 'createdAt' | 'updatedAt'>[];
|
||||
viewGroups: Omit<CoreViewGroup, 'workspaceId' | 'createdAt' | 'updatedAt'>[];
|
||||
viewFilters: Omit<
|
||||
CoreViewFilter,
|
||||
'workspaceId' | 'createdAt' | 'updatedAt'
|
||||
>[];
|
||||
viewFilterGroups?: Omit<
|
||||
CoreViewFilterGroup,
|
||||
'workspaceId' | 'createdAt' | 'updatedAt'
|
||||
>[];
|
||||
viewSorts: Omit<CoreViewSort, 'workspaceId' | 'createdAt' | 'updatedAt'>[];
|
||||
kanbanAggregateOperation?: AggregateOperations | null;
|
||||
kanbanAggregateOperationFieldMetadataId?: string | null;
|
||||
position: number;
|
||||
|
||||
@@ -4,7 +4,15 @@ import { type ViewField } from '@/views/types/ViewField';
|
||||
import { type CoreViewField } from '~/generated/graphql';
|
||||
|
||||
export const convertCoreViewFieldToViewField = (
|
||||
coreViewField: Omit<CoreViewField, 'workspaceId'>,
|
||||
coreViewField: Pick<
|
||||
CoreViewField,
|
||||
| 'id'
|
||||
| 'fieldMetadataId'
|
||||
| 'position'
|
||||
| 'isVisible'
|
||||
| 'size'
|
||||
| 'aggregateOperation'
|
||||
>,
|
||||
): ViewField => {
|
||||
const viewField: ViewField = {
|
||||
__typename: 'ViewField',
|
||||
|
||||
+8
-1
@@ -3,7 +3,14 @@ import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLog
|
||||
import { type CoreViewFilterGroup } from '~/generated/graphql';
|
||||
|
||||
export const convertCoreViewFilterGroupToViewFilterGroup = (
|
||||
coreViewFilterGroup: Omit<CoreViewFilterGroup, 'workspaceId'>,
|
||||
coreViewFilterGroup: Pick<
|
||||
CoreViewFilterGroup,
|
||||
| 'id'
|
||||
| 'viewId'
|
||||
| 'parentViewFilterGroupId'
|
||||
| 'logicalOperator'
|
||||
| 'positionInViewFilterGroup'
|
||||
>,
|
||||
): ViewFilterGroup => {
|
||||
return {
|
||||
__typename: 'ViewFilterGroup',
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
import { type CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName';
|
||||
import { type ViewFilter } from '@/views/types/ViewFilter';
|
||||
import { type CoreViewFilter } from '~/generated/graphql';
|
||||
import { convertViewFilterOperandFromCore } from '../utils/convertViewFilterOperandFromCore';
|
||||
|
||||
export const convertCoreViewFilterToViewFilter = (
|
||||
coreViewFilter: Omit<CoreViewFilter, 'workspaceId'>,
|
||||
coreViewFilter: Pick<
|
||||
CoreViewFilter,
|
||||
| 'id'
|
||||
| 'fieldMetadataId'
|
||||
| 'operand'
|
||||
| 'value'
|
||||
| 'viewFilterGroupId'
|
||||
| 'positionInViewFilterGroup'
|
||||
| 'subFieldName'
|
||||
>,
|
||||
): ViewFilter => {
|
||||
return {
|
||||
__typename: 'ViewFilter',
|
||||
@@ -18,11 +28,8 @@ export const convertCoreViewFilterToViewFilter = (
|
||||
typeof coreViewFilter.value === 'string'
|
||||
? coreViewFilter.value
|
||||
: JSON.stringify(coreViewFilter.value ?? ''),
|
||||
createdAt: coreViewFilter.createdAt,
|
||||
updatedAt: coreViewFilter.updatedAt,
|
||||
viewId: coreViewFilter.viewId,
|
||||
viewFilterGroupId: coreViewFilter.viewFilterGroupId ?? undefined,
|
||||
positionInViewFilterGroup: coreViewFilter.positionInViewFilterGroup ?? null,
|
||||
subFieldName: (coreViewFilter.subFieldName as any) ?? null,
|
||||
viewFilterGroupId: coreViewFilter.viewFilterGroupId,
|
||||
positionInViewFilterGroup: coreViewFilter.positionInViewFilterGroup,
|
||||
subFieldName: coreViewFilter.subFieldName as CompositeFieldSubFieldName,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,7 +2,10 @@ import { type ViewGroup } from '@/views/types/ViewGroup';
|
||||
import { type CoreViewGroup } from '~/generated/graphql';
|
||||
|
||||
export const convertCoreViewGroupToViewGroup = (
|
||||
coreViewGroup: Omit<CoreViewGroup, 'workspaceId'>,
|
||||
coreViewGroup: Pick<
|
||||
CoreViewGroup,
|
||||
'id' | 'fieldMetadataId' | 'isVisible' | 'fieldValue' | 'position'
|
||||
>,
|
||||
): ViewGroup => {
|
||||
return {
|
||||
__typename: 'ViewGroup',
|
||||
|
||||
@@ -2,7 +2,7 @@ import { type ViewSort } from '@/views/types/ViewSort';
|
||||
import { type CoreViewSort, ViewSortDirection } from '~/generated/graphql';
|
||||
|
||||
export const convertCoreViewSortToViewSort = (
|
||||
coreViewSort: Omit<CoreViewSort, 'workspaceId'>,
|
||||
coreViewSort: Pick<CoreViewSort, 'id' | 'fieldMetadataId' | 'direction'>,
|
||||
): ViewSort => {
|
||||
return {
|
||||
__typename: 'ViewSort',
|
||||
|
||||
@@ -6,7 +6,7 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
import { type UpdateViewInput } from '~/generated-metadata/graphql';
|
||||
|
||||
export const convertUpdateViewInputToCore = (
|
||||
view: Partial<GraphQLView>,
|
||||
view: Partial<GraphQLView & { __typename?: string }>,
|
||||
): UpdateViewInput => {
|
||||
const {
|
||||
key,
|
||||
@@ -17,6 +17,9 @@ export const convertUpdateViewInputToCore = (
|
||||
viewFilterGroups: _viewFilterGroups,
|
||||
viewGroups: _viewGroups,
|
||||
viewSorts: _viewSorts,
|
||||
kanbanFieldMetadataId: _kanbanFieldMetadataId,
|
||||
id: _id,
|
||||
__typename: _typename,
|
||||
...rest
|
||||
} = view;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { type ViewFilter } from '@/views/types/ViewFilter';
|
||||
import { compareStrictlyExceptForNullAndUndefined } from '~/utils/compareStrictlyExceptForNullAndUndefined';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { compareStrictlyExceptForNullAndUndefined } from '~/utils/compareStrictlyExceptForNullAndUndefined';
|
||||
|
||||
export const getViewFiltersToCreate = (
|
||||
currentViewFilters: ViewFilter[],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { type ViewFilter } from '@/views/types/ViewFilter';
|
||||
import { areViewFiltersEqual } from '@/views/utils/areViewFiltersEqual';
|
||||
import { compareStrictlyExceptForNullAndUndefined } from '~/utils/compareStrictlyExceptForNullAndUndefined';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { compareStrictlyExceptForNullAndUndefined } from '~/utils/compareStrictlyExceptForNullAndUndefined';
|
||||
|
||||
export const getViewFiltersToUpdate = (
|
||||
currentViewFilters: ViewFilter[],
|
||||
|
||||
Reference in New Issue
Block a user