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:
Raphaël Bosi
2025-08-29 11:20:56 +02:00
committed by GitHub
co-authored by Charles Bochet
parent 0e6ce123c9
commit 0bdd1c4803
56 changed files with 504 additions and 341 deletions
File diff suppressed because one or more lines are too long
+41 -42
View File
@@ -681,6 +681,7 @@ export type CreateServerlessFunctionInput = {
export type CreateViewFieldInput = {
aggregateOperation?: InputMaybe<AggregateOperations>;
fieldMetadataId: Scalars['UUID'];
id?: InputMaybe<Scalars['UUID']>;
isVisible?: InputMaybe<Scalars['Boolean']>;
position?: InputMaybe<Scalars['Float']>;
size?: InputMaybe<Scalars['Float']>;
@@ -688,6 +689,7 @@ export type CreateViewFieldInput = {
};
export type CreateViewFilterGroupInput = {
id?: InputMaybe<Scalars['UUID']>;
logicalOperator?: InputMaybe<ViewFilterGroupLogicalOperator>;
parentViewFilterGroupId?: InputMaybe<Scalars['UUID']>;
positionInViewFilterGroup?: InputMaybe<Scalars['Float']>;
@@ -696,6 +698,7 @@ export type CreateViewFilterGroupInput = {
export type CreateViewFilterInput = {
fieldMetadataId: Scalars['UUID'];
id?: InputMaybe<Scalars['UUID']>;
operand?: InputMaybe<ViewFilterOperand>;
positionInViewFilterGroup?: InputMaybe<Scalars['Float']>;
subFieldName?: InputMaybe<Scalars['String']>;
@@ -707,6 +710,7 @@ export type CreateViewFilterInput = {
export type CreateViewGroupInput = {
fieldMetadataId: Scalars['UUID'];
fieldValue: Scalars['String'];
id?: InputMaybe<Scalars['UUID']>;
isVisible?: InputMaybe<Scalars['Boolean']>;
position?: InputMaybe<Scalars['Float']>;
viewId: Scalars['UUID'];
@@ -715,6 +719,7 @@ export type CreateViewGroupInput = {
export type CreateViewInput = {
anyFieldFilterValue?: InputMaybe<Scalars['String']>;
icon: Scalars['String'];
id?: InputMaybe<Scalars['UUID']>;
isCompact?: InputMaybe<Scalars['Boolean']>;
kanbanAggregateOperation?: InputMaybe<AggregateOperations>;
kanbanAggregateOperationFieldMetadataId?: InputMaybe<Scalars['UUID']>;
@@ -729,6 +734,7 @@ export type CreateViewInput = {
export type CreateViewSortInput = {
direction?: InputMaybe<ViewSortDirection>;
fieldMetadataId: Scalars['UUID'];
id?: InputMaybe<Scalars['UUID']>;
viewId: Scalars['UUID'];
};
@@ -3130,6 +3136,7 @@ export type UpdateViewFieldInput = {
};
export type UpdateViewFilterGroupInput = {
id?: InputMaybe<Scalars['UUID']>;
logicalOperator?: InputMaybe<ViewFilterGroupLogicalOperator>;
parentViewFilterGroupId?: InputMaybe<Scalars['UUID']>;
positionInViewFilterGroup?: InputMaybe<Scalars['Float']>;
@@ -3138,6 +3145,7 @@ export type UpdateViewFilterGroupInput = {
export type UpdateViewFilterInput = {
fieldMetadataId?: InputMaybe<Scalars['UUID']>;
id?: InputMaybe<Scalars['UUID']>;
operand?: InputMaybe<ViewFilterOperand>;
positionInViewFilterGroup?: InputMaybe<Scalars['Float']>;
subFieldName?: InputMaybe<Scalars['String']>;
@@ -3149,6 +3157,7 @@ export type UpdateViewFilterInput = {
export type UpdateViewGroupInput = {
fieldMetadataId?: InputMaybe<Scalars['UUID']>;
fieldValue?: InputMaybe<Scalars['String']>;
id?: InputMaybe<Scalars['UUID']>;
isVisible?: InputMaybe<Scalars['Boolean']>;
position?: InputMaybe<Scalars['Float']>;
viewId?: InputMaybe<Scalars['UUID']>;
@@ -3157,6 +3166,7 @@ export type UpdateViewGroupInput = {
export type UpdateViewInput = {
anyFieldFilterValue?: InputMaybe<Scalars['String']>;
icon?: InputMaybe<Scalars['String']>;
id?: InputMaybe<Scalars['UUID']>;
isCompact?: InputMaybe<Scalars['Boolean']>;
kanbanAggregateOperation?: InputMaybe<AggregateOperations>;
kanbanAggregateOperationFieldMetadataId?: InputMaybe<Scalars['UUID']>;
@@ -3171,6 +3181,7 @@ export type UpdateViewInput = {
export type UpdateViewSortInput = {
direction?: InputMaybe<ViewSortDirection>;
fieldMetadataId?: InputMaybe<Scalars['UUID']>;
id?: InputMaybe<Scalars['UUID']>;
viewId?: InputMaybe<Scalars['UUID']>;
};
@@ -3592,59 +3603,59 @@ export type OnDbEventSubscriptionVariables = Exact<{
export type OnDbEventSubscription = { __typename?: 'Subscription', onDbEvent: { __typename?: 'OnDbEventDTO', eventDate: string, action: DatabaseEventAction, objectNameSingular: string, updatedFields?: Array<string> | null, record: any } };
export type ViewFieldFragmentFragment = { __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string };
export type ViewFieldFragmentFragment = { __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null };
export type ViewFilterFragmentFragment = { __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string };
export type ViewFilterFragmentFragment = { __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any };
export type ViewFilterGroupFragmentFragment = { __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any, createdAt: string, updatedAt: string };
export type ViewFilterGroupFragmentFragment = { __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any };
export type ViewFragmentFragment = { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any, createdAt: string, updatedAt: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any, createdAt: string, updatedAt: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string }> };
export type ViewFragmentFragment = { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any }> };
export type ViewGroupFragmentFragment = { __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string };
export type ViewGroupFragmentFragment = { __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any };
export type ViewSortFragmentFragment = { __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any, createdAt: string, updatedAt: string };
export type ViewSortFragmentFragment = { __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any };
export type CreateCoreViewMutationVariables = Exact<{
input: CreateViewInput;
}>;
export type CreateCoreViewMutation = { __typename?: 'Mutation', createCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any, createdAt: string, updatedAt: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any, createdAt: string, updatedAt: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string }> } };
export type CreateCoreViewMutation = { __typename?: 'Mutation', createCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any }> } };
export type CreateCoreViewFieldMutationVariables = Exact<{
input: CreateViewFieldInput;
}>;
export type CreateCoreViewFieldMutation = { __typename?: 'Mutation', createCoreViewField: { __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string } };
export type CreateCoreViewFieldMutation = { __typename?: 'Mutation', createCoreViewField: { __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null } };
export type CreateCoreViewFilterMutationVariables = Exact<{
input: CreateViewFilterInput;
}>;
export type CreateCoreViewFilterMutation = { __typename?: 'Mutation', createCoreViewFilter: { __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string } };
export type CreateCoreViewFilterMutation = { __typename?: 'Mutation', createCoreViewFilter: { __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any } };
export type CreateCoreViewFilterGroupMutationVariables = Exact<{
input: CreateViewFilterGroupInput;
}>;
export type CreateCoreViewFilterGroupMutation = { __typename?: 'Mutation', createCoreViewFilterGroup: { __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any, createdAt: string, updatedAt: string } };
export type CreateCoreViewFilterGroupMutation = { __typename?: 'Mutation', createCoreViewFilterGroup: { __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any } };
export type CreateCoreViewGroupMutationVariables = Exact<{
input: CreateViewGroupInput;
}>;
export type CreateCoreViewGroupMutation = { __typename?: 'Mutation', createCoreViewGroup: { __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string } };
export type CreateCoreViewGroupMutation = { __typename?: 'Mutation', createCoreViewGroup: { __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any } };
export type CreateCoreViewSortMutationVariables = Exact<{
input: CreateViewSortInput;
}>;
export type CreateCoreViewSortMutation = { __typename?: 'Mutation', createCoreViewSort: { __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any, createdAt: string, updatedAt: string } };
export type CreateCoreViewSortMutation = { __typename?: 'Mutation', createCoreViewSort: { __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any } };
export type DeleteCoreViewMutationVariables = Exact<{
id: Scalars['String'];
@@ -3736,7 +3747,7 @@ export type UpdateCoreViewMutationVariables = Exact<{
}>;
export type UpdateCoreViewMutation = { __typename?: 'Mutation', updateCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any, createdAt: string, updatedAt: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any, createdAt: string, updatedAt: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string }> } };
export type UpdateCoreViewMutation = { __typename?: 'Mutation', updateCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any }> } };
export type UpdateCoreViewFieldMutationVariables = Exact<{
id: Scalars['String'];
@@ -3744,7 +3755,7 @@ export type UpdateCoreViewFieldMutationVariables = Exact<{
}>;
export type UpdateCoreViewFieldMutation = { __typename?: 'Mutation', updateCoreViewField: { __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string } };
export type UpdateCoreViewFieldMutation = { __typename?: 'Mutation', updateCoreViewField: { __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null } };
export type UpdateCoreViewFilterMutationVariables = Exact<{
id: Scalars['String'];
@@ -3752,7 +3763,7 @@ export type UpdateCoreViewFilterMutationVariables = Exact<{
}>;
export type UpdateCoreViewFilterMutation = { __typename?: 'Mutation', updateCoreViewFilter: { __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string } };
export type UpdateCoreViewFilterMutation = { __typename?: 'Mutation', updateCoreViewFilter: { __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any } };
export type UpdateCoreViewFilterGroupMutationVariables = Exact<{
id: Scalars['String'];
@@ -3760,7 +3771,7 @@ export type UpdateCoreViewFilterGroupMutationVariables = Exact<{
}>;
export type UpdateCoreViewFilterGroupMutation = { __typename?: 'Mutation', updateCoreViewFilterGroup: { __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any, createdAt: string, updatedAt: string } };
export type UpdateCoreViewFilterGroupMutation = { __typename?: 'Mutation', updateCoreViewFilterGroup: { __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any } };
export type UpdateCoreViewGroupMutationVariables = Exact<{
id: Scalars['String'];
@@ -3768,7 +3779,7 @@ export type UpdateCoreViewGroupMutationVariables = Exact<{
}>;
export type UpdateCoreViewGroupMutation = { __typename?: 'Mutation', updateCoreViewGroup: { __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string } };
export type UpdateCoreViewGroupMutation = { __typename?: 'Mutation', updateCoreViewGroup: { __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any } };
export type UpdateCoreViewSortMutationVariables = Exact<{
id: Scalars['String'];
@@ -3776,91 +3787,91 @@ export type UpdateCoreViewSortMutationVariables = Exact<{
}>;
export type UpdateCoreViewSortMutation = { __typename?: 'Mutation', updateCoreViewSort: { __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any, createdAt: string, updatedAt: string } };
export type UpdateCoreViewSortMutation = { __typename?: 'Mutation', updateCoreViewSort: { __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any } };
export type FindManyCoreViewFieldsQueryVariables = Exact<{
viewId: Scalars['String'];
}>;
export type FindManyCoreViewFieldsQuery = { __typename?: 'Query', getCoreViewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string }> };
export type FindManyCoreViewFieldsQuery = { __typename?: 'Query', getCoreViewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null }> };
export type FindManyCoreViewFilterGroupsQueryVariables = Exact<{
viewId?: InputMaybe<Scalars['String']>;
}>;
export type FindManyCoreViewFilterGroupsQuery = { __typename?: 'Query', getCoreViewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any, createdAt: string, updatedAt: string }> };
export type FindManyCoreViewFilterGroupsQuery = { __typename?: 'Query', getCoreViewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }> };
export type FindManyCoreViewFiltersQueryVariables = Exact<{
viewId?: InputMaybe<Scalars['String']>;
}>;
export type FindManyCoreViewFiltersQuery = { __typename?: 'Query', getCoreViewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string }> };
export type FindManyCoreViewFiltersQuery = { __typename?: 'Query', getCoreViewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any }> };
export type FindManyCoreViewGroupsQueryVariables = Exact<{
viewId?: InputMaybe<Scalars['String']>;
}>;
export type FindManyCoreViewGroupsQuery = { __typename?: 'Query', getCoreViewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string }> };
export type FindManyCoreViewGroupsQuery = { __typename?: 'Query', getCoreViewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any }> };
export type FindManyCoreViewSortsQueryVariables = Exact<{
viewId?: InputMaybe<Scalars['String']>;
}>;
export type FindManyCoreViewSortsQuery = { __typename?: 'Query', getCoreViewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any, createdAt: string, updatedAt: string }> };
export type FindManyCoreViewSortsQuery = { __typename?: 'Query', getCoreViewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }> };
export type FindManyCoreViewsQueryVariables = Exact<{
objectMetadataId?: InputMaybe<Scalars['String']>;
}>;
export type FindManyCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any, createdAt: string, updatedAt: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any, createdAt: string, updatedAt: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string }> }> };
export type FindManyCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any }> }> };
export type FindOneCoreViewQueryVariables = Exact<{
id: Scalars['String'];
}>;
export type FindOneCoreViewQuery = { __typename?: 'Query', getCoreView?: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any, createdAt: string, updatedAt: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any, createdAt: string, updatedAt: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string }> } | null };
export type FindOneCoreViewQuery = { __typename?: 'Query', getCoreView?: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any }> } | null };
export type FindOneCoreViewFieldQueryVariables = Exact<{
id: Scalars['String'];
}>;
export type FindOneCoreViewFieldQuery = { __typename?: 'Query', getCoreViewField?: { __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string } | null };
export type FindOneCoreViewFieldQuery = { __typename?: 'Query', getCoreViewField?: { __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null } | null };
export type FindOneCoreViewFilterQueryVariables = Exact<{
id: Scalars['String'];
}>;
export type FindOneCoreViewFilterQuery = { __typename?: 'Query', getCoreViewFilter?: { __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string } | null };
export type FindOneCoreViewFilterQuery = { __typename?: 'Query', getCoreViewFilter?: { __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any } | null };
export type FindOneCoreViewFilterGroupQueryVariables = Exact<{
id: Scalars['String'];
}>;
export type FindOneCoreViewFilterGroupQuery = { __typename?: 'Query', getCoreViewFilterGroup?: { __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any, createdAt: string, updatedAt: string } | null };
export type FindOneCoreViewFilterGroupQuery = { __typename?: 'Query', getCoreViewFilterGroup?: { __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any } | null };
export type FindOneCoreViewGroupQueryVariables = Exact<{
id: Scalars['String'];
}>;
export type FindOneCoreViewGroupQuery = { __typename?: 'Query', getCoreViewGroup?: { __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string } | null };
export type FindOneCoreViewGroupQuery = { __typename?: 'Query', getCoreViewGroup?: { __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any } | null };
export type FindOneCoreViewSortQueryVariables = Exact<{
id: Scalars['String'];
}>;
export type FindOneCoreViewSortQuery = { __typename?: 'Query', getCoreViewSort?: { __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any, createdAt: string, updatedAt: string } | null };
export type FindOneCoreViewSortQuery = { __typename?: 'Query', getCoreViewSort?: { __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any } | null };
export const ViewFieldFragmentFragmentDoc = gql`
fragment ViewFieldFragment on CoreViewField {
@@ -3871,8 +3882,6 @@ export const ViewFieldFragmentFragmentDoc = gql`
position
size
aggregateOperation
createdAt
updatedAt
}
`;
export const ViewFilterFragmentFragmentDoc = gql`
@@ -3885,8 +3894,6 @@ export const ViewFilterFragmentFragmentDoc = gql`
positionInViewFilterGroup
subFieldName
viewId
createdAt
updatedAt
}
`;
export const ViewFilterGroupFragmentFragmentDoc = gql`
@@ -3896,8 +3903,6 @@ export const ViewFilterGroupFragmentFragmentDoc = gql`
logicalOperator
positionInViewFilterGroup
viewId
createdAt
updatedAt
}
`;
export const ViewSortFragmentFragmentDoc = gql`
@@ -3906,8 +3911,6 @@ export const ViewSortFragmentFragmentDoc = gql`
fieldMetadataId
direction
viewId
createdAt
updatedAt
}
`;
export const ViewGroupFragmentFragmentDoc = gql`
@@ -3918,8 +3921,6 @@ export const ViewGroupFragmentFragmentDoc = gql`
fieldValue
position
viewId
createdAt
updatedAt
}
`;
export const ViewFragmentFragmentDoc = gql`
@@ -3935,8 +3936,6 @@ export const ViewFragmentFragmentDoc = gql`
openRecordIn
kanbanAggregateOperation
kanbanAggregateOperationFieldMetadataId
createdAt
updatedAt
anyFieldFilterValue
viewFields {
...ViewFieldFragment
@@ -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);
}
@@ -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)) {
@@ -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);
@@ -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(
@@ -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
}
`;
@@ -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,
@@ -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;
@@ -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'];
@@ -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;
@@ -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 {
@@ -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',
@@ -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[],
@@ -22,6 +22,6 @@ export class FileDTO {
@Field(() => UUIDScalarType, { nullable: true })
messageId?: string;
@Field()
@Field(() => Date, { nullable: false })
createdAt: Date;
}
@@ -5,6 +5,9 @@ import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/
@InputType()
export class CreateViewFieldInput {
@Field(() => UUIDScalarType, { nullable: true })
id?: string;
@Field(() => UUIDScalarType, { nullable: false })
fieldMetadataId: string;
@@ -5,6 +5,9 @@ import { ViewFilterGroupLogicalOperator } from 'src/engine/core-modules/view/enu
@InputType()
export class CreateViewFilterGroupInput {
@Field(() => UUIDScalarType, { nullable: true })
id?: string;
@Field(() => UUIDScalarType, { nullable: true })
parentViewFilterGroupId?: string;
@@ -8,6 +8,9 @@ import { ViewFilterValue } from 'src/engine/core-modules/view/types/view-filter-
@InputType()
export class CreateViewFilterInput {
@Field(() => UUIDScalarType, { nullable: true })
id?: string;
@Field(() => UUIDScalarType, { nullable: false })
fieldMetadataId: string;
@@ -1,9 +1,12 @@
import { InputType, Field } from '@nestjs/graphql';
import { Field, InputType } from '@nestjs/graphql';
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
@InputType()
export class CreateViewGroupInput {
@Field(() => UUIDScalarType, { nullable: true })
id?: string;
@Field(() => UUIDScalarType, { nullable: false })
fieldMetadataId: string;
@@ -5,6 +5,9 @@ import { ViewSortDirection } from 'src/engine/core-modules/view/enums/view-sort-
@InputType()
export class CreateViewSortInput {
@Field(() => UUIDScalarType, { nullable: true })
id?: string;
@Field(() => UUIDScalarType, { nullable: false })
fieldMetadataId: string;
@@ -8,6 +8,9 @@ import { ViewType } from 'src/engine/core-modules/view/enums/view-type.enum';
@InputType()
export class CreateViewInput {
@Field(() => UUIDScalarType, { nullable: true })
id?: string;
@Field({ nullable: false })
name: string;
@@ -1,7 +1,7 @@
import { Test, type TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { getDataSourceToken, getRepositoryToken } from '@nestjs/typeorm';
import { type Repository } from 'typeorm';
import { type DataSource, type Repository } from 'typeorm';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
@@ -33,13 +33,22 @@ describe('WorkspaceManagerService', () => {
let workspaceDataSourceService: WorkspaceDataSourceService;
let roleTargetsRepository: Repository<RoleTargetsEntity>;
let roleRepository: Repository<RoleEntity>;
let mockDataSource: jest.Mocked<DataSource>;
beforeEach(async () => {
mockDataSource = {
transaction: jest.fn(),
} as any;
const module: TestingModule = await Test.createTestingModule({
providers: [
WorkspaceManagerService,
WorkspaceMigrationService,
DataSourceService,
{
provide: getDataSourceToken(),
useValue: mockDataSource,
},
{
provide: getRepositoryToken(Workspace),
useValue: {},
@@ -6,7 +6,6 @@ import { DataSource } from 'typeorm';
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
import { computeTableName } from 'src/engine/utils/compute-table-name.util';
import { shouldSeedWorkspaceFavorite } from 'src/engine/utils/should-seed-workspace-favorite';
import {
CALENDAR_CHANNEL_DATA_SEED_COLUMNS,
CALENDAR_CHANNEL_DATA_SEEDS,
@@ -88,9 +87,7 @@ import {
WORKSPACE_MEMBER_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/workspace-member-data-seeds.constant';
import { TimelineActivitySeederService } from 'src/engine/workspace-manager/dev-seeder/data/services/timeline-activity-seeder.service';
import { prefillViews } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-views';
import { prefillWorkflows } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-workflows';
import { prefillWorkspaceFavorites } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-workspace-favorites';
const RECORD_SEEDS_CONFIGS = [
{
@@ -242,28 +239,7 @@ export class DevSeederDataService {
workspaceId,
});
const viewDefinitionsWithId = await prefillViews(
entityManager,
schemaName,
objectMetadataItems.filter((item) => !item.isCustom),
);
await prefillWorkflows(entityManager, schemaName, objectMetadataItems);
await prefillWorkspaceFavorites(
viewDefinitionsWithId
.filter(
(view) =>
view.key === 'INDEX' &&
shouldSeedWorkspaceFavorite(
view.objectMetadataId,
objectMetadataItems,
),
)
.map((view) => view.id),
entityManager,
schemaName,
);
},
);
}
@@ -104,7 +104,7 @@ export class DevSeederMetadataService {
});
}
await this.seedCoreViews(workspaceId);
await this.seedCoreViews({ workspaceId, dataSourceMetadata });
}
private async seedCustomObject({
@@ -152,14 +152,21 @@ export class DevSeederMetadataService {
);
}
private async seedCoreViews(workspaceId: string): Promise<void> {
private async seedCoreViews({
workspaceId,
dataSourceMetadata,
}: {
workspaceId: string;
dataSourceMetadata: DataSourceEntity;
}): Promise<void> {
const createdObjectMetadata =
await this.objectMetadataService.findManyWithinWorkspace(workspaceId);
await prefillCoreViews(
this.coreDataSource,
await prefillCoreViews({
coreDataSource: this.coreDataSource,
workspaceId,
createdObjectMetadata,
);
objectMetadataItems: createdObjectMetadata,
schemaName: dataSourceMetadata.schema,
});
}
}
@@ -1,5 +1,6 @@
import { type EntityManager } from 'typeorm';
import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type';
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
export const AIRBNB_ID = 'c776ee49-f608-4a77-8cc8-6fe96ae1e43f';
export const ANTHROPIC_ID = 'f45ee421-8a3e-4aa5-a1cf-7207cc6754e1';
@@ -8,13 +9,11 @@ export const FIGMA_ID = '9d5bcf43-7d38-4e88-82cb-d6d4ce638bf0';
export const NOTION_ID = '06290608-8bf0-4806-99ae-a715a6a93fad';
export const prefillCompanies = async (
entityManager: WorkspaceEntityManager,
entityManager: EntityManager,
schemaName: string,
) => {
await entityManager
.createQueryBuilder(undefined, undefined, undefined, {
shouldBypassPermissionChecks: true,
})
.createQueryBuilder()
.insert()
.into(`${schemaName}.company`, [
'id',
@@ -12,12 +12,15 @@ import { ViewKey } from 'src/engine/core-modules/view/enums/view-key.enum';
import { ViewOpenRecordIn } from 'src/engine/core-modules/view/enums/view-open-record-in';
import { ViewType } from 'src/engine/core-modules/view/enums/view-type.enum';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
import { shouldSeedWorkspaceFavorite } from 'src/engine/utils/should-seed-workspace-favorite';
import { prefillWorkspaceFavorites } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-workspace-favorites';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { companiesAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/companies-all.view';
import { dashboardsAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/dashboards-all.view';
import { notesAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/notes-all.view';
import { opportunitiesAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/opportunities-all.view';
import { opportunitiesTableByStageView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/opportunity-table-by-stage.view';
import { opportunitiesByStageView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/opportunity-by-stage.view';
import { peopleAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/people-all.view';
import { tasksAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-all.view';
import { tasksAssignedToMeView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-assigned-to-me';
@@ -28,17 +31,26 @@ import { workflowsAllView } from 'src/engine/workspace-manager/standard-objects-
import { ViewOpenRecordInType } from 'src/modules/view/standard-objects/view.workspace-entity';
import { convertViewFilterOperandToCoreOperand } from 'src/modules/view/utils/convert-view-filter-operand-to-core-operand.util';
export const prefillCoreViews = async (
coreDataSource: DataSource,
workspaceId: string,
objectMetadataItems: ObjectMetadataEntity[],
featureFlags?: Record<string, boolean>,
): Promise<ViewEntity[]> => {
type PrefillCoreViewsArgs = {
coreDataSource: DataSource;
workspaceId: string;
objectMetadataItems: ObjectMetadataEntity[];
schemaName: string;
featureFlags?: Record<string, boolean>;
};
export const prefillCoreViews = async ({
coreDataSource,
workspaceId,
objectMetadataItems,
schemaName,
featureFlags,
}: PrefillCoreViewsArgs): Promise<ViewEntity[]> => {
const views = [
companiesAllView(objectMetadataItems, true),
peopleAllView(objectMetadataItems, true),
opportunitiesAllView(objectMetadataItems, true),
opportunitiesTableByStageView(objectMetadataItems, true),
opportunitiesByStageView(objectMetadataItems, true),
notesAllView(objectMetadataItems, true),
tasksAllView(objectMetadataItems, true),
tasksAssignedToMeView(objectMetadataItems, true),
@@ -61,6 +73,21 @@ export const prefillCoreViews = async (
const createdViews = await createCoreViews(queryRunner, workspaceId, views);
await prefillWorkspaceFavorites(
createdViews
.filter(
(view) =>
view.key === 'INDEX' &&
shouldSeedWorkspaceFavorite(
view.objectMetadataId,
objectMetadataItems,
),
)
.map((view) => view.id),
queryRunner.manager as WorkspaceEntityManager,
schemaName,
);
await queryRunner.commitTransaction();
return createdViews;
@@ -1,5 +1,6 @@
import { type EntityManager } from 'typeorm';
import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type';
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
import {
AIRBNB_ID,
ANTHROPIC_ID,
@@ -9,13 +10,11 @@ import {
} from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-companies';
export const prefillPeople = async (
entityManager: WorkspaceEntityManager,
entityManager: EntityManager,
schemaName: string,
) => {
await entityManager
.createQueryBuilder(undefined, undefined, undefined, {
shouldBypassPermissionChecks: true,
})
.createQueryBuilder()
.insert()
.into(`${schemaName}.person`, [
'nameFirstName',
@@ -1,8 +1,8 @@
import { type EntityManager } from 'typeorm';
import { v4 } from 'uuid';
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { companiesAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/companies-all.view';
import { customAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/custom-all.view';
@@ -19,7 +19,7 @@ import { workflowVersionsAllView } from 'src/engine/workspace-manager/standard-o
import { workflowsAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/workflows-all.view';
export const prefillViews = async (
entityManager: WorkspaceEntityManager,
entityManager: EntityManager,
schemaName: string,
objectMetadataItems: ObjectMetadataEntity[],
featureFlags?: Record<string, boolean>,
@@ -55,7 +55,7 @@ export const prefillViews = async (
};
const createWorkspaceViews = async (
entityManager: WorkspaceEntityManager,
entityManager: EntityManager,
schemaName: string,
viewDefinitions: ViewDefinition[],
) => {
@@ -65,9 +65,7 @@ const createWorkspaceViews = async (
}));
await entityManager
.createQueryBuilder(undefined, undefined, undefined, {
shouldBypassPermissionChecks: true,
})
.createQueryBuilder()
.insert()
.into(`${schemaName}.view`, [
'id',
@@ -117,9 +115,7 @@ const createWorkspaceViews = async (
for (const viewDefinition of viewDefinitionsWithId) {
if (viewDefinition.fields && viewDefinition.fields.length > 0) {
await entityManager
.createQueryBuilder(undefined, undefined, undefined, {
shouldBypassPermissionChecks: true,
})
.createQueryBuilder()
.insert()
.into(`${schemaName}.viewField`, [
'fieldMetadataId',
@@ -144,9 +140,7 @@ const createWorkspaceViews = async (
if (viewDefinition.filters && viewDefinition.filters.length > 0) {
await entityManager
.createQueryBuilder(undefined, undefined, undefined, {
shouldBypassPermissionChecks: true,
})
.createQueryBuilder()
.insert()
.into(`${schemaName}.viewFilter`, [
'fieldMetadataId',
@@ -174,9 +168,7 @@ const createWorkspaceViews = async (
viewDefinition.groups.length > 0
) {
await entityManager
.createQueryBuilder(undefined, undefined, undefined, {
shouldBypassPermissionChecks: true,
})
.createQueryBuilder()
.insert()
.into(`${schemaName}.viewGroup`, [
'fieldMetadataId',
@@ -1,16 +1,16 @@
import { isDefined } from 'twenty-shared/utils';
import { type EntityManager } from 'typeorm';
import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { generateObjectMetadataMaps } from 'src/engine/metadata-modules/utils/generate-object-metadata-maps.util';
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
import { generateObjectRecordFields } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/generate-object-record-fields';
const QUICK_LEAD_WORKFLOW_ID = '8b213cac-a68b-4ffe-817a-3ec994e9932d';
const QUICK_LEAD_WORKFLOW_VERSION_ID = 'ac67974f-c524-4288-9d88-af8515400b68';
export const prefillWorkflows = async (
entityManager: WorkspaceEntityManager,
entityManager: EntityManager,
schemaName: string,
objectMetadataItems: ObjectMetadataEntity[],
) => {
@@ -37,9 +37,7 @@ export const prefillWorkflows = async (
}
await entityManager
.createQueryBuilder(undefined, undefined, undefined, {
shouldBypassPermissionChecks: true,
})
.createQueryBuilder()
.insert()
.into(`${schemaName}.workflow`, [
'id',
@@ -70,9 +68,7 @@ export const prefillWorkflows = async (
.execute();
await entityManager
.createQueryBuilder(undefined, undefined, undefined, {
shouldBypassPermissionChecks: true,
})
.createQueryBuilder()
.insert()
.into(`${schemaName}.workflowVersion`, [
'id',
@@ -1,18 +1,15 @@
import { type EntityManager } from 'typeorm';
import { v4 } from 'uuid';
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
const tableName = 'favorite';
export const prefillWorkspaceFavorites = async (
viewIds: string[],
entityManager: WorkspaceEntityManager,
entityManager: EntityManager,
schemaName: string,
) => {
await entityManager
.createQueryBuilder(undefined, undefined, undefined, {
shouldBypassPermissionChecks: true,
})
.createQueryBuilder()
.insert()
.into(`${schemaName}.${tableName}`, ['id', 'viewId', 'position'])
.values(
@@ -1,6 +1,6 @@
import { type DataSource, type EntityManager } from 'typeorm';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace.datasource';
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
import { shouldSeedWorkspaceFavorite } from 'src/engine/utils/should-seed-workspace-favorite';
import { prefillCompanies } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-companies';
import { prefillPeople } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-people';
@@ -9,40 +9,38 @@ import { prefillWorkflows } from 'src/engine/workspace-manager/standard-objects-
import { prefillWorkspaceFavorites } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-workspace-favorites';
export const standardObjectsPrefillData = async (
workspaceDataSource: WorkspaceDataSource,
dataSource: DataSource,
schemaName: string,
objectMetadataItems: ObjectMetadataEntity[],
featureFlags?: Record<string, boolean>,
) => {
workspaceDataSource.transaction(
async (entityManager: WorkspaceEntityManager) => {
await prefillCompanies(entityManager, schemaName);
dataSource.transaction(async (entityManager: EntityManager) => {
await prefillCompanies(entityManager, schemaName);
await prefillPeople(entityManager, schemaName);
await prefillPeople(entityManager, schemaName);
await prefillWorkflows(entityManager, schemaName, objectMetadataItems);
await prefillWorkflows(entityManager, schemaName, objectMetadataItems);
const viewDefinitionsWithId = await prefillViews(
entityManager,
schemaName,
objectMetadataItems,
featureFlags,
);
const viewDefinitionsWithId = await prefillViews(
entityManager,
schemaName,
objectMetadataItems,
featureFlags,
);
await prefillWorkspaceFavorites(
viewDefinitionsWithId
.filter(
(view) =>
view.key === 'INDEX' &&
shouldSeedWorkspaceFavorite(
view.objectMetadataId,
objectMetadataItems,
),
)
.map((view) => view.id),
entityManager,
schemaName,
);
},
);
await prefillWorkspaceFavorites(
viewDefinitionsWithId
.filter(
(view) =>
view.key === 'INDEX' &&
shouldSeedWorkspaceFavorite(
view.objectMetadataId,
objectMetadataItems,
),
)
.map((view) => view.id),
entityManager,
schemaName,
);
});
};
@@ -1,7 +1,7 @@
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { DataSource, Repository } from 'typeorm';
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
@@ -29,6 +29,8 @@ export class WorkspaceManagerService {
private readonly logger = new Logger(WorkspaceManagerService.name);
constructor(
@InjectDataSource()
private readonly coreDataSource: DataSource,
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
private readonly workspaceMigrationService: WorkspaceMigrationService,
private readonly objectMetadataService: ObjectMetadataService,
@@ -125,16 +127,11 @@ export class WorkspaceManagerService {
workspaceId: string,
featureFlags: Record<string, boolean>,
) {
const workspaceDataSource =
await this.twentyORMGlobalManager.getDataSourceForWorkspace({
workspaceId,
});
const createdObjectMetadata =
await this.objectMetadataService.findManyWithinWorkspace(workspaceId);
await standardObjectsPrefillData(
workspaceDataSource,
this.coreDataSource,
dataSourceMetadata.schema,
createdObjectMetadata,
featureFlags,
@@ -143,12 +140,13 @@ export class WorkspaceManagerService {
if (featureFlags[FeatureFlagKey.IS_CORE_VIEW_SYNCING_ENABLED]) {
this.logger.log(`Prefilling core views for workspace ${workspaceId}`);
await prefillCoreViews(
workspaceDataSource,
await prefillCoreViews({
coreDataSource: this.coreDataSource,
workspaceId,
createdObjectMetadata,
objectMetadataItems: createdObjectMetadata,
schemaName: dataSourceMetadata.schema,
featureFlags,
);
});
}
}