Fix duplicate Fields widget (#19696)
## Context Tab duplication was broken after the view creation logic was deferred and moved to the FE. - Duplicating a tab or a FIELDS widget now produces a fully independent copy: new view, new view field groups, new view fields — all with fresh IDs — while preserving any unsaved edits from the source widget. - Removed the backend auto-seed of default view fields / view field groups in ViewService.createOne for FIELDS_WIDGET views. The frontend always sends the complete layout via upsertFieldsWidget, so the auto-seed was both redundant and the source of potential bugs. - Extracted a shared useDuplicateFieldsWidgetForPageLayout hook used by both tab and widget duplication paths, plus a small useCloneViewInMetadataStore helper that clones the FlatView in the metadata store and returns the copied flat view fields/groups for the caller.
This commit is contained in:
+83
@@ -0,0 +1,83 @@
|
||||
import { type FlatViewField } from '@/metadata-store/types/FlatViewField';
|
||||
import { type FlatViewFieldGroup } from '@/metadata-store/types/FlatViewFieldGroup';
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import {
|
||||
type FieldsWidgetGroup,
|
||||
type FieldsWidgetGroupField,
|
||||
} from '@/page-layout/widgets/fields/types/FieldsWidgetGroup';
|
||||
import { type FieldsWidgetEditorMode } from '@/page-layout/widgets/fields/types/FieldsWidgetEditorMode';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type BuildResult = {
|
||||
editorMode: FieldsWidgetEditorMode;
|
||||
groups: FieldsWidgetGroup[];
|
||||
ungroupedFields: FieldsWidgetGroupField[];
|
||||
};
|
||||
|
||||
export const buildFieldsWidgetGroupsFromFlatViewData = ({
|
||||
flatViewFieldGroups,
|
||||
flatViewFields,
|
||||
fieldMetadataItems,
|
||||
}: {
|
||||
flatViewFieldGroups: FlatViewFieldGroup[];
|
||||
flatViewFields: FlatViewField[];
|
||||
fieldMetadataItems: FieldMetadataItem[];
|
||||
}): BuildResult => {
|
||||
const fieldMetadataById = new Map(
|
||||
fieldMetadataItems.map((fieldMetadataItem) => [
|
||||
fieldMetadataItem.id,
|
||||
fieldMetadataItem,
|
||||
]),
|
||||
);
|
||||
|
||||
if (flatViewFieldGroups.length > 0) {
|
||||
const groups = flatViewFieldGroups.map((group) => ({
|
||||
id: group.id,
|
||||
name: group.name,
|
||||
position: group.position,
|
||||
isVisible: group.isVisible,
|
||||
fields: flatViewFields
|
||||
.filter((field) => field.viewFieldGroupId === group.id)
|
||||
.sort((a, b) => a.position - b.position)
|
||||
.map((field, index) => {
|
||||
const fieldMetadataItem = fieldMetadataById.get(
|
||||
field.fieldMetadataId,
|
||||
);
|
||||
|
||||
if (!isDefined(fieldMetadataItem)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
fieldMetadataItem,
|
||||
position: field.position,
|
||||
isVisible: field.isVisible,
|
||||
globalIndex: index,
|
||||
};
|
||||
})
|
||||
.filter(isDefined),
|
||||
}));
|
||||
|
||||
return { editorMode: 'grouped', groups, ungroupedFields: [] };
|
||||
}
|
||||
|
||||
const ungroupedFields = flatViewFields
|
||||
.sort((a, b) => a.position - b.position)
|
||||
.map((field, index) => {
|
||||
const fieldMetadataItem = fieldMetadataById.get(field.fieldMetadataId);
|
||||
|
||||
if (!isDefined(fieldMetadataItem)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
fieldMetadataItem,
|
||||
position: field.position,
|
||||
isVisible: field.isVisible,
|
||||
globalIndex: index,
|
||||
};
|
||||
})
|
||||
.filter(isDefined);
|
||||
|
||||
return { editorMode: 'ungrouped', groups: [], ungroupedFields };
|
||||
};
|
||||
Reference in New Issue
Block a user