From 7c26b1cce36b9bbb4f996b4405d914b6d3a0e1ac Mon Sep 17 00:00:00 2001 From: nitin <142569587+ehconitin@users.noreply.github.com> Date: Fri, 12 Sep 2025 18:05:51 +0530 Subject: [PATCH] [Dashboards] - Add seeds (#14404) closes https://github.com/twentyhq/core-team-issues/issues/1440 --- .../page-layout-data-seeds.constant.ts | 97 ++++ .../page-layout-tab-data-seeds.constant.ts | 121 +++++ .../core/utils/seed-core-schema.util.ts | 9 + .../utils/seed-page-layout-widgets.util.ts | 35 ++ .../core/utils/seed-page-layouts.util.ts | 46 ++ .../dashboard-data-seeds.constant.ts | 128 +++++ .../page-layout-widget-data-seeds.constant.ts | 496 ++++++++++++++++++ .../data/services/dev-seeder-data.service.ts | 26 +- .../dev-seeder/services/dev-seeder.service.ts | 1 + .../attachment.workspace-entity.ts | 8 + .../favorite.workspace-entity.ts | 8 + .../timeline-activity.workspace-entity.ts | 8 + .../page-layout-resolver.integration-spec.ts | 23 +- .../search-resolver.integration-spec.ts | 1 + 14 files changed, 990 insertions(+), 17 deletions(-) create mode 100644 packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/constants/page-layout-data-seeds.constant.ts create mode 100644 packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/constants/page-layout-tab-data-seeds.constant.ts create mode 100644 packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-page-layout-widgets.util.ts create mode 100644 packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-page-layouts.util.ts create mode 100644 packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/constants/dashboard-data-seeds.constant.ts create mode 100644 packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/constants/page-layout-widget-data-seeds.constant.ts diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/constants/page-layout-data-seeds.constant.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/constants/page-layout-data-seeds.constant.ts new file mode 100644 index 0000000000..0f05cd5b9e --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/constants/page-layout-data-seeds.constant.ts @@ -0,0 +1,97 @@ +import { PageLayoutType } from 'src/engine/core-modules/page-layout/enums/page-layout-type.enum'; + +export const PAGE_LAYOUT_SEED_IDS = { + SALES_DASHBOARD: '20202020-1af3-467c-866d-5b2fdf7851ac', + CUSTOMER_DASHBOARD: '20202020-249e-4bee-be65-d3a89b0a2ffb', + TEAM_DASHBOARD: '20202020-78dd-41f5-9bbf-6d0fe532ac94', + REVENUE_ANALYTICS: '20202020-7d8e-4c0e-bae0-e46ecf3aee6c', + MARKETING_METRICS: '20202020-1939-4ffa-8f84-1ca4e29e3e92', + SUPPORT_DASHBOARD: '20202020-ffcc-47c5-ae0f-667d9c223a3d', + PRODUCT_USAGE: '20202020-a2d4-4c48-bedf-c4f64bd02d3e', + OPERATIONS_KPI: '20202020-41c1-4e73-8abc-46b3cca612b3', + FINANCE_OVERVIEW: '20202020-553b-4552-bc6f-2805906ee792', + EXECUTIVE_SUMMARY: '20202020-0fce-4d5b-a7d8-d5c1b0fa4970', +}; + +type PageLayoutSeed = { + id: string; + name: string; + type: PageLayoutType; + objectMetadataId: string | null; + workspaceId: string; +}; + +export const getPageLayoutDataSeeds = ( + workspaceId: string, +): PageLayoutSeed[] => [ + { + id: PAGE_LAYOUT_SEED_IDS.SALES_DASHBOARD, + name: 'Sales Dashboard Layout', + type: PageLayoutType.DASHBOARD, + objectMetadataId: null, + workspaceId, + }, + { + id: PAGE_LAYOUT_SEED_IDS.CUSTOMER_DASHBOARD, + name: 'Customer Dashboard Layout', + type: PageLayoutType.DASHBOARD, + objectMetadataId: null, + workspaceId, + }, + { + id: PAGE_LAYOUT_SEED_IDS.TEAM_DASHBOARD, + name: 'Team Dashboard Layout', + type: PageLayoutType.DASHBOARD, + objectMetadataId: null, + workspaceId, + }, + { + id: PAGE_LAYOUT_SEED_IDS.REVENUE_ANALYTICS, + name: 'Revenue Analytics Layout', + type: PageLayoutType.DASHBOARD, + objectMetadataId: null, + workspaceId, + }, + { + id: PAGE_LAYOUT_SEED_IDS.MARKETING_METRICS, + name: 'Marketing Metrics Layout', + type: PageLayoutType.DASHBOARD, + objectMetadataId: null, + workspaceId, + }, + { + id: PAGE_LAYOUT_SEED_IDS.SUPPORT_DASHBOARD, + name: 'Support Dashboard Layout', + type: PageLayoutType.DASHBOARD, + objectMetadataId: null, + workspaceId, + }, + { + id: PAGE_LAYOUT_SEED_IDS.PRODUCT_USAGE, + name: 'Product Usage Layout', + type: PageLayoutType.DASHBOARD, + objectMetadataId: null, + workspaceId, + }, + { + id: PAGE_LAYOUT_SEED_IDS.OPERATIONS_KPI, + name: 'Operations KPI Layout', + type: PageLayoutType.DASHBOARD, + objectMetadataId: null, + workspaceId, + }, + { + id: PAGE_LAYOUT_SEED_IDS.FINANCE_OVERVIEW, + name: 'Finance Overview Layout', + type: PageLayoutType.DASHBOARD, + objectMetadataId: null, + workspaceId, + }, + { + id: PAGE_LAYOUT_SEED_IDS.EXECUTIVE_SUMMARY, + name: 'Executive Summary Layout', + type: PageLayoutType.DASHBOARD, + objectMetadataId: null, + workspaceId, + }, +]; diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/constants/page-layout-tab-data-seeds.constant.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/constants/page-layout-tab-data-seeds.constant.ts new file mode 100644 index 0000000000..47abf59c2d --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/constants/page-layout-tab-data-seeds.constant.ts @@ -0,0 +1,121 @@ +import { PAGE_LAYOUT_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/core/constants/page-layout-data-seeds.constant'; + +export const PAGE_LAYOUT_TAB_SEED_IDS = { + SALES_OVERVIEW: '20202020-3fff-4590-8a63-00d861e968ad', + SALES_DETAILS: '20202020-3db8-449c-aac8-359055276c93', + CUSTOMER_OVERVIEW: '20202020-95ae-4979-8c32-a48313afaa11', + CUSTOMER_ANALYTICS: '20202020-4321-43c9-8dc2-d9fb697d39ba', + TEAM_OVERVIEW: '20202020-e58d-441b-ae1e-6ee8dd157653', + TEAM_METRICS: '20202020-92f2-4586-bd40-6e021198c8da', + REVENUE_MAIN: '20202020-a498-4648-836e-a7e89013e115', + MARKETING_MAIN: '20202020-509b-4dac-a8ec-7255687a6b49', + SUPPORT_MAIN: '20202020-3c11-49d9-8bc7-a18245604aa2', + PRODUCT_MAIN: '20202020-6885-44ae-bc21-f450de57a567', + OPERATIONS_MAIN: '20202020-c4eb-456a-9266-0c44f90e6136', + FINANCE_MAIN: '20202020-45d2-46d1-ae75-69bc82dea9ef', + EXECUTIVE_MAIN: '20202020-264b-4801-9656-8bdd73ca7f9a', +}; + +type PageLayoutTabSeed = { + id: string; + title: string; + position: number; + pageLayoutId: string; + workspaceId: string; +}; + +export const getPageLayoutTabDataSeeds = ( + workspaceId: string, +): PageLayoutTabSeed[] => [ + { + id: PAGE_LAYOUT_TAB_SEED_IDS.SALES_OVERVIEW, + title: 'Overview', + position: 0, + pageLayoutId: PAGE_LAYOUT_SEED_IDS.SALES_DASHBOARD, + workspaceId, + }, + { + id: PAGE_LAYOUT_TAB_SEED_IDS.SALES_DETAILS, + title: 'Details', + position: 1, + pageLayoutId: PAGE_LAYOUT_SEED_IDS.SALES_DASHBOARD, + workspaceId, + }, + { + id: PAGE_LAYOUT_TAB_SEED_IDS.CUSTOMER_OVERVIEW, + title: 'Overview', + position: 0, + pageLayoutId: PAGE_LAYOUT_SEED_IDS.CUSTOMER_DASHBOARD, + workspaceId, + }, + { + id: PAGE_LAYOUT_TAB_SEED_IDS.CUSTOMER_ANALYTICS, + title: 'Analytics', + position: 1, + pageLayoutId: PAGE_LAYOUT_SEED_IDS.CUSTOMER_DASHBOARD, + workspaceId, + }, + { + id: PAGE_LAYOUT_TAB_SEED_IDS.TEAM_OVERVIEW, + title: 'Overview', + position: 0, + pageLayoutId: PAGE_LAYOUT_SEED_IDS.TEAM_DASHBOARD, + workspaceId, + }, + { + id: PAGE_LAYOUT_TAB_SEED_IDS.TEAM_METRICS, + title: 'Metrics', + position: 1, + pageLayoutId: PAGE_LAYOUT_SEED_IDS.TEAM_DASHBOARD, + workspaceId, + }, + { + id: PAGE_LAYOUT_TAB_SEED_IDS.REVENUE_MAIN, + title: 'Revenue', + position: 0, + pageLayoutId: PAGE_LAYOUT_SEED_IDS.REVENUE_ANALYTICS, + workspaceId, + }, + { + id: PAGE_LAYOUT_TAB_SEED_IDS.MARKETING_MAIN, + title: 'Marketing', + position: 0, + pageLayoutId: PAGE_LAYOUT_SEED_IDS.MARKETING_METRICS, + workspaceId, + }, + { + id: PAGE_LAYOUT_TAB_SEED_IDS.SUPPORT_MAIN, + title: 'Support', + position: 0, + pageLayoutId: PAGE_LAYOUT_SEED_IDS.SUPPORT_DASHBOARD, + workspaceId, + }, + { + id: PAGE_LAYOUT_TAB_SEED_IDS.PRODUCT_MAIN, + title: 'Product', + position: 0, + pageLayoutId: PAGE_LAYOUT_SEED_IDS.PRODUCT_USAGE, + workspaceId, + }, + { + id: PAGE_LAYOUT_TAB_SEED_IDS.OPERATIONS_MAIN, + title: 'Operations', + position: 0, + pageLayoutId: PAGE_LAYOUT_SEED_IDS.OPERATIONS_KPI, + workspaceId, + }, + { + id: PAGE_LAYOUT_TAB_SEED_IDS.FINANCE_MAIN, + title: 'Finance', + position: 0, + pageLayoutId: PAGE_LAYOUT_SEED_IDS.FINANCE_OVERVIEW, + workspaceId, + }, + { + id: PAGE_LAYOUT_TAB_SEED_IDS.EXECUTIVE_MAIN, + title: 'Executive', + position: 0, + pageLayoutId: PAGE_LAYOUT_SEED_IDS.EXECUTIVE_SUMMARY, + workspaceId, + }, +]; diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-core-schema.util.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-core-schema.util.ts index 11327b97db..eec1ac9b4b 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-core-schema.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-core-schema.util.ts @@ -4,6 +4,8 @@ import { seedBillingSubscriptions } from 'src/engine/workspace-manager/dev-seede import { seedAgents } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-agents.util'; import { seedApiKeys } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-api-keys.util'; import { seedFeatureFlags } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util'; +import { seedPageLayouts } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-page-layouts.util'; +import { seedPageLayoutWidgets } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-page-layout-widgets.util'; import { seedUserWorkspaces } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-user-workspaces.util'; import { seedUsers } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-users.util'; import { seedWorkspaces } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-workspaces.util'; @@ -14,6 +16,7 @@ type SeedCoreSchemaArgs = { appVersion: string | undefined; seedBilling?: boolean; seedFeatureFlags?: boolean; + seedPageLayouts?: boolean; }; export const seedCoreSchema = async ({ @@ -22,6 +25,7 @@ export const seedCoreSchema = async ({ workspaceId, seedBilling = true, seedFeatureFlags: shouldSeedFeatureFlags = true, + seedPageLayouts: shouldSeedPageLayouts = true, }: SeedCoreSchemaArgs) => { const schemaName = 'core'; @@ -45,4 +49,9 @@ export const seedCoreSchema = async ({ if (seedBilling) { await seedBillingSubscriptions(dataSource, schemaName, workspaceId); } + + if (shouldSeedPageLayouts) { + await seedPageLayouts(dataSource, schemaName, workspaceId); + await seedPageLayoutWidgets(dataSource, schemaName, workspaceId); + } }; diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-page-layout-widgets.util.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-page-layout-widgets.util.ts new file mode 100644 index 0000000000..58337e78a6 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-page-layout-widgets.util.ts @@ -0,0 +1,35 @@ +import { type DataSource } from 'typeorm'; + +import { PAGE_LAYOUT_WIDGET_DATA_SEEDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/page-layout-widget-data-seeds.constant'; + +export const seedPageLayoutWidgets = async ( + dataSource: DataSource, + schemaName: string, + workspaceId: string, +) => { + const pageLayoutWidgets = PAGE_LAYOUT_WIDGET_DATA_SEEDS.map((widget) => ({ + ...widget, + workspaceId, + gridPosition: widget.gridPosition, + configuration: widget.configuration, + })); + + if (pageLayoutWidgets.length > 0) { + await dataSource + .createQueryBuilder() + .insert() + .into(`${schemaName}.pageLayoutWidget`, [ + 'id', + 'pageLayoutTabId', + 'title', + 'type', + 'gridPosition', + 'configuration', + 'objectMetadataId', + 'workspaceId', + ]) + .values(pageLayoutWidgets) + .orIgnore() + .execute(); + } +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-page-layouts.util.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-page-layouts.util.ts new file mode 100644 index 0000000000..2a1866c5cf --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-page-layouts.util.ts @@ -0,0 +1,46 @@ +import { type DataSource } from 'typeorm'; + +import { getPageLayoutDataSeeds } from 'src/engine/workspace-manager/dev-seeder/core/constants/page-layout-data-seeds.constant'; +import { getPageLayoutTabDataSeeds } from 'src/engine/workspace-manager/dev-seeder/core/constants/page-layout-tab-data-seeds.constant'; + +export const seedPageLayouts = async ( + dataSource: DataSource, + schemaName: string, + workspaceId: string, +) => { + const pageLayouts = getPageLayoutDataSeeds(workspaceId); + + if (pageLayouts.length > 0) { + await dataSource + .createQueryBuilder() + .insert() + .into(`${schemaName}.pageLayout`, [ + 'id', + 'name', + 'type', + 'objectMetadataId', + 'workspaceId', + ]) + .values(pageLayouts) + .orIgnore() + .execute(); + } + + const pageLayoutTabs = getPageLayoutTabDataSeeds(workspaceId); + + if (pageLayoutTabs.length > 0) { + await dataSource + .createQueryBuilder() + .insert() + .into(`${schemaName}.pageLayoutTab`, [ + 'id', + 'title', + 'position', + 'pageLayoutId', + 'workspaceId', + ]) + .values(pageLayoutTabs) + .orIgnore() + .execute(); + } +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/constants/dashboard-data-seeds.constant.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/constants/dashboard-data-seeds.constant.ts new file mode 100644 index 0000000000..5ef18b941e --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/constants/dashboard-data-seeds.constant.ts @@ -0,0 +1,128 @@ +import { PAGE_LAYOUT_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/core/constants/page-layout-data-seeds.constant'; +import { WORKSPACE_MEMBER_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/workspace-member-data-seeds.constant'; + +type DashboardDataSeed = { + id: string; + title: string; + pageLayoutId: string; + createdBySource: string; + createdByWorkspaceMemberId: string; + createdByName: string; + position: number; +}; + +export const DASHBOARD_DATA_SEED_COLUMNS: (keyof DashboardDataSeed)[] = [ + 'id', + 'title', + 'pageLayoutId', + 'createdBySource', + 'createdByWorkspaceMemberId', + 'createdByName', + 'position', +]; + +export const DASHBOARD_DATA_SEED_IDS = { + SALES_OVERVIEW: '20202020-9e82-4342-91ef-c9e70f16a675', + CUSTOMER_INSIGHTS: '20202020-d64e-4588-98cc-c56ba821247b', + TEAM_PERFORMANCE: '20202020-b888-4c58-8975-76b4c2035d3a', + REVENUE_ANALYTICS: '20202020-842e-4cd0-a205-a5bfb1efdb1c', + MARKETING_METRICS: '20202020-7b87-4522-9fa8-7f97332c4fa7', + SUPPORT_DASHBOARD: '20202020-5404-49ba-a10a-7941205e577f', + PRODUCT_USAGE: '20202020-fce2-4c4c-b1dd-6db836141c11', + OPERATIONS_KPI: '20202020-c1e4-444c-ab36-4fb42d493eb3', + FINANCE_OVERVIEW: '20202020-b993-4601-945b-996ec668f9e9', + EXECUTIVE_SUMMARY: '20202020-d2e3-4304-9c80-b3db67903974', +}; + +export const DASHBOARD_DATA_SEEDS: DashboardDataSeed[] = [ + { + id: DASHBOARD_DATA_SEED_IDS.SALES_OVERVIEW, + title: 'Sales Overview', + pageLayoutId: PAGE_LAYOUT_SEED_IDS.SALES_DASHBOARD, + createdBySource: 'MANUAL', + createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM, + createdByName: 'Tim Apple', + position: 0, + }, + { + id: DASHBOARD_DATA_SEED_IDS.CUSTOMER_INSIGHTS, + title: 'Customer Insights', + pageLayoutId: PAGE_LAYOUT_SEED_IDS.CUSTOMER_DASHBOARD, + createdBySource: 'MANUAL', + createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.JONY, + createdByName: 'Jony Ive', + position: 1, + }, + { + id: DASHBOARD_DATA_SEED_IDS.TEAM_PERFORMANCE, + title: 'Team Performance', + pageLayoutId: PAGE_LAYOUT_SEED_IDS.TEAM_DASHBOARD, + createdBySource: 'MANUAL', + createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.PHIL, + createdByName: 'Phil Schiller', + position: 2, + }, + { + id: DASHBOARD_DATA_SEED_IDS.REVENUE_ANALYTICS, + title: 'Revenue Analytics', + pageLayoutId: PAGE_LAYOUT_SEED_IDS.REVENUE_ANALYTICS, + createdBySource: 'MANUAL', + createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM, + createdByName: 'Tim Apple', + position: 3, + }, + { + id: DASHBOARD_DATA_SEED_IDS.MARKETING_METRICS, + title: 'Marketing Metrics', + pageLayoutId: PAGE_LAYOUT_SEED_IDS.MARKETING_METRICS, + createdBySource: 'MANUAL', + createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.JONY, + createdByName: 'Jony Ive', + position: 4, + }, + { + id: DASHBOARD_DATA_SEED_IDS.SUPPORT_DASHBOARD, + title: 'Support Dashboard', + pageLayoutId: PAGE_LAYOUT_SEED_IDS.SUPPORT_DASHBOARD, + createdBySource: 'MANUAL', + createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.PHIL, + createdByName: 'Phil Schiller', + position: 5, + }, + { + id: DASHBOARD_DATA_SEED_IDS.PRODUCT_USAGE, + title: 'Product Usage', + pageLayoutId: PAGE_LAYOUT_SEED_IDS.PRODUCT_USAGE, + createdBySource: 'MANUAL', + createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM, + createdByName: 'Tim Apple', + position: 6, + }, + { + id: DASHBOARD_DATA_SEED_IDS.OPERATIONS_KPI, + title: 'Operations KPI', + pageLayoutId: PAGE_LAYOUT_SEED_IDS.OPERATIONS_KPI, + createdBySource: 'MANUAL', + createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.JONY, + createdByName: 'Jony Ive', + position: 7, + }, + { + id: DASHBOARD_DATA_SEED_IDS.FINANCE_OVERVIEW, + title: 'Finance Overview', + pageLayoutId: PAGE_LAYOUT_SEED_IDS.FINANCE_OVERVIEW, + createdBySource: 'MANUAL', + createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.PHIL, + createdByName: 'Phil Schiller', + position: 8, + }, + { + id: DASHBOARD_DATA_SEED_IDS.EXECUTIVE_SUMMARY, + title: 'Executive Summary', + pageLayoutId: PAGE_LAYOUT_SEED_IDS.EXECUTIVE_SUMMARY, + createdBySource: 'MANUAL', + createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM, + createdByName: 'Tim Apple', + position: 9, + }, +]; diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/constants/page-layout-widget-data-seeds.constant.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/constants/page-layout-widget-data-seeds.constant.ts new file mode 100644 index 0000000000..353609f358 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/constants/page-layout-widget-data-seeds.constant.ts @@ -0,0 +1,496 @@ +import { WidgetType } from 'src/engine/core-modules/page-layout/enums/widget-type.enum'; +import { PAGE_LAYOUT_TAB_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/core/constants/page-layout-tab-data-seeds.constant'; + +type PageLayoutWidgetDataSeed = { + id: string; + pageLayoutTabId: string; + title: string; + type: WidgetType; + gridPosition: { + row: number; + column: number; + rowSpan: number; + columnSpan: number; + }; + + configuration: Record | null; + objectMetadataId: string | null; +}; + +export const PAGE_LAYOUT_WIDGET_DATA_SEED_COLUMNS: (keyof PageLayoutWidgetDataSeed)[] = + [ + 'id', + 'pageLayoutTabId', + 'title', + 'type', + 'gridPosition', + 'configuration', + 'objectMetadataId', + ]; + +export const PAGE_LAYOUT_WIDGET_DATA_SEED_IDS = { + SALES_PIPELINE_NUMBER: '20202020-1d5d-4381-b42f-f92ad3735717', + SALES_CONVERSION_GAUGE: '20202020-6fd4-497f-9d16-8db467756572', + SALES_MONTHLY_REVENUE: '20202020-577b-4a4c-ae7c-be57e1d7b253', + SALES_DEALS_BY_STAGE: '20202020-08b2-42cb-a7fe-5c561380e679', + SALES_TOP_PERFORMERS: '20202020-93ac-4aaf-86f7-0bb38f446211', + SALES_FORECAST_LINE: '20202020-3219-4b0e-ad3f-b3de9adb7c55', + + CUSTOMER_TOTAL_COUNT: '20202020-7a14-4b70-80ae-12bb0d36a881', + CUSTOMER_ACQUISITION_TREND: '20202020-4ca1-4f7e-8089-4ef61c274675', + CUSTOMER_SEGMENTS_PIE: '20202020-3ff4-42fb-881f-38afbee5a503', + CUSTOMER_SATISFACTION_GAUGE: '20202020-d82b-410b-8e94-93dfbb29e60b', + CUSTOMER_RETENTION_RATE: '20202020-79f8-4136-baf8-e12c1bfa12a2', + CUSTOMER_LIFETIME_VALUE: '20202020-e596-4287-a045-62c56a0ce80b', + + TEAM_ACTIVITY_OVERVIEW: '20202020-480b-499b-83d4-2e7816dfcf8c', + TEAM_PRODUCTIVITY_METRICS: '20202020-2c02-4eb9-acaf-d10cc196326b', + TEAM_GOAL_PROGRESS: '20202020-9fc7-46b9-8a8d-b93e6de9b48a', + TEAM_MEMBER_LEADERBOARD: '20202020-0258-48c9-82d6-de11b3093a46', + + REVENUE_TOTAL_NUMBER: '20202020-80e9-4b4d-8f60-2bb7faac11d8', + REVENUE_GROWTH_TREND: '20202020-ffcd-48bd-ba03-812562e55c85', + REVENUE_BY_PRODUCT: '20202020-943c-4a8f-9975-6b81c58f7a04', + REVENUE_BY_REGION: '20202020-8df7-4d44-a239-9745fa7258b5', + + MARKETING_LEADS_GENERATED: '20202020-778d-4bed-afd7-f5204ac2dc80', + MARKETING_CAMPAIGN_ROI: '20202020-67a0-4390-bae6-087ba213187a', + MARKETING_CHANNEL_PERFORMANCE: '20202020-6b35-4c99-b380-4783e9e2acad', + MARKETING_CONVERSION_FUNNEL: '20202020-5722-4acc-b1d5-ae4f3bc72cf9', + + SUPPORT_TICKET_COUNT: '20202020-3b1c-4bb2-88e6-d899965764d6', + SUPPORT_RESOLUTION_TIME: '20202020-6afc-436f-b746-1151bfddcaa9', + SUPPORT_SATISFACTION_SCORE: '20202020-1e8f-478f-a8c4-c2366bfa7ebd', + SUPPORT_TICKET_BY_PRIORITY: '20202020-3efc-4725-a6a6-d3cf6a0a2f75', + + PRODUCT_ACTIVE_USERS: '20202020-db70-403d-ae63-e05094fb59b4', + PRODUCT_FEATURE_ADOPTION: '20202020-64b7-4b58-aa7f-59ec7fb227ab', + PRODUCT_USAGE_HEATMAP: '20202020-4074-4c7a-880d-244614c618e6', + PRODUCT_USER_ENGAGEMENT: '20202020-9b23-4b94-91da-4b813ae3104d', + + OPERATIONS_EFFICIENCY_GAUGE: '20202020-30fa-4ff4-bce2-095e38e7b418', + OPERATIONS_COST_BREAKDOWN: '20202020-0ec9-493a-99f9-fef117e8edcb', + OPERATIONS_PROCESS_TIME: '20202020-0d3e-4538-80c7-641a0d51a09c', + OPERATIONS_ERROR_RATE: '20202020-a061-4815-89cf-4afe36c6d306', + + FINANCE_CASH_FLOW: '20202020-cf55-4e54-9f25-b5aaed168ebe', + FINANCE_EXPENSES_PIE: '20202020-1d79-49fd-8cb5-13a1c3249239', + FINANCE_PROFIT_MARGIN: '20202020-31fd-488a-a69a-674ebe1f675b', + FINANCE_BUDGET_VARIANCE: '20202020-f02d-4861-853a-db77b9b9e543', + + EXECUTIVE_KEY_METRICS: '20202020-bb61-44fd-976b-8b0fc40fb4b4', + EXECUTIVE_COMPANY_HEALTH: '20202020-9f8d-4a74-91b1-9ae6646a8c47', + EXECUTIVE_QUARTERLY_REVIEW: '20202020-4762-407c-981c-f87911675a3a', + EXECUTIVE_STRATEGIC_GOALS: '20202020-ac35-4961-9ca4-12e4ecf8d138', +}; + +export const PAGE_LAYOUT_WIDGET_DATA_SEEDS: PageLayoutWidgetDataSeed[] = [ + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.SALES_PIPELINE_NUMBER, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.SALES_OVERVIEW, + title: 'Pipeline Value', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 0, rowSpan: 2, columnSpan: 3 }, + configuration: { graphType: 'NUMBER' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.SALES_CONVERSION_GAUGE, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.SALES_OVERVIEW, + title: 'Conversion Rate', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 3, rowSpan: 4, columnSpan: 4 }, + configuration: { graphType: 'GAUGE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.SALES_MONTHLY_REVENUE, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.SALES_OVERVIEW, + title: 'Monthly Revenue', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 7, rowSpan: 8, columnSpan: 5 }, + configuration: { graphType: 'LINE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.SALES_DEALS_BY_STAGE, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.SALES_OVERVIEW, + title: 'Deals by Stage', + type: WidgetType.GRAPH, + gridPosition: { row: 4, column: 0, rowSpan: 4, columnSpan: 6 }, + configuration: { graphType: 'BAR' }, + objectMetadataId: null, + }, + + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.SALES_TOP_PERFORMERS, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.SALES_DETAILS, + title: 'Top Sales Performers', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 0, rowSpan: 5, columnSpan: 5 }, + configuration: { graphType: 'PIE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.SALES_FORECAST_LINE, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.SALES_DETAILS, + title: 'Sales Forecast', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 5, rowSpan: 12, columnSpan: 7 }, + configuration: { graphType: 'LINE' }, + objectMetadataId: null, + }, + + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.CUSTOMER_TOTAL_COUNT, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.CUSTOMER_OVERVIEW, + title: 'Total Customers', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 0, rowSpan: 3, columnSpan: 4 }, + configuration: { graphType: 'NUMBER' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.CUSTOMER_SATISFACTION_GAUGE, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.CUSTOMER_OVERVIEW, + title: 'Satisfaction Score', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 4, rowSpan: 3, columnSpan: 3 }, + configuration: { graphType: 'GAUGE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.CUSTOMER_SEGMENTS_PIE, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.CUSTOMER_OVERVIEW, + title: 'Customer Segments', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 7, rowSpan: 5, columnSpan: 5 }, + configuration: { graphType: 'PIE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.CUSTOMER_ACQUISITION_TREND, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.CUSTOMER_OVERVIEW, + title: 'Acquisition Trend', + type: WidgetType.GRAPH, + gridPosition: { row: 3, column: 0, rowSpan: 10, columnSpan: 6 }, + configuration: { graphType: 'LINE' }, + objectMetadataId: null, + }, + + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.CUSTOMER_RETENTION_RATE, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.CUSTOMER_ANALYTICS, + title: 'Retention Rate', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 0, rowSpan: 8, columnSpan: 5 }, + configuration: { graphType: 'LINE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.CUSTOMER_LIFETIME_VALUE, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.CUSTOMER_ANALYTICS, + title: 'Lifetime Value Distribution', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 5, rowSpan: 5, columnSpan: 7 }, + configuration: { graphType: 'BAR' }, + objectMetadataId: null, + }, + + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.TEAM_ACTIVITY_OVERVIEW, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.TEAM_OVERVIEW, + title: 'Team Activity', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 0, rowSpan: 4, columnSpan: 6 }, + configuration: { graphType: 'BAR' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.TEAM_GOAL_PROGRESS, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.TEAM_OVERVIEW, + title: 'Goal Progress', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 6, rowSpan: 2, columnSpan: 2 }, + configuration: { graphType: 'GAUGE' }, + objectMetadataId: null, + }, + + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.TEAM_PRODUCTIVITY_METRICS, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.TEAM_METRICS, + title: 'Productivity Metrics', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 0, rowSpan: 10, columnSpan: 6 }, + configuration: { graphType: 'LINE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.TEAM_MEMBER_LEADERBOARD, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.TEAM_METRICS, + title: 'Team Leaderboard', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 6, rowSpan: 6, columnSpan: 6 }, + configuration: { graphType: 'BAR' }, + objectMetadataId: null, + }, + + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.REVENUE_TOTAL_NUMBER, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.REVENUE_MAIN, + title: 'Total Revenue', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 0, rowSpan: 2, columnSpan: 3 }, + configuration: { graphType: 'NUMBER' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.REVENUE_GROWTH_TREND, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.REVENUE_MAIN, + title: 'Revenue Growth', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 3, rowSpan: 12, columnSpan: 7 }, + configuration: { graphType: 'LINE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.REVENUE_BY_PRODUCT, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.REVENUE_MAIN, + title: 'Revenue by Product', + type: WidgetType.GRAPH, + gridPosition: { row: 2, column: 0, rowSpan: 3, columnSpan: 3 }, + configuration: { graphType: 'PIE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.REVENUE_BY_REGION, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.REVENUE_MAIN, + title: 'Revenue by Region', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 10, rowSpan: 4, columnSpan: 2 }, + configuration: { graphType: 'BAR' }, + objectMetadataId: null, + }, + + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.MARKETING_LEADS_GENERATED, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.MARKETING_MAIN, + title: 'Leads Generated', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 0, rowSpan: 1, columnSpan: 2 }, + configuration: { graphType: 'NUMBER' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.MARKETING_CAMPAIGN_ROI, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.MARKETING_MAIN, + title: 'Campaign ROI', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 2, rowSpan: 3, columnSpan: 3 }, + configuration: { graphType: 'GAUGE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.MARKETING_CHANNEL_PERFORMANCE, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.MARKETING_MAIN, + title: 'Channel Performance', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 5, rowSpan: 4, columnSpan: 6 }, + configuration: { graphType: 'BAR' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.MARKETING_CONVERSION_FUNNEL, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.MARKETING_MAIN, + title: 'Conversion Funnel', + type: WidgetType.GRAPH, + gridPosition: { row: 3, column: 0, rowSpan: 5, columnSpan: 8 }, + configuration: { graphType: 'BAR' }, + objectMetadataId: null, + }, + + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.SUPPORT_TICKET_COUNT, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.SUPPORT_MAIN, + title: 'Open Tickets', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 0, rowSpan: 2, columnSpan: 3 }, + configuration: { graphType: 'NUMBER' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.SUPPORT_RESOLUTION_TIME, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.SUPPORT_MAIN, + title: 'Avg Resolution Time', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 3, rowSpan: 3, columnSpan: 4 }, + configuration: { graphType: 'NUMBER' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.SUPPORT_SATISFACTION_SCORE, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.SUPPORT_MAIN, + title: 'Customer Satisfaction', + type: WidgetType.GRAPH, + gridPosition: { row: 2, column: 0, rowSpan: 3, columnSpan: 3 }, + configuration: { graphType: 'GAUGE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.SUPPORT_TICKET_BY_PRIORITY, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.SUPPORT_MAIN, + title: 'Tickets by Priority', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 7, rowSpan: 4, columnSpan: 4 }, + configuration: { graphType: 'PIE' }, + objectMetadataId: null, + }, + + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.PRODUCT_ACTIVE_USERS, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.PRODUCT_MAIN, + title: 'Active Users', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 0, rowSpan: 2, columnSpan: 3 }, + configuration: { graphType: 'NUMBER' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.PRODUCT_FEATURE_ADOPTION, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.PRODUCT_MAIN, + title: 'Feature Adoption', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 3, rowSpan: 6, columnSpan: 8 }, + configuration: { graphType: 'BAR' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.PRODUCT_USER_ENGAGEMENT, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.PRODUCT_MAIN, + title: 'User Engagement', + type: WidgetType.GRAPH, + gridPosition: { row: 2, column: 0, rowSpan: 10, columnSpan: 6 }, + configuration: { graphType: 'LINE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.PRODUCT_USAGE_HEATMAP, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.PRODUCT_MAIN, + title: 'Usage Patterns', + type: WidgetType.GRAPH, + gridPosition: { row: 6, column: 3, rowSpan: 4, columnSpan: 8 }, + configuration: { graphType: 'PIE' }, + objectMetadataId: null, + }, + + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.OPERATIONS_EFFICIENCY_GAUGE, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.OPERATIONS_MAIN, + title: 'Operational Efficiency', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 0, rowSpan: 2, columnSpan: 2 }, + configuration: { graphType: 'GAUGE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.OPERATIONS_COST_BREAKDOWN, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.OPERATIONS_MAIN, + title: 'Cost Breakdown', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 2, rowSpan: 4, columnSpan: 4 }, + configuration: { graphType: 'PIE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.OPERATIONS_PROCESS_TIME, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.OPERATIONS_MAIN, + title: 'Process Time Trends', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 6, rowSpan: 10, columnSpan: 6 }, + configuration: { graphType: 'LINE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.OPERATIONS_ERROR_RATE, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.OPERATIONS_MAIN, + title: 'Error Rate', + type: WidgetType.GRAPH, + gridPosition: { row: 4, column: 0, rowSpan: 3, columnSpan: 5 }, + configuration: { graphType: 'BAR' }, + objectMetadataId: null, + }, + + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.FINANCE_CASH_FLOW, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.FINANCE_MAIN, + title: 'Cash Flow', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 0, rowSpan: 10, columnSpan: 6 }, + configuration: { graphType: 'LINE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.FINANCE_EXPENSES_PIE, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.FINANCE_MAIN, + title: 'Expense Categories', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 6, rowSpan: 5, columnSpan: 5 }, + configuration: { graphType: 'PIE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.FINANCE_PROFIT_MARGIN, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.FINANCE_MAIN, + title: 'Profit Margin', + type: WidgetType.GRAPH, + gridPosition: { row: 5, column: 6, rowSpan: 3, columnSpan: 3 }, + configuration: { graphType: 'GAUGE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.FINANCE_BUDGET_VARIANCE, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.FINANCE_MAIN, + title: 'Budget vs Actual', + type: WidgetType.GRAPH, + gridPosition: { row: 5, column: 9, rowSpan: 4, columnSpan: 3 }, + configuration: { graphType: 'BAR' }, + objectMetadataId: null, + }, + + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.EXECUTIVE_KEY_METRICS, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.EXECUTIVE_MAIN, + title: 'Key Business Metrics', + type: WidgetType.GRAPH, + gridPosition: { row: 0, column: 0, rowSpan: 3, columnSpan: 12 }, + configuration: { graphType: 'PIE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.EXECUTIVE_COMPANY_HEALTH, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.EXECUTIVE_MAIN, + title: 'Company Health Score', + type: WidgetType.GRAPH, + gridPosition: { row: 3, column: 0, rowSpan: 4, columnSpan: 4 }, + configuration: { graphType: 'GAUGE' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.EXECUTIVE_QUARTERLY_REVIEW, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.EXECUTIVE_MAIN, + title: 'Quarterly Performance', + type: WidgetType.GRAPH, + gridPosition: { row: 3, column: 4, rowSpan: 4, columnSpan: 4 }, + configuration: { graphType: 'BAR' }, + objectMetadataId: null, + }, + { + id: PAGE_LAYOUT_WIDGET_DATA_SEED_IDS.EXECUTIVE_STRATEGIC_GOALS, + pageLayoutTabId: PAGE_LAYOUT_TAB_SEED_IDS.EXECUTIVE_MAIN, + title: 'Strategic Goals Progress', + type: WidgetType.GRAPH, + gridPosition: { row: 3, column: 8, rowSpan: 8, columnSpan: 4 }, + configuration: { graphType: 'LINE' }, + objectMetadataId: null, + }, +]; diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/services/dev-seeder-data.service.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/services/dev-seeder-data.service.ts index 3ffc392a57..61f7dc0350 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/services/dev-seeder-data.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/services/dev-seeder-data.service.ts @@ -3,6 +3,7 @@ import { InjectDataSource } from '@nestjs/typeorm'; import { DataSource } from 'typeorm'; +import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; 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'; @@ -30,6 +31,10 @@ import { CONNECTED_ACCOUNT_DATA_SEED_COLUMNS, CONNECTED_ACCOUNT_DATA_SEEDS, } from 'src/engine/workspace-manager/dev-seeder/data/constants/connected-account-data-seeds.constant'; +import { + DASHBOARD_DATA_SEED_COLUMNS, + DASHBOARD_DATA_SEEDS, +} from 'src/engine/workspace-manager/dev-seeder/data/constants/dashboard-data-seeds.constant'; import { MESSAGE_CHANNEL_DATA_SEED_COLUMNS, MESSAGE_CHANNEL_DATA_SEEDS, @@ -89,7 +94,10 @@ import { import { TimelineActivitySeederService } from 'src/engine/workspace-manager/dev-seeder/data/services/timeline-activity-seeder.service'; import { prefillWorkflows } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-workflows'; -const getRecordSeedsConfigs = (workspaceId: string) => [ +const getRecordSeedsConfigs = ( + workspaceId: string, + featureFlags?: Record, +) => [ { tableName: 'workspaceMember', pgColumns: WORKSPACE_MEMBER_DATA_SEED_COLUMNS, @@ -100,6 +108,15 @@ const getRecordSeedsConfigs = (workspaceId: string) => [ pgColumns: COMPANY_DATA_SEED_COLUMNS, recordSeeds: COMPANY_DATA_SEEDS, }, + ...(featureFlags?.[FeatureFlagKey.IS_PAGE_LAYOUT_ENABLED] + ? [ + { + tableName: 'dashboard', + pgColumns: DASHBOARD_DATA_SEED_COLUMNS, + recordSeeds: DASHBOARD_DATA_SEEDS, + }, + ] + : []), { tableName: 'person', pgColumns: PERSON_DATA_SEED_COLUMNS, @@ -204,16 +221,21 @@ export class DevSeederDataService { public async seed({ schemaName, workspaceId, + featureFlags, }: { schemaName: string; workspaceId: string; + featureFlags?: Record; }) { const objectMetadataItems = await this.objectMetadataService.findManyWithinWorkspace(workspaceId); await this.coreDataSource.transaction( async (entityManager: WorkspaceEntityManager) => { - for (const recordSeedsConfig of getRecordSeedsConfigs(workspaceId)) { + for (const recordSeedsConfig of getRecordSeedsConfigs( + workspaceId, + featureFlags, + )) { const objectMetadata = objectMetadataItems.find( (item) => computeTableName(item.nameSingular, item.isCustom) === diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/services/dev-seeder.service.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/services/dev-seeder.service.ts index ce78ebbda8..6a5e9d68f1 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/services/dev-seeder.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/services/dev-seeder.service.ts @@ -76,6 +76,7 @@ export class DevSeederService { await this.devSeederDataService.seed({ schemaName: dataSourceMetadata.schema, workspaceId, + featureFlags, }); await this.workspaceCacheStorageService.flush(workspaceId, undefined); diff --git a/packages/twenty-server/src/modules/attachment/standard-objects/attachment.workspace-entity.ts b/packages/twenty-server/src/modules/attachment/standard-objects/attachment.workspace-entity.ts index 681372c800..170601ce02 100644 --- a/packages/twenty-server/src/modules/attachment/standard-objects/attachment.workspace-entity.ts +++ b/packages/twenty-server/src/modules/attachment/standard-objects/attachment.workspace-entity.ts @@ -5,11 +5,13 @@ import { RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metada import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface'; import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface'; +import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; import { CustomWorkspaceEntity } from 'src/engine/twenty-orm/custom.workspace-entity'; import { WorkspaceDynamicRelation } from 'src/engine/twenty-orm/decorators/workspace-dynamic-relation.decorator'; import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; +import { WorkspaceGate } from 'src/engine/twenty-orm/decorators/workspace-gate.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; @@ -169,10 +171,16 @@ export class AttachmentWorkspaceEntity extends BaseWorkspaceEntity { inverseSideFieldKey: 'attachments', onDelete: RelationOnDeleteAction.CASCADE, }) + @WorkspaceGate({ + featureFlag: FeatureFlagKey.IS_PAGE_LAYOUT_ENABLED, + }) @WorkspaceIsNullable() dashboard: Relation | null; @WorkspaceJoinColumn('dashboard') + @WorkspaceGate({ + featureFlag: FeatureFlagKey.IS_PAGE_LAYOUT_ENABLED, + }) dashboardId: string | null; @WorkspaceDynamicRelation({ diff --git a/packages/twenty-server/src/modules/favorite/standard-objects/favorite.workspace-entity.ts b/packages/twenty-server/src/modules/favorite/standard-objects/favorite.workspace-entity.ts index 17b3ec393b..f4b4c8d439 100644 --- a/packages/twenty-server/src/modules/favorite/standard-objects/favorite.workspace-entity.ts +++ b/packages/twenty-server/src/modules/favorite/standard-objects/favorite.workspace-entity.ts @@ -4,12 +4,14 @@ import { FieldMetadataType } from 'twenty-shared/types'; import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface'; import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface'; +import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { RelationOnDeleteAction } from 'src/engine/metadata-modules/relation-metadata/relation-on-delete-action.type'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; import { CustomWorkspaceEntity } from 'src/engine/twenty-orm/custom.workspace-entity'; import { WorkspaceDynamicRelation } from 'src/engine/twenty-orm/decorators/workspace-dynamic-relation.decorator'; import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; +import { WorkspaceGate } from 'src/engine/twenty-orm/decorators/workspace-gate.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator'; @@ -221,10 +223,16 @@ export class FavoriteWorkspaceEntity extends BaseWorkspaceEntity { inverseSideFieldKey: 'favorites', onDelete: RelationOnDeleteAction.CASCADE, }) + @WorkspaceGate({ + featureFlag: FeatureFlagKey.IS_PAGE_LAYOUT_ENABLED, + }) @WorkspaceIsNullable() dashboard: Relation | null; @WorkspaceJoinColumn('dashboard') + @WorkspaceGate({ + featureFlag: FeatureFlagKey.IS_PAGE_LAYOUT_ENABLED, + }) dashboardId: string; @WorkspaceField({ diff --git a/packages/twenty-server/src/modules/timeline/standard-objects/timeline-activity.workspace-entity.ts b/packages/twenty-server/src/modules/timeline/standard-objects/timeline-activity.workspace-entity.ts index 880dc2021e..032f6bea29 100644 --- a/packages/twenty-server/src/modules/timeline/standard-objects/timeline-activity.workspace-entity.ts +++ b/packages/twenty-server/src/modules/timeline/standard-objects/timeline-activity.workspace-entity.ts @@ -5,11 +5,13 @@ import { RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metada import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface'; import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface'; +import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; import { CustomWorkspaceEntity } from 'src/engine/twenty-orm/custom.workspace-entity'; import { WorkspaceDynamicRelation } from 'src/engine/twenty-orm/decorators/workspace-dynamic-relation.decorator'; import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; +import { WorkspaceGate } from 'src/engine/twenty-orm/decorators/workspace-gate.decorator'; import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; @@ -254,10 +256,16 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity { inverseSideFieldKey: 'timelineActivities', onDelete: RelationOnDeleteAction.SET_NULL, }) + @WorkspaceGate({ + featureFlag: FeatureFlagKey.IS_PAGE_LAYOUT_ENABLED, + }) @WorkspaceIsNullable() dashboard: Relation | null; @WorkspaceJoinColumn('dashboard') + @WorkspaceGate({ + featureFlag: FeatureFlagKey.IS_PAGE_LAYOUT_ENABLED, + }) dashboardId: string | null; @WorkspaceDynamicRelation({ diff --git a/packages/twenty-server/test/integration/graphql/suites/page-layout/page-layout-resolver.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/page-layout/page-layout-resolver.integration-spec.ts index 97c73b92b3..193aa17509 100644 --- a/packages/twenty-server/test/integration/graphql/suites/page-layout/page-layout-resolver.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/page-layout/page-layout-resolver.integration-spec.ts @@ -10,15 +10,15 @@ import { assertGraphQLSuccessfulResponse, } from 'test/integration/graphql/utils/graphql-test-assertions.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; -import { - cleanupPageLayoutRecordsWithGraphQL, - createTestPageLayoutWithGraphQL, -} from 'test/integration/graphql/utils/page-layout-graphql.util'; +import { createTestPageLayoutWithGraphQL } from 'test/integration/graphql/utils/page-layout-graphql.util'; import { restorePageLayoutOperationFactory } from 'test/integration/graphql/utils/restore-page-layout-operation-factory.util'; import { updatePageLayoutOperationFactory } from 'test/integration/graphql/utils/update-page-layout-operation-factory.util'; import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util'; import { deleteOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata.util'; -import { assertPageLayoutStructure } from 'test/integration/utils/page-layout-test.util'; +import { + assertPageLayoutStructure, + cleanupPageLayoutRecords, +} from 'test/integration/utils/page-layout-test.util'; import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PageLayoutType } from 'src/engine/core-modules/page-layout/enums/page-layout-type.enum'; @@ -52,21 +52,14 @@ describe('Page Layout Resolver', () => { await deleteOneObjectMetadata({ input: { idToDelete: testObjectMetadataId }, }); + await cleanupPageLayoutRecords(); }); - afterEach(async () => { - await cleanupPageLayoutRecordsWithGraphQL(); + beforeEach(async () => { + await cleanupPageLayoutRecords(); }); describe('getPageLayouts', () => { - it('should return empty array when no page layouts exist', async () => { - const operation = findPageLayoutsOperationFactory(); - const response = await makeGraphqlAPIRequest(operation); - - assertGraphQLSuccessfulResponse(response); - expect(response.body.data.getPageLayouts).toEqual([]); - }); - it('should return all page layouts for workspace when no objectMetadataId provided', async () => { const pageLayoutName = 'Test Page Layout for Workspace'; diff --git a/packages/twenty-server/test/integration/graphql/suites/search/search-resolver.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/search/search-resolver.integration-spec.ts index 7cbdd2453a..1a782de2c3 100644 --- a/packages/twenty-server/test/integration/graphql/suites/search/search-resolver.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/search/search-resolver.integration-spec.ts @@ -43,6 +43,7 @@ describe('SearchResolver', () => { await deleteAllRecords('task'); await deleteAllRecords('noteTarget'); await deleteAllRecords('taskTarget'); + await deleteAllRecords('dashboard'); await deleteAllRecords('_pet'); await deleteAllRecords('_surveyResult');