Add configuration types for widgets (#14717)

closes https://github.com/twentyhq/core-team-issues/issues/1532
This commit is contained in:
nitin
2025-09-29 17:11:26 +05:30
committed by GitHub
parent 2685f4a5b9
commit ea144c434b
88 changed files with 2829 additions and 1487 deletions
@@ -1,14 +1,21 @@
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
import { GraphType, WidgetType } from '~/generated-metadata/graphql';
import { type PageLayoutTab } from '../../types/PageLayoutTab';
import { type PageLayoutWidget } from '~/generated/graphql';
import { WidgetType } from '../../mocks/mockWidgets';
import { type PageLayoutTab } from '../../types/pageLayoutTypes';
import { addWidgetToTab } from '../addWidgetToTab';
describe('addWidgetToTab', () => {
const mockWidget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
id: 'widget-1',
pageLayoutTabId: 'tab-1',
title: 'Test Widget',
type: WidgetType.GRAPH,
configuration: {
graphType: GraphType.NUMBER,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: 'id',
},
gridPosition: { row: 0, column: 0, rowSpan: 2, columnSpan: 2 },
objectMetadataId: null,
createdAt: '2024-01-01T00:00:00Z',
@@ -1,5 +1,10 @@
import { type PageLayoutWidget } from '~/generated/graphql';
import { GraphType, WidgetType } from '../../mocks/mockWidgets';
import {
GraphOrderBy,
GraphType,
WidgetType,
type PageLayoutWidget,
} from '~/generated-metadata/graphql';
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
import { convertLayoutsToWidgets } from '../convertLayoutsToWidgets';
describe('convertLayoutsToWidgets', () => {
@@ -18,6 +23,8 @@ describe('convertLayoutsToWidgets', () => {
},
configuration: {
graphType: GraphType.NUMBER,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: 'id',
},
createdAt: '2024-01-01T00:00:00Z',
updatedAt: '2024-01-01T00:00:00Z',
@@ -37,6 +44,10 @@ describe('convertLayoutsToWidgets', () => {
},
configuration: {
graphType: GraphType.PIE,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: 'id',
groupByFieldMetadataId: 'status',
orderBy: GraphOrderBy.VALUE_DESC,
},
createdAt: '2024-01-01T00:00:00Z',
updatedAt: '2024-01-01T00:00:00Z',
@@ -1,6 +1,12 @@
import { type PageLayout } from '@/page-layout/types/pageLayoutTypes';
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
import { type PageLayout } from '@/page-layout/types/PageLayout';
import { convertPageLayoutToTabLayouts } from '@/page-layout/utils/convertPageLayoutToTabLayouts';
import { PageLayoutType, WidgetType } from '~/generated/graphql';
import {
GraphOrderBy,
GraphType,
PageLayoutType,
WidgetType,
} from '~/generated-metadata/graphql';
describe('convertPageLayoutToTabLayouts', () => {
it('should convert page layout to tab layouts', () => {
@@ -17,10 +23,16 @@ describe('convertPageLayoutToTabLayouts', () => {
pageLayoutId: 'page-layout-1',
widgets: [
{
__typename: 'PageLayoutWidget',
id: 'widget-1',
pageLayoutTabId: 'tab-1',
title: 'Widget 1',
type: WidgetType.GRAPH,
configuration: {
graphType: GraphType.NUMBER,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: 'id',
},
gridPosition: { row: 0, column: 0, rowSpan: 2, columnSpan: 2 },
objectMetadataId: 'object-metadata-1',
createdAt: '2025-01-01T00:00:00.000Z',
@@ -28,10 +40,18 @@ describe('convertPageLayoutToTabLayouts', () => {
deletedAt: null,
},
{
__typename: 'PageLayoutWidget',
id: 'widget-2',
pageLayoutTabId: 'tab-1',
title: 'Widget 2',
type: WidgetType.GRAPH,
configuration: {
graphType: GraphType.PIE,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: 'id',
groupByFieldMetadataId: 'status',
orderBy: GraphOrderBy.VALUE_DESC,
},
gridPosition: { row: 2, column: 0, rowSpan: 2, columnSpan: 2 },
objectMetadataId: 'object-metadata-1',
createdAt: '2025-01-01T00:00:00.000Z',
@@ -1,5 +1,10 @@
import { WidgetType } from '../../mocks/mockWidgets';
import { type PageLayoutTab } from '../../types/pageLayoutTypes';
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
import {
GraphOrderBy,
GraphType,
WidgetType,
} from '~/generated-metadata/graphql';
import { type PageLayoutTab } from '../../types/PageLayoutTab';
import { removeWidgetFromTab } from '../removeWidgetFromTab';
describe('removeWidgetFromTab', () => {
@@ -11,10 +16,16 @@ describe('removeWidgetFromTab', () => {
pageLayoutId: 'layout-1',
widgets: [
{
__typename: 'PageLayoutWidget' as const,
id: 'widget-1',
pageLayoutTabId: 'tab-1',
title: 'Widget 1',
type: WidgetType.GRAPH,
configuration: {
graphType: GraphType.NUMBER,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: 'id',
},
gridPosition: { row: 0, column: 0, rowSpan: 2, columnSpan: 2 },
objectMetadataId: null,
createdAt: '2024-01-01T00:00:00Z',
@@ -22,10 +33,18 @@ describe('removeWidgetFromTab', () => {
deletedAt: null,
},
{
__typename: 'PageLayoutWidget' as const,
id: 'widget-2',
pageLayoutTabId: 'tab-1',
title: 'Widget 2',
type: WidgetType.GRAPH,
configuration: {
graphType: GraphType.PIE,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: 'id',
groupByFieldMetadataId: 'status',
orderBy: GraphOrderBy.VALUE_DESC,
},
gridPosition: { row: 2, column: 0, rowSpan: 2, columnSpan: 2 },
objectMetadataId: null,
createdAt: '2024-01-01T00:00:00Z',
@@ -44,10 +63,14 @@ describe('removeWidgetFromTab', () => {
pageLayoutId: 'layout-1',
widgets: [
{
__typename: 'PageLayoutWidget' as const,
id: 'widget-3',
pageLayoutTabId: 'tab-2',
title: 'Widget 3',
type: WidgetType.IFRAME,
configuration: {
url: 'https://example.com',
},
gridPosition: { row: 0, column: 0, rowSpan: 2, columnSpan: 2 },
objectMetadataId: null,
createdAt: '2024-01-01T00:00:00Z',
@@ -1,4 +1,4 @@
import { type PageLayoutTab } from '@/page-layout/types/pageLayoutTypes';
import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab';
import { type PageLayoutWidget } from '~/generated/graphql';
export const addWidgetToTab = (
@@ -1,5 +1,5 @@
import { type Layouts } from 'react-grid-layout';
import { type PageLayoutWidget } from '~/generated/graphql';
import { type Layouts } from 'react-grid-layout';
export const convertLayoutsToWidgets = (
widgets: PageLayoutWidget[],
@@ -1,4 +1,4 @@
import { type PageLayout } from '@/page-layout/types/pageLayoutTypes';
import { type PageLayout } from '@/page-layout/types/PageLayout';
import { type TabLayouts } from '@/page-layout/types/tab-layouts';
export const convertPageLayoutToTabLayouts = (
@@ -0,0 +1,91 @@
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
import { v4 as uuidv4 } from 'uuid';
import { GraphOrderBy, GraphType } from '~/generated-metadata/graphql';
import {
type GridPosition,
type PageLayoutWidget,
type WidgetConfiguration,
WidgetType,
} from '~/generated/graphql';
const createDefaultGraphConfiguration = (
graphType: GraphType,
): WidgetConfiguration => {
const placeholderFieldId1 = uuidv4();
const placeholderFieldId2 = uuidv4();
switch (graphType) {
case GraphType.NUMBER:
return {
graphType: GraphType.NUMBER,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: placeholderFieldId1,
};
case GraphType.PIE:
return {
graphType: GraphType.PIE,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: placeholderFieldId1,
groupByFieldMetadataId: placeholderFieldId2,
orderBy: GraphOrderBy.VALUE_DESC,
};
case GraphType.BAR:
return {
graphType: GraphType.BAR,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: placeholderFieldId1,
groupByFieldMetadataIdX: placeholderFieldId2,
orderByX: GraphOrderBy.FIELD_ASC,
};
case GraphType.LINE:
return {
graphType: GraphType.LINE,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: placeholderFieldId1,
groupByFieldMetadataIdX: placeholderFieldId2,
orderByX: GraphOrderBy.FIELD_ASC,
};
case GraphType.GAUGE:
return {
graphType: GraphType.GAUGE,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: placeholderFieldId1,
aggregateOperationTotal: AggregateOperations.COUNT,
aggregateFieldMetadataIdTotal: placeholderFieldId2,
};
default:
return {
graphType: GraphType.NUMBER,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: placeholderFieldId1,
};
}
};
export const createDefaultGraphWidget = (
id: string,
pageLayoutTabId: string,
title: string,
graphType: GraphType,
gridPosition: GridPosition,
objectMetadataId?: string | null,
): PageLayoutWidget => {
return {
__typename: 'PageLayoutWidget',
id,
pageLayoutTabId,
title,
type: WidgetType.GRAPH,
configuration: createDefaultGraphConfiguration(graphType),
gridPosition,
objectMetadataId: objectMetadataId ?? null,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
};
};
@@ -0,0 +1,30 @@
import {
type GridPosition,
type PageLayoutWidget,
WidgetType,
} from '~/generated/graphql';
export const createDefaultIframeWidget = (
id: string,
pageLayoutTabId: string,
title: string,
url: string,
gridPosition: GridPosition,
objectMetadataId?: string | null,
): PageLayoutWidget => {
return {
__typename: 'PageLayoutWidget',
id,
pageLayoutTabId,
title,
type: WidgetType.IFRAME,
configuration: {
url,
},
gridPosition,
objectMetadataId: objectMetadataId ?? null,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
};
};
@@ -1,4 +1,4 @@
import { GraphType } from '../mocks/mockWidgets';
import { GraphType } from '~/generated-metadata/graphql';
export const getDefaultWidgetData = (graphType: GraphType) => {
switch (graphType) {
@@ -1,4 +1,4 @@
import { type PageLayout } from '~/modules/page-layout/types/pageLayoutTypes';
import { type PageLayout } from '@/page-layout/types/PageLayout';
export const isPageLayoutEmpty = (pageLayout: PageLayout): boolean => {
return (
@@ -1,4 +1,4 @@
import { type PageLayoutTab } from '../types/pageLayoutTypes';
import { type PageLayoutTab } from '../types/PageLayoutTab';
export const removeWidgetFromTab = (
tabs: PageLayoutTab[],
@@ -0,0 +1,17 @@
import { type PageLayout } from '@/page-layout/types/PageLayout';
import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab';
import { type PageLayout as PageLayoutGenerated } from '~/generated/graphql';
export const transformPageLayout = (
pageLayout: PageLayoutGenerated,
): PageLayout => {
return {
...pageLayout,
tabs: (pageLayout.tabs ?? []).map(
(tab): PageLayoutTab => ({
...tab,
widgets: tab.widgets ?? [],
}),
),
};
};