Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 845b9ff6ba | |||
| 992ff40ac3 |
@@ -0,0 +1,109 @@
|
||||
import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext';
|
||||
import { fieldsWidgetEditorModeDraftComponentState } from '@/page-layout/states/fieldsWidgetEditorModeDraftComponentState';
|
||||
import { fieldsWidgetGroupsDraftComponentState } from '@/page-layout/states/fieldsWidgetGroupsDraftComponentState';
|
||||
import { fieldsWidgetUngroupedFieldsDraftComponentState } from '@/page-layout/states/fieldsWidgetUngroupedFieldsDraftComponentState';
|
||||
import { hasInitializedFieldsWidgetGroupsDraftComponentState } from '@/page-layout/states/hasInitializedFieldsWidgetGroupsDraftComponentState';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
export const useCopyFieldsWidgetDraftState = (
|
||||
pageLayoutIdFromProps: string,
|
||||
) => {
|
||||
const pageLayoutId = useAvailableComponentInstanceIdOrThrow(
|
||||
PageLayoutComponentInstanceContext,
|
||||
pageLayoutIdFromProps,
|
||||
);
|
||||
|
||||
const fieldsWidgetGroupsDraftState = useAtomComponentStateCallbackState(
|
||||
fieldsWidgetGroupsDraftComponentState,
|
||||
pageLayoutId,
|
||||
);
|
||||
|
||||
const fieldsWidgetUngroupedFieldsDraftState =
|
||||
useAtomComponentStateCallbackState(
|
||||
fieldsWidgetUngroupedFieldsDraftComponentState,
|
||||
pageLayoutId,
|
||||
);
|
||||
|
||||
const fieldsWidgetEditorModeDraftState = useAtomComponentStateCallbackState(
|
||||
fieldsWidgetEditorModeDraftComponentState,
|
||||
pageLayoutId,
|
||||
);
|
||||
|
||||
const hasInitializedFieldsWidgetGroupsDraftState =
|
||||
useAtomComponentStateCallbackState(
|
||||
hasInitializedFieldsWidgetGroupsDraftComponentState,
|
||||
pageLayoutId,
|
||||
);
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const copyFieldsWidgetDraftState = useCallback(
|
||||
(sourceWidgetId: string, targetWidgetId: string) => {
|
||||
const groupsDraft = store.get(fieldsWidgetGroupsDraftState);
|
||||
const ungroupedFieldsDraft = store.get(
|
||||
fieldsWidgetUngroupedFieldsDraftState,
|
||||
);
|
||||
const editorModeDraft = store.get(fieldsWidgetEditorModeDraftState);
|
||||
|
||||
let hasCopiedData = false;
|
||||
|
||||
if (sourceWidgetId in groupsDraft) {
|
||||
const sourceGroups = groupsDraft[sourceWidgetId];
|
||||
const clonedGroups = sourceGroups.map((group) => ({
|
||||
...group,
|
||||
id: uuidv4(),
|
||||
fields: group.fields.map((field) => ({
|
||||
...field,
|
||||
viewFieldId: undefined,
|
||||
})),
|
||||
}));
|
||||
store.set(fieldsWidgetGroupsDraftState, (prev) => ({
|
||||
...prev,
|
||||
[targetWidgetId]: clonedGroups,
|
||||
}));
|
||||
hasCopiedData = true;
|
||||
}
|
||||
|
||||
if (sourceWidgetId in ungroupedFieldsDraft) {
|
||||
const sourceUngrouped = ungroupedFieldsDraft[sourceWidgetId];
|
||||
const clonedUngrouped = sourceUngrouped.map((field) => ({
|
||||
...field,
|
||||
viewFieldId: undefined,
|
||||
}));
|
||||
store.set(fieldsWidgetUngroupedFieldsDraftState, (prev) => ({
|
||||
...prev,
|
||||
[targetWidgetId]: clonedUngrouped,
|
||||
}));
|
||||
hasCopiedData = true;
|
||||
}
|
||||
|
||||
if (sourceWidgetId in editorModeDraft) {
|
||||
store.set(fieldsWidgetEditorModeDraftState, (prev) => ({
|
||||
...prev,
|
||||
[targetWidgetId]: editorModeDraft[sourceWidgetId],
|
||||
}));
|
||||
hasCopiedData = true;
|
||||
}
|
||||
|
||||
if (hasCopiedData) {
|
||||
store.set(hasInitializedFieldsWidgetGroupsDraftState, (prev) => ({
|
||||
...prev,
|
||||
[targetWidgetId]: true,
|
||||
}));
|
||||
}
|
||||
},
|
||||
[
|
||||
fieldsWidgetEditorModeDraftState,
|
||||
fieldsWidgetGroupsDraftState,
|
||||
fieldsWidgetUngroupedFieldsDraftState,
|
||||
hasInitializedFieldsWidgetGroupsDraftState,
|
||||
store,
|
||||
],
|
||||
);
|
||||
|
||||
return { copyFieldsWidgetDraftState };
|
||||
};
|
||||
+6
-10
@@ -13,7 +13,7 @@ export const useCreatePendingFieldsWidgetViews = () => {
|
||||
const store = useStore();
|
||||
|
||||
const createPendingFieldsWidgetViews = useCallback(
|
||||
async (pageLayoutId: string) => {
|
||||
async (pageLayoutId: string): Promise<void> => {
|
||||
const draft = store.get(
|
||||
pageLayoutDraftComponentState.atomFamily({
|
||||
instanceId: pageLayoutId,
|
||||
@@ -35,15 +35,11 @@ export const useCreatePendingFieldsWidgetViews = () => {
|
||||
|
||||
const newFieldsWidgets = draft.tabs
|
||||
.flatMap((tab) => tab.widgets)
|
||||
.filter((widget) => {
|
||||
if (widget.type !== WidgetType.FIELDS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const viewId = getWidgetConfigurationViewId(widget.configuration);
|
||||
|
||||
return isDefined(viewId) && !persistedWidgetIds.has(widget.id);
|
||||
});
|
||||
.filter(
|
||||
(widget) =>
|
||||
widget.type === WidgetType.FIELDS &&
|
||||
!persistedWidgetIds.has(widget.id),
|
||||
);
|
||||
|
||||
for (const widget of newFieldsWidgets) {
|
||||
const viewId = getWidgetConfigurationViewId(widget.configuration);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { useCopyFieldsWidgetDraftState } from '@/page-layout/hooks/useCopyFieldsWidgetDraftState';
|
||||
import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext';
|
||||
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
|
||||
import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState';
|
||||
import { pageLayoutTabSettingsOpenTabIdComponentState } from '@/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState';
|
||||
import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab';
|
||||
import { duplicateWidgetConfigurationWithNewViewId } from '@/page-layout/utils/duplicateWidgetConfigurationWithNewViewId';
|
||||
import { generateDuplicatedTimestamps } from '@/page-layout/utils/generateDuplicatedTimestamps';
|
||||
import { sortTabsByPosition } from '@/page-layout/utils/sortTabsByPosition';
|
||||
import { useSidePanelMenu } from '@/side-panel/hooks/useSidePanelMenu';
|
||||
@@ -17,6 +19,7 @@ import { useCallback } from 'react';
|
||||
import { SidePanelPages } from 'twenty-shared/types';
|
||||
import { appendCopySuffix, isDefined } from 'twenty-shared/utils';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { WidgetConfigurationType } from '~/generated-metadata/graphql';
|
||||
|
||||
export const useDuplicatePageLayoutTab = ({
|
||||
pageLayoutId: pageLayoutIdFromProps,
|
||||
@@ -40,6 +43,9 @@ export const useDuplicatePageLayoutTab = ({
|
||||
pageLayoutId,
|
||||
);
|
||||
|
||||
const { copyFieldsWidgetDraftState } =
|
||||
useCopyFieldsWidgetDraftState(pageLayoutId);
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const setActiveTabId = useSetAtomComponentState(
|
||||
@@ -79,6 +85,9 @@ export const useDuplicatePageLayoutTab = ({
|
||||
...widget,
|
||||
id: newWidgetId,
|
||||
pageLayoutTabId: newTabId,
|
||||
configuration: duplicateWidgetConfigurationWithNewViewId(
|
||||
widget.configuration,
|
||||
),
|
||||
...generateDuplicatedTimestamps(),
|
||||
};
|
||||
});
|
||||
@@ -128,6 +137,19 @@ export const useDuplicatePageLayoutTab = ({
|
||||
tabs: [...prev.tabs, newTab],
|
||||
});
|
||||
|
||||
for (const [oldWidgetId, newWidgetId] of widgetOldIdNewIdMap) {
|
||||
const sourceWidget = sourceTab.widgets.find(
|
||||
(widget) => widget.id === oldWidgetId,
|
||||
);
|
||||
|
||||
if (
|
||||
sourceWidget?.configuration.configurationType ===
|
||||
WidgetConfigurationType.FIELDS
|
||||
) {
|
||||
copyFieldsWidgetDraftState(oldWidgetId, newWidgetId);
|
||||
}
|
||||
}
|
||||
|
||||
closeSidePanelMenu();
|
||||
|
||||
setActiveTabId(newTabId);
|
||||
@@ -144,6 +166,7 @@ export const useDuplicatePageLayoutTab = ({
|
||||
},
|
||||
[
|
||||
closeSidePanelMenu,
|
||||
copyFieldsWidgetDraftState,
|
||||
navigatePageLayoutSidePanel,
|
||||
pageLayoutCurrentLayouts,
|
||||
pageLayoutDraft,
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { useCopyFieldsWidgetDraftState } from '@/page-layout/hooks/useCopyFieldsWidgetDraftState';
|
||||
import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext';
|
||||
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
|
||||
import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState';
|
||||
import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState';
|
||||
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
|
||||
import { addWidgetToTab } from '@/page-layout/utils/addWidgetToTab';
|
||||
import { duplicateWidgetConfigurationWithNewViewId } from '@/page-layout/utils/duplicateWidgetConfigurationWithNewViewId';
|
||||
import { generateDuplicatedTimestamps } from '@/page-layout/utils/generateDuplicatedTimestamps';
|
||||
import { getScrollWrapperInstanceIdFromPageLayoutId } from '@/page-layout/utils/getScrollWrapperInstanceIdFromPageLayoutId';
|
||||
import { getUpdatedTabLayouts } from '@/page-layout/utils/getUpdatedTabLayouts';
|
||||
@@ -15,6 +17,7 @@ import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { appendCopySuffix, isDefined } from 'twenty-shared/utils';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { WidgetConfigurationType } from '~/generated-metadata/graphql';
|
||||
|
||||
export const useDuplicatePageLayoutWidget = (
|
||||
pageLayoutIdFromProps?: string,
|
||||
@@ -39,6 +42,9 @@ export const useDuplicatePageLayoutWidget = (
|
||||
pageLayoutId,
|
||||
);
|
||||
|
||||
const { copyFieldsWidgetDraftState } =
|
||||
useCopyFieldsWidgetDraftState(pageLayoutId);
|
||||
|
||||
const { getScrollWrapperElement } = useScrollWrapperHTMLElement(
|
||||
getScrollWrapperInstanceIdFromPageLayoutId(pageLayoutId),
|
||||
);
|
||||
@@ -75,6 +81,9 @@ export const useDuplicatePageLayoutWidget = (
|
||||
...sourceWidget,
|
||||
id: newWidgetId,
|
||||
title: appendCopySuffix(sourceWidget.title),
|
||||
configuration: duplicateWidgetConfigurationWithNewViewId(
|
||||
sourceWidget.configuration,
|
||||
),
|
||||
...generateDuplicatedTimestamps(),
|
||||
};
|
||||
|
||||
@@ -115,6 +124,13 @@ export const useDuplicatePageLayoutWidget = (
|
||||
tabs: addWidgetToTab(prev.tabs, sourceTab.id, clonedWidget),
|
||||
}));
|
||||
|
||||
if (
|
||||
sourceWidget.configuration.configurationType ===
|
||||
WidgetConfigurationType.FIELDS
|
||||
) {
|
||||
copyFieldsWidgetDraftState(widgetId, newWidgetId);
|
||||
}
|
||||
|
||||
setPageLayoutEditingWidgetId(newWidgetId);
|
||||
|
||||
const { scrollWrapperElement } = getScrollWrapperElement();
|
||||
@@ -137,6 +153,7 @@ export const useDuplicatePageLayoutWidget = (
|
||||
return newWidgetId;
|
||||
},
|
||||
[
|
||||
copyFieldsWidgetDraftState,
|
||||
pageLayoutCurrentLayoutsState,
|
||||
pageLayoutDraftState,
|
||||
setPageLayoutEditingWidgetId,
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { WidgetConfigurationType } from '~/generated-metadata/graphql';
|
||||
|
||||
export const duplicateWidgetConfigurationWithNewViewId = (
|
||||
configuration: PageLayoutWidget['configuration'],
|
||||
): PageLayoutWidget['configuration'] => {
|
||||
if (configuration.configurationType === WidgetConfigurationType.FIELDS) {
|
||||
return {
|
||||
...configuration,
|
||||
viewId: uuidv4(),
|
||||
};
|
||||
}
|
||||
|
||||
return configuration;
|
||||
};
|
||||
+17
-46
@@ -5,7 +5,7 @@ import {
|
||||
type FieldsWidgetGroup,
|
||||
type FieldsWidgetGroupField,
|
||||
} from '@/page-layout/widgets/fields/types/FieldsWidgetGroup';
|
||||
import { buildDefaultFieldsWidgetGroups } from '@/page-layout/widgets/fields/utils/buildDefaultFieldsWidgetGroups';
|
||||
import { mapViewFieldsToFieldsWidgetGroupFields } from '@/page-layout/widgets/fields/utils/mapViewFieldsToFieldsWidgetGroupFields';
|
||||
import { useViewById } from '@/views/hooks/useViewById';
|
||||
import { useMemo } from 'react';
|
||||
import {
|
||||
@@ -106,7 +106,7 @@ export const useFieldsWidgetEditorGroupsData = ({
|
||||
const fields: FieldsWidgetGroupField[] = groupFields
|
||||
.map((viewField) => {
|
||||
const fieldMetadataItem = objectMetadataItem.fields.find(
|
||||
(f) => f.id === viewField.fieldMetadataId,
|
||||
(field) => field.id === viewField.fieldMetadataId,
|
||||
);
|
||||
|
||||
if (!isDefined(fieldMetadataItem)) {
|
||||
@@ -137,7 +137,7 @@ export const useFieldsWidgetEditorGroupsData = ({
|
||||
const lastGroup = groups[groups.length - 1];
|
||||
const lastFieldPosition =
|
||||
lastGroup.fields.length > 0
|
||||
? Math.max(...lastGroup.fields.map((f) => f.position)) + 1
|
||||
? Math.max(...lastGroup.fields.map((field) => field.position)) + 1
|
||||
: 0;
|
||||
|
||||
const missingFields = buildMissingFields({
|
||||
@@ -154,38 +154,23 @@ export const useFieldsWidgetEditorGroupsData = ({
|
||||
}
|
||||
|
||||
if (isDefined(view) && view.viewFields.length > 0) {
|
||||
let globalIndex = 0;
|
||||
const existingFieldMetadataIds = new Set<string>();
|
||||
const fields = mapViewFieldsToFieldsWidgetGroupFields({
|
||||
viewFields: view.viewFields,
|
||||
objectMetadataFields: objectMetadataItem.fields,
|
||||
});
|
||||
|
||||
const fields = [...view.viewFields]
|
||||
.sort((a, b) => a.position - b.position)
|
||||
.map((viewField) => {
|
||||
const fieldMetadataItem = objectMetadataItem.fields.find(
|
||||
(f) => f.id === viewField.fieldMetadataId,
|
||||
);
|
||||
|
||||
if (!isDefined(fieldMetadataItem)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
existingFieldMetadataIds.add(viewField.fieldMetadataId);
|
||||
|
||||
return {
|
||||
fieldMetadataItem,
|
||||
position: viewField.position,
|
||||
isVisible: viewField.isVisible,
|
||||
globalIndex: globalIndex++,
|
||||
viewFieldId: viewField.id,
|
||||
};
|
||||
})
|
||||
.filter(isDefined);
|
||||
const existingFieldMetadataIds = new Set(
|
||||
fields.map((field) => field.fieldMetadataItem.id),
|
||||
);
|
||||
|
||||
const lastFieldPosition =
|
||||
fields.length > 0 ? Math.max(...fields.map((f) => f.position)) + 1 : 0;
|
||||
fields.length > 0
|
||||
? Math.max(...fields.map((field) => field.position)) + 1
|
||||
: 0;
|
||||
|
||||
const missingFields = buildMissingFields({
|
||||
existingFieldMetadataIds,
|
||||
startGlobalIndex: globalIndex,
|
||||
startGlobalIndex: fields.length,
|
||||
startPosition: lastFieldPosition,
|
||||
});
|
||||
|
||||
@@ -200,27 +185,13 @@ export const useFieldsWidgetEditorGroupsData = ({
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
groups: buildDefaultFieldsWidgetGroups({
|
||||
fields: objectMetadataItem.fields,
|
||||
objectNameSingular,
|
||||
labelIdentifierFieldMetadataItemId:
|
||||
labelIdentifierFieldMetadataItem?.id,
|
||||
}),
|
||||
ungroupedFields: [],
|
||||
editorMode: 'grouped' as const,
|
||||
};
|
||||
}, [
|
||||
objectMetadataItem,
|
||||
objectNameSingular,
|
||||
view,
|
||||
labelIdentifierFieldMetadataItem,
|
||||
]);
|
||||
return { groups: [], ungroupedFields: [], editorMode: 'ungrouped' };
|
||||
}, [objectMetadataItem, view, labelIdentifierFieldMetadataItem]);
|
||||
|
||||
return {
|
||||
...result,
|
||||
isFromView:
|
||||
isDefined(view) &&
|
||||
(isDefined(view.viewFieldGroups) || view.viewFields.length > 0),
|
||||
(isNonEmptyArray(view.viewFieldGroups) || view.viewFields.length > 0),
|
||||
};
|
||||
};
|
||||
|
||||
+41
-30
@@ -1,12 +1,10 @@
|
||||
import { useLabelIdentifierFieldMetadataItem } from '@/object-metadata/hooks/useLabelIdentifierFieldMetadataItem';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { type FieldsWidgetDisplayMode } from '@/page-layout/widgets/fields/types/FieldsWidgetDisplayMode';
|
||||
import {
|
||||
type FieldsWidgetGroup,
|
||||
type FieldsWidgetGroupField,
|
||||
} from '@/page-layout/widgets/fields/types/FieldsWidgetGroup';
|
||||
import { buildDefaultFieldsWidgetGroups } from '@/page-layout/widgets/fields/utils/buildDefaultFieldsWidgetGroups';
|
||||
import { filterDraftGroupsForDisplay } from '@/page-layout/widgets/fields/utils/filterDraftGroupsForDisplay';
|
||||
import { mapViewFieldsToFieldsWidgetGroupFields } from '@/page-layout/widgets/fields/utils/mapViewFieldsToFieldsWidgetGroupFields';
|
||||
import { useViewById } from '@/views/hooks/useViewById';
|
||||
import { useMemo } from 'react';
|
||||
import { isDefined, isNonEmptyArray } from 'twenty-shared/utils';
|
||||
@@ -24,14 +22,13 @@ export const useFieldsWidgetGroups = ({
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
const { labelIdentifierFieldMetadataItem } =
|
||||
useLabelIdentifierFieldMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const groups = useMemo<FieldsWidgetGroup[]>(() => {
|
||||
const { groups, displayMode } = useMemo<{
|
||||
groups: FieldsWidgetGroup[];
|
||||
displayMode: FieldsWidgetDisplayMode;
|
||||
}>(() => {
|
||||
if (!isDefined(objectMetadataItem)) {
|
||||
return [];
|
||||
return { groups: [], displayMode: 'inline' };
|
||||
}
|
||||
|
||||
if (isDefined(view) && isNonEmptyArray(view.viewFieldGroups)) {
|
||||
@@ -41,7 +38,7 @@ export const useFieldsWidgetGroups = ({
|
||||
|
||||
let globalIndex = 0;
|
||||
|
||||
return sortedGroups
|
||||
const groups = sortedGroups
|
||||
.filter((group) => group.isVisible)
|
||||
.map((group) => {
|
||||
const groupFields = [...(group.viewFields ?? [])].sort(
|
||||
@@ -52,21 +49,19 @@ export const useFieldsWidgetGroups = ({
|
||||
.filter((field) => field.isVisible)
|
||||
.map((viewField) => {
|
||||
const fieldMetadataItem = objectMetadataItem.fields.find(
|
||||
(f) => f.id === viewField.fieldMetadataId,
|
||||
(field) => field.id === viewField.fieldMetadataId,
|
||||
);
|
||||
|
||||
if (!isDefined(fieldMetadataItem)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const field: FieldsWidgetGroupField = {
|
||||
return {
|
||||
fieldMetadataItem,
|
||||
position: viewField.position,
|
||||
isVisible: viewField.isVisible,
|
||||
globalIndex: globalIndex++,
|
||||
};
|
||||
|
||||
return field;
|
||||
})
|
||||
.filter(isDefined);
|
||||
|
||||
@@ -79,28 +74,44 @@ export const useFieldsWidgetGroups = ({
|
||||
};
|
||||
})
|
||||
.filter((group) => group.fields.length > 0);
|
||||
|
||||
return { groups, displayMode: 'grouped' };
|
||||
}
|
||||
|
||||
return filterDraftGroupsForDisplay(
|
||||
buildDefaultFieldsWidgetGroups({
|
||||
fields: objectMetadataItem.fields,
|
||||
objectNameSingular,
|
||||
labelIdentifierFieldMetadataItemId:
|
||||
labelIdentifierFieldMetadataItem?.id,
|
||||
}),
|
||||
);
|
||||
}, [
|
||||
objectMetadataItem,
|
||||
objectNameSingular,
|
||||
labelIdentifierFieldMetadataItem,
|
||||
view,
|
||||
]);
|
||||
if (isDefined(view) && view.viewFields.length > 0) {
|
||||
const allFields = mapViewFieldsToFieldsWidgetGroupFields({
|
||||
viewFields: view.viewFields,
|
||||
objectMetadataFields: objectMetadataItem.fields,
|
||||
});
|
||||
|
||||
const displayMode: FieldsWidgetDisplayMode = 'grouped';
|
||||
const visibleFields = allFields.filter((field) => field.isVisible);
|
||||
|
||||
if (visibleFields.length === 0) {
|
||||
return { groups: [], displayMode: 'inline' };
|
||||
}
|
||||
|
||||
return {
|
||||
groups: [
|
||||
{
|
||||
id: `${viewId}-ungrouped`,
|
||||
name: '',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
fields: visibleFields,
|
||||
},
|
||||
],
|
||||
displayMode: 'inline',
|
||||
};
|
||||
}
|
||||
|
||||
return { groups: [], displayMode: 'inline' };
|
||||
}, [objectMetadataItem, view, viewId]);
|
||||
|
||||
return {
|
||||
groups,
|
||||
displayMode,
|
||||
isFromView: isDefined(view) && isNonEmptyArray(view.viewFieldGroups),
|
||||
isFromView:
|
||||
isDefined(view) &&
|
||||
(isNonEmptyArray(view.viewFieldGroups) || view.viewFields.length > 0),
|
||||
};
|
||||
};
|
||||
|
||||
+5
-22
@@ -4,6 +4,7 @@ import {
|
||||
type FieldsWidgetGroupField,
|
||||
} from '@/page-layout/widgets/fields/types/FieldsWidgetGroup';
|
||||
import { getHiddenFieldsFromGroups } from '@/page-layout/widgets/fields/utils/getHiddenFieldsFromGroups';
|
||||
import { mapViewFieldsToFieldsWidgetGroupFields } from '@/page-layout/widgets/fields/utils/mapViewFieldsToFieldsWidgetGroupFields';
|
||||
import { useViewById } from '@/views/hooks/useViewById';
|
||||
import { useMemo } from 'react';
|
||||
import { isDefined, isNonEmptyArray } from 'twenty-shared/utils';
|
||||
@@ -61,28 +62,10 @@ export const useFieldsWidgetHiddenFields = ({
|
||||
}
|
||||
|
||||
if (isDefined(view) && view.viewFields.length > 0) {
|
||||
let globalIndex = 0;
|
||||
|
||||
return [...view.viewFields]
|
||||
.sort((a, b) => a.position - b.position)
|
||||
.filter((viewField) => !viewField.isVisible)
|
||||
.map((viewField) => {
|
||||
const fieldMetadataItem = objectMetadataItem.fields.find(
|
||||
(f) => f.id === viewField.fieldMetadataId,
|
||||
);
|
||||
|
||||
if (!isDefined(fieldMetadataItem)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
fieldMetadataItem,
|
||||
position: viewField.position,
|
||||
isVisible: false,
|
||||
globalIndex: globalIndex++,
|
||||
};
|
||||
})
|
||||
.filter(isDefined);
|
||||
return mapViewFieldsToFieldsWidgetGroupFields({
|
||||
viewFields: view.viewFields,
|
||||
objectMetadataFields: objectMetadataItem.fields,
|
||||
}).filter((field) => !field.isVisible);
|
||||
}
|
||||
|
||||
return [];
|
||||
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { type FieldsWidgetGroup } from '@/page-layout/widgets/fields/types/FieldsWidgetGroup';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { isFieldMetadataEligibleForFieldsWidget } from 'twenty-shared/utils';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
export const buildDefaultFieldsWidgetGroups = ({
|
||||
fields,
|
||||
objectNameSingular,
|
||||
labelIdentifierFieldMetadataItemId,
|
||||
}: {
|
||||
fields: FieldMetadataItem[];
|
||||
objectNameSingular: string;
|
||||
labelIdentifierFieldMetadataItemId: string | undefined;
|
||||
}): FieldsWidgetGroup[] => {
|
||||
const eligibleFields = fields.filter((field) =>
|
||||
isFieldMetadataEligibleForFieldsWidget({
|
||||
fieldName: field.name,
|
||||
fieldType: field.type,
|
||||
isLabelIdentifierField: field.id === labelIdentifierFieldMetadataItemId,
|
||||
}),
|
||||
);
|
||||
|
||||
const standardFields = eligibleFields.filter((field) => !field.isCustom);
|
||||
const customFields = eligibleFields.filter((field) => field.isCustom);
|
||||
|
||||
const isFieldVisible = (fieldType: FieldMetadataType) =>
|
||||
fieldType !== FieldMetadataType.RELATION &&
|
||||
fieldType !== FieldMetadataType.MORPH_RELATION;
|
||||
|
||||
const groups: FieldsWidgetGroup[] = [];
|
||||
let globalIndex = 0;
|
||||
|
||||
if (standardFields.length > 0) {
|
||||
groups.push({
|
||||
id: uuidv4(),
|
||||
name: 'General',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
fields: standardFields.map((field, index) => ({
|
||||
fieldMetadataItem: field,
|
||||
position: index,
|
||||
isVisible: isFieldVisible(field.type),
|
||||
globalIndex: globalIndex++,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
if (customFields.length > 0) {
|
||||
groups.push({
|
||||
id: uuidv4(),
|
||||
name: 'Other',
|
||||
position: 1,
|
||||
isVisible: true,
|
||||
fields: customFields.map((field, index) => ({
|
||||
fieldMetadataItem: field,
|
||||
position: index,
|
||||
isVisible: isFieldVisible(field.type),
|
||||
globalIndex: globalIndex++,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
return groups;
|
||||
};
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { type FieldsWidgetGroupField } from '@/page-layout/widgets/fields/types/FieldsWidgetGroup';
|
||||
import { type ViewField } from '@/views/types/ViewField';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const mapViewFieldsToFieldsWidgetGroupFields = ({
|
||||
viewFields,
|
||||
objectMetadataFields,
|
||||
}: {
|
||||
viewFields: ViewField[];
|
||||
objectMetadataFields: FieldMetadataItem[];
|
||||
}): FieldsWidgetGroupField[] => {
|
||||
let globalIndex = 0;
|
||||
|
||||
return [...viewFields]
|
||||
.sort((a, b) => a.position - b.position)
|
||||
.map((viewField) => {
|
||||
const fieldMetadataItem = objectMetadataFields.find(
|
||||
(field) => field.id === viewField.fieldMetadataId,
|
||||
);
|
||||
|
||||
if (!isDefined(fieldMetadataItem)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
fieldMetadataItem,
|
||||
position: viewField.position,
|
||||
isVisible: viewField.isVisible,
|
||||
globalIndex: globalIndex++,
|
||||
viewFieldId: viewField.id,
|
||||
};
|
||||
})
|
||||
.filter(isDefined);
|
||||
};
|
||||
Reference in New Issue
Block a user