Migrate pagelayout position frontend (#18229)
## Context Part 1 of migrating gridPosition in favor of typed position FE should now always send both values to the BE and use both. Next steps: - Update the backend to enforce and validate the new position field + DB migrations gridPositon -> position (type: GRID) - Cleanup frontend usage - Cleanup backend
This commit is contained in:
+17
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
AggregateOperations,
|
||||
GraphOrderBy,
|
||||
PageLayoutTabLayoutMode,
|
||||
WidgetConfigurationType,
|
||||
WidgetType,
|
||||
type PageLayoutWidget,
|
||||
@@ -73,12 +74,28 @@ describe('convertLayoutsToWidgets', () => {
|
||||
columnSpan: 4,
|
||||
rowSpan: 5,
|
||||
});
|
||||
expect(result[0].position).toEqual({
|
||||
__typename: 'PageLayoutWidgetGridPosition',
|
||||
layoutMode: PageLayoutTabLayoutMode.GRID,
|
||||
column: 2,
|
||||
row: 3,
|
||||
columnSpan: 4,
|
||||
rowSpan: 5,
|
||||
});
|
||||
expect(result[1].gridPosition).toEqual({
|
||||
column: 6,
|
||||
row: 7,
|
||||
columnSpan: 8,
|
||||
rowSpan: 9,
|
||||
});
|
||||
expect(result[1].position).toEqual({
|
||||
__typename: 'PageLayoutWidgetGridPosition',
|
||||
layoutMode: PageLayoutTabLayoutMode.GRID,
|
||||
column: 6,
|
||||
row: 7,
|
||||
columnSpan: 8,
|
||||
rowSpan: 9,
|
||||
});
|
||||
});
|
||||
|
||||
it('should use defaults when layout not found', () => {
|
||||
|
||||
+7
@@ -84,6 +84,13 @@ describe('convertPageLayoutDraftToUpdateInput', () => {
|
||||
rowSpan: 4,
|
||||
columnSpan: 5,
|
||||
});
|
||||
expect(result.tabs[0].widgets[0].position).toEqual({
|
||||
layoutMode: 'GRID',
|
||||
row: 2,
|
||||
column: 3,
|
||||
rowSpan: 4,
|
||||
columnSpan: 5,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle objectMetadataId as null when not provided', () => {
|
||||
|
||||
+9
@@ -3,6 +3,7 @@ import {
|
||||
AxisNameDisplay,
|
||||
BarChartLayout,
|
||||
GraphOrderBy,
|
||||
PageLayoutTabLayoutMode,
|
||||
WidgetConfigurationType,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { createDefaultGraphWidget } from '@/page-layout/utils/createDefaultGraphWidget';
|
||||
@@ -67,6 +68,14 @@ describe('createDefaultGraphWidget', () => {
|
||||
expect(widget.pageLayoutTabId).toBe('tab-1');
|
||||
expect(widget.title).toBe('Test Widget');
|
||||
expect(widget.gridPosition).toEqual(baseParams.gridPosition);
|
||||
expect(widget.position).toEqual({
|
||||
__typename: 'PageLayoutWidgetGridPosition',
|
||||
layoutMode: PageLayoutTabLayoutMode.GRID,
|
||||
row: 0,
|
||||
column: 0,
|
||||
rowSpan: 2,
|
||||
columnSpan: 2,
|
||||
});
|
||||
expect(widget.createdAt).toBeDefined();
|
||||
expect(widget.updatedAt).toBeDefined();
|
||||
expect(widget.deletedAt).toBeNull();
|
||||
|
||||
+12
-1
@@ -1,4 +1,7 @@
|
||||
import { WidgetType } from '~/generated-metadata/graphql';
|
||||
import {
|
||||
PageLayoutTabLayoutMode,
|
||||
WidgetType,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { createDefaultStandaloneRichTextWidget } from '@/page-layout/utils/createDefaultStandaloneRichTextWidget';
|
||||
|
||||
describe('createDefaultStandaloneRichTextWidget', () => {
|
||||
@@ -20,6 +23,14 @@ describe('createDefaultStandaloneRichTextWidget', () => {
|
||||
body: { blocknote: '[{"type":"paragraph","content":"Test"}]' },
|
||||
},
|
||||
gridPosition: { row: 0, column: 0, rowSpan: 4, columnSpan: 4 },
|
||||
position: {
|
||||
__typename: 'PageLayoutWidgetGridPosition',
|
||||
layoutMode: PageLayoutTabLayoutMode.GRID,
|
||||
row: 0,
|
||||
column: 0,
|
||||
rowSpan: 4,
|
||||
columnSpan: 4,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
|
||||
import { type Layouts } from 'react-grid-layout';
|
||||
import { PageLayoutTabLayoutMode } from '~/generated-metadata/graphql';
|
||||
|
||||
export const convertLayoutsToWidgets = (
|
||||
widgets: PageLayoutWidget[],
|
||||
@@ -10,13 +11,26 @@ export const convertLayoutsToWidgets = (
|
||||
return widgets.map((widget) => {
|
||||
const layout = activeLayouts.find((l) => l.i === widget.id);
|
||||
|
||||
const row = layout?.y ?? 0;
|
||||
const column = layout?.x ?? 0;
|
||||
const rowSpan = layout?.h ?? 2;
|
||||
const columnSpan = layout?.w ?? 2;
|
||||
|
||||
return {
|
||||
...widget,
|
||||
gridPosition: {
|
||||
row: layout?.y ?? 0,
|
||||
column: layout?.x ?? 0,
|
||||
rowSpan: layout?.h ?? 2,
|
||||
columnSpan: layout?.w ?? 2,
|
||||
row,
|
||||
column,
|
||||
rowSpan,
|
||||
columnSpan,
|
||||
},
|
||||
position: {
|
||||
__typename: 'PageLayoutWidgetGridPosition' as const,
|
||||
layoutMode: PageLayoutTabLayoutMode.GRID,
|
||||
row,
|
||||
column,
|
||||
rowSpan,
|
||||
columnSpan,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
+12
-1
@@ -1,6 +1,9 @@
|
||||
import { type DraftPageLayout } from '@/page-layout/types/DraftPageLayout';
|
||||
import { isDynamicRelationWidget } from '@/page-layout/utils/isDynamicRelationWidget';
|
||||
import { type UpdatePageLayoutWithTabsInput } from '~/generated-metadata/graphql';
|
||||
import {
|
||||
PageLayoutTabLayoutMode,
|
||||
type UpdatePageLayoutWithTabsInput,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export const convertPageLayoutDraftToUpdateInput = (
|
||||
pageLayoutDraft: DraftPageLayout,
|
||||
@@ -27,6 +30,14 @@ export const convertPageLayoutDraftToUpdateInput = (
|
||||
rowSpan: widget.gridPosition.rowSpan,
|
||||
columnSpan: widget.gridPosition.columnSpan,
|
||||
},
|
||||
position: {
|
||||
layoutMode:
|
||||
widget.position?.layoutMode ?? PageLayoutTabLayoutMode.GRID,
|
||||
row: widget.gridPosition.row,
|
||||
column: widget.gridPosition.column,
|
||||
rowSpan: widget.gridPosition.rowSpan,
|
||||
columnSpan: widget.gridPosition.columnSpan,
|
||||
},
|
||||
configuration: widget.configuration ?? null,
|
||||
})),
|
||||
})),
|
||||
|
||||
+15
-4
@@ -32,12 +32,23 @@ export const convertPageLayoutToTabLayouts = (
|
||||
}
|
||||
}
|
||||
|
||||
const gridPos =
|
||||
isDefined(widget.position) &&
|
||||
widget.position.__typename === 'PageLayoutWidgetGridPosition'
|
||||
? {
|
||||
row: widget.position.row,
|
||||
column: widget.position.column,
|
||||
rowSpan: widget.position.rowSpan,
|
||||
columnSpan: widget.position.columnSpan,
|
||||
}
|
||||
: widget.gridPosition;
|
||||
|
||||
return {
|
||||
i: widget.id,
|
||||
x: widget.gridPosition.column,
|
||||
y: widget.gridPosition.row,
|
||||
w: widget.gridPosition.columnSpan,
|
||||
h: widget.gridPosition.rowSpan,
|
||||
x: gridPos.column,
|
||||
y: gridPos.row,
|
||||
w: gridPos.columnSpan,
|
||||
h: gridPos.rowSpan,
|
||||
minW,
|
||||
minH,
|
||||
};
|
||||
|
||||
+9
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
type GridPosition,
|
||||
PageLayoutTabLayoutMode,
|
||||
WidgetConfigurationType,
|
||||
WidgetType,
|
||||
} from '~/generated-metadata/graphql';
|
||||
@@ -24,6 +25,14 @@ export const createDefaultFrontComponentWidget = (
|
||||
frontComponentId,
|
||||
},
|
||||
gridPosition,
|
||||
position: {
|
||||
__typename: 'PageLayoutWidgetGridPosition',
|
||||
layoutMode: PageLayoutTabLayoutMode.GRID,
|
||||
row: gridPosition.row,
|
||||
column: gridPosition.column,
|
||||
rowSpan: gridPosition.rowSpan,
|
||||
columnSpan: gridPosition.columnSpan,
|
||||
},
|
||||
objectMetadataId: null,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
BarChartLayout,
|
||||
GraphOrderBy,
|
||||
type GridPosition,
|
||||
PageLayoutTabLayoutMode,
|
||||
type PageLayoutWidget,
|
||||
type WidgetConfiguration,
|
||||
WidgetConfigurationType,
|
||||
@@ -74,6 +75,14 @@ export const createDefaultGraphWidget = ({
|
||||
type: WidgetType.GRAPH,
|
||||
configuration,
|
||||
gridPosition,
|
||||
position: {
|
||||
__typename: 'PageLayoutWidgetGridPosition',
|
||||
layoutMode: PageLayoutTabLayoutMode.GRID,
|
||||
row: gridPosition.row,
|
||||
column: gridPosition.column,
|
||||
rowSpan: gridPosition.rowSpan,
|
||||
columnSpan: gridPosition.columnSpan,
|
||||
},
|
||||
objectMetadataId: resolvedObjectMetadataId,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
type GridPosition,
|
||||
PageLayoutTabLayoutMode,
|
||||
type PageLayoutWidget,
|
||||
WidgetConfigurationType,
|
||||
WidgetType,
|
||||
@@ -24,6 +25,14 @@ export const createDefaultIframeWidget = (
|
||||
url,
|
||||
},
|
||||
gridPosition,
|
||||
position: {
|
||||
__typename: 'PageLayoutWidgetGridPosition',
|
||||
layoutMode: PageLayoutTabLayoutMode.GRID,
|
||||
row: gridPosition.row,
|
||||
column: gridPosition.column,
|
||||
rowSpan: gridPosition.rowSpan,
|
||||
columnSpan: gridPosition.columnSpan,
|
||||
},
|
||||
objectMetadataId: objectMetadataId ?? null,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
|
||||
+9
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
type GridPosition,
|
||||
PageLayoutTabLayoutMode,
|
||||
type PageLayoutWidget,
|
||||
type RichTextV2Body,
|
||||
WidgetConfigurationType,
|
||||
@@ -24,6 +25,14 @@ export const createDefaultStandaloneRichTextWidget = (
|
||||
body,
|
||||
},
|
||||
gridPosition,
|
||||
position: {
|
||||
__typename: 'PageLayoutWidgetGridPosition',
|
||||
layoutMode: PageLayoutTabLayoutMode.GRID,
|
||||
row: gridPosition.row,
|
||||
column: gridPosition.column,
|
||||
rowSpan: gridPosition.rowSpan,
|
||||
columnSpan: gridPosition.columnSpan,
|
||||
},
|
||||
objectMetadataId: objectMetadataId ?? null,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
|
||||
@@ -4,6 +4,7 @@ import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
|
||||
import { DYNAMIC_RELATION_WIDGET_ID_PREFIX } from '@/page-layout/utils/isDynamicRelationWidget';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
PageLayoutTabLayoutMode,
|
||||
WidgetConfigurationType,
|
||||
WidgetType,
|
||||
} from '~/generated-metadata/graphql';
|
||||
@@ -25,6 +26,14 @@ const getRelationFieldWidgetToInsert = (
|
||||
rowSpan: 1,
|
||||
columnSpan: 12,
|
||||
},
|
||||
position: {
|
||||
__typename: 'PageLayoutWidgetGridPosition' as const,
|
||||
layoutMode: PageLayoutTabLayoutMode.GRID,
|
||||
row: 0,
|
||||
column: 0,
|
||||
rowSpan: 1,
|
||||
columnSpan: 12,
|
||||
},
|
||||
configuration: {
|
||||
__typename: 'FieldConfiguration' as const,
|
||||
configurationType: WidgetConfigurationType.FIELD,
|
||||
|
||||
+1
@@ -30,6 +30,7 @@ export class WorkspaceFlatFrontComponentMapCacheService extends WorkspaceCachePr
|
||||
const [frontComponents, applications] = await Promise.all([
|
||||
this.frontComponentRepository.find({
|
||||
where: { workspaceId },
|
||||
withDeleted: true,
|
||||
}),
|
||||
this.applicationRepository.find({
|
||||
where: { workspaceId },
|
||||
|
||||
+2
-2
@@ -329,7 +329,7 @@ export const fromPageLayoutWidgetConfigurationToUniversalConfiguration = ({
|
||||
}
|
||||
|
||||
case WidgetConfigurationType.FRONT_COMPONENT: {
|
||||
const { frontComponentId, ...rest } = configuration;
|
||||
const { frontComponentId, configurationType } = configuration;
|
||||
|
||||
const frontComponentUniversalIdentifier: string | null =
|
||||
frontComponentUniversalIdentifierById[frontComponentId] ?? null;
|
||||
@@ -345,7 +345,7 @@ export const fromPageLayoutWidgetConfigurationToUniversalConfiguration = ({
|
||||
}
|
||||
|
||||
return {
|
||||
...rest,
|
||||
configurationType,
|
||||
frontComponentUniversalIdentifier,
|
||||
};
|
||||
}
|
||||
|
||||
+2
-2
@@ -313,7 +313,7 @@ export const fromUniversalConfigurationToFlatPageLayoutWidgetConfiguration = ({
|
||||
}
|
||||
|
||||
case WidgetConfigurationType.FRONT_COMPONENT: {
|
||||
const { frontComponentUniversalIdentifier, ...rest } =
|
||||
const { frontComponentUniversalIdentifier, configurationType } =
|
||||
universalConfiguration;
|
||||
|
||||
if (!isDefined(frontComponentUniversalIdentifier)) {
|
||||
@@ -336,7 +336,7 @@ export const fromUniversalConfigurationToFlatPageLayoutWidgetConfiguration = ({
|
||||
}
|
||||
|
||||
return {
|
||||
...rest,
|
||||
configurationType,
|
||||
frontComponentId: flatFrontComponent.id,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user