diff --git a/packages/twenty-front/codegen-metadata.cjs b/packages/twenty-front/codegen-metadata.cjs index 8e025eeee2..10978f53dd 100644 --- a/packages/twenty-front/codegen-metadata.cjs +++ b/packages/twenty-front/codegen-metadata.cjs @@ -27,6 +27,8 @@ module.exports = { './src/modules/file/graphql/**/*.{ts,tsx}', './src/modules/onboarding/graphql/**/*.{ts,tsx}', + './src/modules/page-layout/widgets/**/graphql/**/*.{ts,tsx}', + '!./src/**/*.test.{ts,tsx}', '!./src/**/*.stories.{ts,tsx}', '!./src/**/__mocks__/*.ts', diff --git a/packages/twenty-front/codegen.cjs b/packages/twenty-front/codegen.cjs index f372b63f67..262769bd9c 100644 --- a/packages/twenty-front/codegen.cjs +++ b/packages/twenty-front/codegen.cjs @@ -20,7 +20,6 @@ module.exports = { './src/modules/subscription/graphql/**/*.{ts,tsx}', './src/modules/page-layout/graphql/**/*.{ts,tsx}', - './src/modules/page-layout/widgets/**/graphql/**/*.{ts,tsx}', '!./src/**/*.test.{ts,tsx}', '!./src/**/*.stories.{ts,tsx}', diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 0bf19901dc..eb4fc9d41f 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -1637,6 +1637,17 @@ export type FrontComponent = { updatedAt: Scalars['DateTime']; }; +export type FrontComponentCode = { + __typename?: 'FrontComponentCode'; + sourceCode: Scalars['String']; +}; + +export type FrontComponentConfiguration = { + __typename?: 'FrontComponentConfiguration'; + configurationType: WidgetConfigurationType; + frontComponentId: Scalars['UUID']; +}; + export type FullName = { __typename?: 'FullName'; firstName: Scalars['String']; @@ -3611,6 +3622,7 @@ export type Query = { getCoreViews: Array; getDatabaseConfigVariable: ConfigVariable; getEmailingDomains: Array; + getFrontComponentCode: FrontComponentCode; getIndicatorHealthStatus: AdminPanelHealthServiceData; getMeteredProductsUsage: Array; getPageLayout?: Maybe; @@ -3839,6 +3851,11 @@ export type QueryGetDatabaseConfigVariableArgs = { }; +export type QueryGetFrontComponentCodeArgs = { + id: Scalars['UUID']; +}; + + export type QueryGetIndicatorHealthStatusArgs = { indicatorId: HealthIndicatorId; }; @@ -5230,7 +5247,7 @@ export type Webhook = { updatedAt: Scalars['DateTime']; }; -export type WidgetConfiguration = AggregateChartConfiguration | BarChartConfiguration | CalendarConfiguration | EmailsConfiguration | FieldConfiguration | FieldRichTextConfiguration | FieldsConfiguration | FilesConfiguration | GaugeChartConfiguration | IframeConfiguration | LineChartConfiguration | NotesConfiguration | PieChartConfiguration | StandaloneRichTextConfiguration | TasksConfiguration | TimelineConfiguration | ViewConfiguration | WorkflowConfiguration | WorkflowRunConfiguration | WorkflowVersionConfiguration; +export type WidgetConfiguration = AggregateChartConfiguration | BarChartConfiguration | CalendarConfiguration | EmailsConfiguration | FieldConfiguration | FieldRichTextConfiguration | FieldsConfiguration | FilesConfiguration | FrontComponentConfiguration | GaugeChartConfiguration | IframeConfiguration | LineChartConfiguration | NotesConfiguration | PieChartConfiguration | StandaloneRichTextConfiguration | TasksConfiguration | TimelineConfiguration | ViewConfiguration | WorkflowConfiguration | WorkflowRunConfiguration | WorkflowVersionConfiguration; export enum WidgetConfigurationType { AGGREGATE_CHART = 'AGGREGATE_CHART', @@ -5241,6 +5258,7 @@ export enum WidgetConfigurationType { FIELDS = 'FIELDS', FIELD_RICH_TEXT = 'FIELD_RICH_TEXT', FILES = 'FILES', + FRONT_COMPONENT = 'FRONT_COMPONENT', GAUGE_CHART = 'GAUGE_CHART', IFRAME = 'IFRAME', LINE_CHART = 'LINE_CHART', @@ -5262,6 +5280,7 @@ export enum WidgetType { FIELDS = 'FIELDS', FIELD_RICH_TEXT = 'FIELD_RICH_TEXT', FILES = 'FILES', + FRONT_COMPONENT = 'FRONT_COMPONENT', GRAPH = 'GRAPH', IFRAME = 'IFRAME', NOTES = 'NOTES', @@ -6092,6 +6111,34 @@ export type SkipSyncEmailOnboardingStepMutationVariables = Exact<{ [key: string] export type SkipSyncEmailOnboardingStepMutation = { __typename?: 'Mutation', skipSyncEmailOnboardingStep: { __typename?: 'OnboardingStepSuccess', success: boolean } }; +export type GetFrontComponentCodeQueryVariables = Exact<{ + id: Scalars['UUID']; +}>; + + +export type GetFrontComponentCodeQuery = { __typename?: 'Query', getFrontComponentCode: { __typename?: 'FrontComponentCode', sourceCode: string } }; + +export type BarChartDataQueryVariables = Exact<{ + input: BarChartDataInput; +}>; + + +export type BarChartDataQuery = { __typename?: 'Query', barChartData: { __typename?: 'BarChartDataOutput', data: Array, indexBy: string, keys: Array, xAxisLabel: string, yAxisLabel: string, showLegend: boolean, showDataLabels: boolean, layout: BarChartLayout, groupMode: BarChartGroupMode, hasTooManyGroups: boolean, formattedToRawLookup: any, series: Array<{ __typename?: 'BarChartSeries', key: string, label: string }> } }; + +export type LineChartDataQueryVariables = Exact<{ + input: LineChartDataInput; +}>; + + +export type LineChartDataQuery = { __typename?: 'Query', lineChartData: { __typename?: 'LineChartDataOutput', xAxisLabel: string, yAxisLabel: string, showLegend: boolean, showDataLabels: boolean, hasTooManyGroups: boolean, formattedToRawLookup: any, series: Array<{ __typename?: 'LineChartSeries', id: string, label: string, data: Array<{ __typename?: 'LineChartDataPoint', x: string, y: number }> }> } }; + +export type PieChartDataQueryVariables = Exact<{ + input: PieChartDataInput; +}>; + + +export type PieChartDataQuery = { __typename?: 'Query', pieChartData: { __typename?: 'PieChartDataOutput', showLegend: boolean, showDataLabels: boolean, showCenterMetric: boolean, hasTooManyGroups: boolean, formattedToRawLookup: any, data: Array<{ __typename?: 'PieChartDataItem', id: string, value: number }> } }; + export type SaveImapSmtpCaldavAccountMutationVariables = Exact<{ accountOwnerId: Scalars['UUID']; handle: Scalars['String']; @@ -10669,6 +10716,181 @@ export function useSkipSyncEmailOnboardingStepMutation(baseOptions?: Apollo.Muta export type SkipSyncEmailOnboardingStepMutationHookResult = ReturnType; export type SkipSyncEmailOnboardingStepMutationResult = Apollo.MutationResult; export type SkipSyncEmailOnboardingStepMutationOptions = Apollo.BaseMutationOptions; +export const GetFrontComponentCodeDocument = gql` + query GetFrontComponentCode($id: UUID!) { + getFrontComponentCode(id: $id) { + sourceCode + } +} + `; + +/** + * __useGetFrontComponentCodeQuery__ + * + * To run a query within a React component, call `useGetFrontComponentCodeQuery` and pass it any options that fit your needs. + * When your component renders, `useGetFrontComponentCodeQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetFrontComponentCodeQuery({ + * variables: { + * id: // value for 'id' + * }, + * }); + */ +export function useGetFrontComponentCodeQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(GetFrontComponentCodeDocument, options); + } +export function useGetFrontComponentCodeLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(GetFrontComponentCodeDocument, options); + } +export type GetFrontComponentCodeQueryHookResult = ReturnType; +export type GetFrontComponentCodeLazyQueryHookResult = ReturnType; +export type GetFrontComponentCodeQueryResult = Apollo.QueryResult; +export const BarChartDataDocument = gql` + query BarChartData($input: BarChartDataInput!) { + barChartData(input: $input) { + data + indexBy + keys + series { + key + label + } + xAxisLabel + yAxisLabel + showLegend + showDataLabels + layout + groupMode + hasTooManyGroups + formattedToRawLookup + } +} + `; + +/** + * __useBarChartDataQuery__ + * + * To run a query within a React component, call `useBarChartDataQuery` and pass it any options that fit your needs. + * When your component renders, `useBarChartDataQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useBarChartDataQuery({ + * variables: { + * input: // value for 'input' + * }, + * }); + */ +export function useBarChartDataQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(BarChartDataDocument, options); + } +export function useBarChartDataLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(BarChartDataDocument, options); + } +export type BarChartDataQueryHookResult = ReturnType; +export type BarChartDataLazyQueryHookResult = ReturnType; +export type BarChartDataQueryResult = Apollo.QueryResult; +export const LineChartDataDocument = gql` + query LineChartData($input: LineChartDataInput!) { + lineChartData(input: $input) { + series { + id + label + data { + x + y + } + } + xAxisLabel + yAxisLabel + showLegend + showDataLabels + hasTooManyGroups + formattedToRawLookup + } +} + `; + +/** + * __useLineChartDataQuery__ + * + * To run a query within a React component, call `useLineChartDataQuery` and pass it any options that fit your needs. + * When your component renders, `useLineChartDataQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useLineChartDataQuery({ + * variables: { + * input: // value for 'input' + * }, + * }); + */ +export function useLineChartDataQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(LineChartDataDocument, options); + } +export function useLineChartDataLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(LineChartDataDocument, options); + } +export type LineChartDataQueryHookResult = ReturnType; +export type LineChartDataLazyQueryHookResult = ReturnType; +export type LineChartDataQueryResult = Apollo.QueryResult; +export const PieChartDataDocument = gql` + query PieChartData($input: PieChartDataInput!) { + pieChartData(input: $input) { + data { + id + value + } + showLegend + showDataLabels + showCenterMetric + hasTooManyGroups + formattedToRawLookup + } +} + `; + +/** + * __usePieChartDataQuery__ + * + * To run a query within a React component, call `usePieChartDataQuery` and pass it any options that fit your needs. + * When your component renders, `usePieChartDataQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = usePieChartDataQuery({ + * variables: { + * input: // value for 'input' + * }, + * }); + */ +export function usePieChartDataQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(PieChartDataDocument, options); + } +export function usePieChartDataLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(PieChartDataDocument, options); + } +export type PieChartDataQueryHookResult = ReturnType; +export type PieChartDataLazyQueryHookResult = ReturnType; +export type PieChartDataQueryResult = Apollo.QueryResult; export const SaveImapSmtpCaldavAccountDocument = gql` mutation SaveImapSmtpCaldavAccount($accountOwnerId: UUID!, $handle: String!, $connectionParameters: EmailAccountConnectionParameters!, $id: UUID) { saveImapSmtpCaldavAccount( diff --git a/packages/twenty-front/src/generated/graphql.ts b/packages/twenty-front/src/generated/graphql.ts index b43ccdd27d..8e916a23ca 100644 --- a/packages/twenty-front/src/generated/graphql.ts +++ b/packages/twenty-front/src/generated/graphql.ts @@ -1604,6 +1604,17 @@ export type FrontComponent = { updatedAt: Scalars['DateTime']; }; +export type FrontComponentCode = { + __typename?: 'FrontComponentCode'; + sourceCode: Scalars['String']; +}; + +export type FrontComponentConfiguration = { + __typename?: 'FrontComponentConfiguration'; + configurationType: WidgetConfigurationType; + frontComponentId: Scalars['UUID']; +}; + export type FullName = { __typename?: 'FullName'; firstName: Scalars['String']; @@ -5005,7 +5016,7 @@ export type Webhook = { updatedAt: Scalars['DateTime']; }; -export type WidgetConfiguration = AggregateChartConfiguration | BarChartConfiguration | CalendarConfiguration | EmailsConfiguration | FieldConfiguration | FieldRichTextConfiguration | FieldsConfiguration | FilesConfiguration | GaugeChartConfiguration | IframeConfiguration | LineChartConfiguration | NotesConfiguration | PieChartConfiguration | StandaloneRichTextConfiguration | TasksConfiguration | TimelineConfiguration | ViewConfiguration | WorkflowConfiguration | WorkflowRunConfiguration | WorkflowVersionConfiguration; +export type WidgetConfiguration = AggregateChartConfiguration | BarChartConfiguration | CalendarConfiguration | EmailsConfiguration | FieldConfiguration | FieldRichTextConfiguration | FieldsConfiguration | FilesConfiguration | FrontComponentConfiguration | GaugeChartConfiguration | IframeConfiguration | LineChartConfiguration | NotesConfiguration | PieChartConfiguration | StandaloneRichTextConfiguration | TasksConfiguration | TimelineConfiguration | ViewConfiguration | WorkflowConfiguration | WorkflowRunConfiguration | WorkflowVersionConfiguration; export enum WidgetConfigurationType { AGGREGATE_CHART = 'AGGREGATE_CHART', @@ -5016,6 +5027,7 @@ export enum WidgetConfigurationType { FIELDS = 'FIELDS', FIELD_RICH_TEXT = 'FIELD_RICH_TEXT', FILES = 'FILES', + FRONT_COMPONENT = 'FRONT_COMPONENT', GAUGE_CHART = 'GAUGE_CHART', IFRAME = 'IFRAME', LINE_CHART = 'LINE_CHART', @@ -5037,6 +5049,7 @@ export enum WidgetType { FIELDS = 'FIELDS', FIELD_RICH_TEXT = 'FIELD_RICH_TEXT', FILES = 'FILES', + FRONT_COMPONENT = 'FRONT_COMPONENT', GRAPH = 'GRAPH', IFRAME = 'IFRAME', NOTES = 'NOTES', @@ -5334,7 +5347,7 @@ export type SearchQueryVariables = Exact<{ export type SearchQuery = { __typename?: 'Query', search: { __typename?: 'SearchResultConnection', edges: Array<{ __typename?: 'SearchResultEdge', cursor: string, node: { __typename?: 'SearchRecord', recordId: any, objectNameSingular: string, objectLabelSingular: string, label: string, imageUrl?: string | null, tsRankCD: number, tsRank: number } }>, pageInfo: { __typename?: 'SearchResultPageInfo', hasNextPage: boolean, endCursor?: string | null } } }; -export type PageLayoutWidgetFragmentFragment = { __typename?: 'PageLayoutWidget', id: any, title: string, type: WidgetType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: any, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, configuration: { __typename?: 'AggregateChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: any, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, layout: BarChartLayout, isCumulative?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'CalendarConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'EmailsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldRichTextConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FilesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'GaugeChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', configurationType: WidgetConfigurationType, url?: string | null } | { __typename?: 'LineChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'NotesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'PieChartConfiguration', configurationType: WidgetConfigurationType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, manualSortOrder?: Array | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, hideEmptyCategory?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', configurationType: WidgetConfigurationType, body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } | { __typename?: 'TasksConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'TimelineConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'ViewConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowRunConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowVersionConfiguration', configurationType: WidgetConfigurationType } }; +export type PageLayoutWidgetFragmentFragment = { __typename?: 'PageLayoutWidget', id: any, title: string, type: WidgetType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: any, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, configuration: { __typename?: 'AggregateChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: any, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, layout: BarChartLayout, isCumulative?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'CalendarConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'EmailsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldRichTextConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FilesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FrontComponentConfiguration', configurationType: WidgetConfigurationType, frontComponentId: any } | { __typename?: 'GaugeChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', configurationType: WidgetConfigurationType, url?: string | null } | { __typename?: 'LineChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'NotesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'PieChartConfiguration', configurationType: WidgetConfigurationType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, manualSortOrder?: Array | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, hideEmptyCategory?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', configurationType: WidgetConfigurationType, body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } | { __typename?: 'TasksConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'TimelineConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'ViewConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowRunConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowVersionConfiguration', configurationType: WidgetConfigurationType } }; export type UpdatePageLayoutWithTabsAndWidgetsMutationVariables = Exact<{ id: Scalars['String']; @@ -5342,28 +5355,7 @@ export type UpdatePageLayoutWithTabsAndWidgetsMutationVariables = Exact<{ }>; -export type UpdatePageLayoutWithTabsAndWidgetsMutation = { __typename?: 'Mutation', updatePageLayoutWithTabsAndWidgets: { __typename?: 'PageLayout', id: any, name: string, type: PageLayoutType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, tabs?: Array<{ __typename?: 'PageLayoutTab', id: any, title: string, position: number, pageLayoutId: any, createdAt: string, updatedAt: string, widgets?: Array<{ __typename?: 'PageLayoutWidget', id: any, title: string, type: WidgetType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: any, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, configuration: { __typename?: 'AggregateChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: any, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, layout: BarChartLayout, isCumulative?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'CalendarConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'EmailsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldRichTextConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FilesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'GaugeChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', configurationType: WidgetConfigurationType, url?: string | null } | { __typename?: 'LineChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'NotesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'PieChartConfiguration', configurationType: WidgetConfigurationType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, manualSortOrder?: Array | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, hideEmptyCategory?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', configurationType: WidgetConfigurationType, body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } | { __typename?: 'TasksConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'TimelineConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'ViewConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowRunConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowVersionConfiguration', configurationType: WidgetConfigurationType } }> | null }> | null } }; - -export type BarChartDataQueryVariables = Exact<{ - input: BarChartDataInput; -}>; - - -export type BarChartDataQuery = { __typename?: 'Query', barChartData: { __typename?: 'BarChartDataOutput', data: Array, indexBy: string, keys: Array, xAxisLabel: string, yAxisLabel: string, showLegend: boolean, showDataLabels: boolean, layout: BarChartLayout, groupMode: BarChartGroupMode, hasTooManyGroups: boolean, formattedToRawLookup: any, series: Array<{ __typename?: 'BarChartSeries', key: string, label: string }> } }; - -export type LineChartDataQueryVariables = Exact<{ - input: LineChartDataInput; -}>; - - -export type LineChartDataQuery = { __typename?: 'Query', lineChartData: { __typename?: 'LineChartDataOutput', xAxisLabel: string, yAxisLabel: string, showLegend: boolean, showDataLabels: boolean, hasTooManyGroups: boolean, formattedToRawLookup: any, series: Array<{ __typename?: 'LineChartSeries', id: string, label: string, data: Array<{ __typename?: 'LineChartDataPoint', x: string, y: number }> }> } }; - -export type PieChartDataQueryVariables = Exact<{ - input: PieChartDataInput; -}>; - - -export type PieChartDataQuery = { __typename?: 'Query', pieChartData: { __typename?: 'PieChartDataOutput', showLegend: boolean, showDataLabels: boolean, showCenterMetric: boolean, hasTooManyGroups: boolean, formattedToRawLookup: any, data: Array<{ __typename?: 'PieChartDataItem', id: string, value: number }> } }; +export type UpdatePageLayoutWithTabsAndWidgetsMutation = { __typename?: 'Mutation', updatePageLayoutWithTabsAndWidgets: { __typename?: 'PageLayout', id: any, name: string, type: PageLayoutType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, tabs?: Array<{ __typename?: 'PageLayoutTab', id: any, title: string, position: number, pageLayoutId: any, createdAt: string, updatedAt: string, widgets?: Array<{ __typename?: 'PageLayoutWidget', id: any, title: string, type: WidgetType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: any, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, configuration: { __typename?: 'AggregateChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: any, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, layout: BarChartLayout, isCumulative?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'CalendarConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'EmailsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldRichTextConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FilesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FrontComponentConfiguration', configurationType: WidgetConfigurationType, frontComponentId: any } | { __typename?: 'GaugeChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', configurationType: WidgetConfigurationType, url?: string | null } | { __typename?: 'LineChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'NotesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'PieChartConfiguration', configurationType: WidgetConfigurationType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, manualSortOrder?: Array | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, hideEmptyCategory?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', configurationType: WidgetConfigurationType, body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } | { __typename?: 'TasksConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'TimelineConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'ViewConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowRunConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowVersionConfiguration', configurationType: WidgetConfigurationType } }> | null }> | null } }; export type ViewFieldFragmentFragment = { __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }; @@ -5822,6 +5814,10 @@ export const PageLayoutWidgetFragmentFragmentDoc = gql` ... on WorkflowVersionConfiguration { configurationType } + ... on FrontComponentConfiguration { + configurationType + frontComponentId + } } pageLayoutTabId } @@ -6038,146 +6034,6 @@ export function useUpdatePageLayoutWithTabsAndWidgetsMutation(baseOptions?: Apol export type UpdatePageLayoutWithTabsAndWidgetsMutationHookResult = ReturnType; export type UpdatePageLayoutWithTabsAndWidgetsMutationResult = Apollo.MutationResult; export type UpdatePageLayoutWithTabsAndWidgetsMutationOptions = Apollo.BaseMutationOptions; -export const BarChartDataDocument = gql` - query BarChartData($input: BarChartDataInput!) { - barChartData(input: $input) { - data - indexBy - keys - series { - key - label - } - xAxisLabel - yAxisLabel - showLegend - showDataLabels - layout - groupMode - hasTooManyGroups - formattedToRawLookup - } -} - `; - -/** - * __useBarChartDataQuery__ - * - * To run a query within a React component, call `useBarChartDataQuery` and pass it any options that fit your needs. - * When your component renders, `useBarChartDataQuery` returns an object from Apollo Client that contains loading, error, and data properties - * you can use to render your UI. - * - * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; - * - * @example - * const { data, loading, error } = useBarChartDataQuery({ - * variables: { - * input: // value for 'input' - * }, - * }); - */ -export function useBarChartDataQuery(baseOptions: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(BarChartDataDocument, options); - } -export function useBarChartDataLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(BarChartDataDocument, options); - } -export type BarChartDataQueryHookResult = ReturnType; -export type BarChartDataLazyQueryHookResult = ReturnType; -export type BarChartDataQueryResult = Apollo.QueryResult; -export const LineChartDataDocument = gql` - query LineChartData($input: LineChartDataInput!) { - lineChartData(input: $input) { - series { - id - label - data { - x - y - } - } - xAxisLabel - yAxisLabel - showLegend - showDataLabels - hasTooManyGroups - formattedToRawLookup - } -} - `; - -/** - * __useLineChartDataQuery__ - * - * To run a query within a React component, call `useLineChartDataQuery` and pass it any options that fit your needs. - * When your component renders, `useLineChartDataQuery` returns an object from Apollo Client that contains loading, error, and data properties - * you can use to render your UI. - * - * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; - * - * @example - * const { data, loading, error } = useLineChartDataQuery({ - * variables: { - * input: // value for 'input' - * }, - * }); - */ -export function useLineChartDataQuery(baseOptions: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(LineChartDataDocument, options); - } -export function useLineChartDataLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(LineChartDataDocument, options); - } -export type LineChartDataQueryHookResult = ReturnType; -export type LineChartDataLazyQueryHookResult = ReturnType; -export type LineChartDataQueryResult = Apollo.QueryResult; -export const PieChartDataDocument = gql` - query PieChartData($input: PieChartDataInput!) { - pieChartData(input: $input) { - data { - id - value - } - showLegend - showDataLabels - showCenterMetric - hasTooManyGroups - formattedToRawLookup - } -} - `; - -/** - * __usePieChartDataQuery__ - * - * To run a query within a React component, call `usePieChartDataQuery` and pass it any options that fit your needs. - * When your component renders, `usePieChartDataQuery` returns an object from Apollo Client that contains loading, error, and data properties - * you can use to render your UI. - * - * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; - * - * @example - * const { data, loading, error } = usePieChartDataQuery({ - * variables: { - * input: // value for 'input' - * }, - * }); - */ -export function usePieChartDataQuery(baseOptions: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(PieChartDataDocument, options); - } -export function usePieChartDataLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(PieChartDataDocument, options); - } -export type PieChartDataQueryHookResult = ReturnType; -export type PieChartDataLazyQueryHookResult = ReturnType; -export type PieChartDataQueryResult = Apollo.QueryResult; export const CreateCoreViewDocument = gql` mutation CreateCoreView($input: CreateViewInput!) { createCoreView(input: $input) { diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType.ts index 50ef98671c..789fcf1e89 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType.ts @@ -7,6 +7,7 @@ import { type EmailsConfiguration, type FieldRichTextConfiguration, type FilesConfiguration, + type FrontComponentConfiguration, type GaugeChartConfiguration, type IframeConfiguration, type LineChartConfiguration, @@ -36,6 +37,12 @@ type WidgetConfigurationTypenameMap = { CalendarConfiguration: Omit & { configurationType: WidgetConfigurationType.CALENDAR; }; + FrontComponentConfiguration: Omit< + FrontComponentConfiguration, + 'configurationType' + > & { + configurationType: WidgetConfigurationType.FRONT_COMPONENT; + }; EmailsConfiguration: Omit & { configurationType: WidgetConfigurationType.EMAILS; }; diff --git a/packages/twenty-front/src/modules/page-layout/graphql/fragments/pageLayoutWidgetFragment.ts b/packages/twenty-front/src/modules/page-layout/graphql/fragments/pageLayoutWidgetFragment.ts index 86e38b4aac..f649db899d 100644 --- a/packages/twenty-front/src/modules/page-layout/graphql/fragments/pageLayoutWidgetFragment.ts +++ b/packages/twenty-front/src/modules/page-layout/graphql/fragments/pageLayoutWidgetFragment.ts @@ -171,6 +171,10 @@ export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql` ... on WorkflowVersionConfiguration { configurationType } + ... on FrontComponentConfiguration { + configurationType + frontComponentId + } } pageLayoutTabId } diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetContentRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetContentRenderer.tsx index d8a5bebcd1..d4c748526c 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetContentRenderer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetContentRenderer.tsx @@ -5,6 +5,7 @@ import { FieldRichTextWidgetRenderer } from '@/page-layout/widgets/field-rich-te import { FieldWidget } from '@/page-layout/widgets/field/components/FieldWidget'; import { FieldsWidget } from '@/page-layout/widgets/fields/components/FieldsWidget'; import { FileWidget } from '@/page-layout/widgets/files/components/FileWidget'; +import { FrontComponentWidgetRenderer } from '@/page-layout/widgets/front-component/components/FrontComponentWidgetRenderer'; import { GraphWidgetRenderer } from '@/page-layout/widgets/graph/components/GraphWidgetRenderer'; import { IframeWidget } from '@/page-layout/widgets/iframe/components/IframeWidget'; import { NoteWidget } from '@/page-layout/widgets/notes/components/NoteWidget'; @@ -69,6 +70,9 @@ export const WidgetContentRenderer = ({ case WidgetType.STANDALONE_RICH_TEXT: return ; + case WidgetType.FRONT_COMPONENT: + return ; + default: return null; } diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/ChartSkeletonLoader.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetSkeletonLoader.tsx similarity index 94% rename from packages/twenty-front/src/modules/page-layout/widgets/graph/components/ChartSkeletonLoader.tsx rename to packages/twenty-front/src/modules/page-layout/widgets/components/WidgetSkeletonLoader.tsx index db17a11b85..1aa8c7a17f 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/ChartSkeletonLoader.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetSkeletonLoader.tsx @@ -11,7 +11,7 @@ const StyledContainer = styled.div` width: 100%; `; -export const ChartSkeletonLoader = () => { +export const WidgetSkeletonLoader = () => { const theme = useTheme(); return ( diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field-rich-text/components/FieldRichTextWidgetRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field-rich-text/components/FieldRichTextWidgetRenderer.tsx index 4dc3ceed28..6fa2d572f3 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field-rich-text/components/FieldRichTextWidgetRenderer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field-rich-text/components/FieldRichTextWidgetRenderer.tsx @@ -1,5 +1,5 @@ import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; -import { ChartSkeletonLoader } from '@/page-layout/widgets/graph/components/ChartSkeletonLoader'; +import { WidgetSkeletonLoader } from '@/page-layout/widgets/components/WidgetSkeletonLoader'; import { lazy, Suspense } from 'react'; const FieldRichTextWidget = lazy(() => @@ -18,7 +18,7 @@ export const FieldRichTextWidgetRenderer = ({ widget, }: FieldRichTextWidgetRendererProps) => { return ( - }> + }> ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/front-component/components/FrontComponentContent.tsx b/packages/twenty-front/src/modules/page-layout/widgets/front-component/components/FrontComponentContent.tsx new file mode 100644 index 0000000000..122fd55ac8 --- /dev/null +++ b/packages/twenty-front/src/modules/page-layout/widgets/front-component/components/FrontComponentContent.tsx @@ -0,0 +1,32 @@ +import { useQuery } from '@apollo/client'; + +import { isDefined } from 'twenty-shared/utils'; + +import { PageLayoutWidgetNoDataDisplay } from '@/page-layout/widgets/components/PageLayoutWidgetNoDataDisplay'; +import { WidgetSkeletonLoader } from '@/page-layout/widgets/components/WidgetSkeletonLoader'; +import { GET_FRONT_COMPONENT_CODE } from '@/page-layout/widgets/front-component/graphql/queries/getFrontComponentCode'; + +type FrontComponentContentProps = { + frontComponentId: string; +}; + +export const FrontComponentContent = ({ + frontComponentId, +}: FrontComponentContentProps) => { + const { data, loading, error } = useQuery(GET_FRONT_COMPONENT_CODE, { + variables: { id: frontComponentId }, + }); + + if (loading) { + return ; + } + + const sourceCode = data?.getFrontComponentCode?.sourceCode; + + if (isDefined(error) || !isDefined(sourceCode)) { + return ; + } + + // TODO: render the front component content here + return
FrontComponentContent
; +}; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/front-component/components/FrontComponentWidgetRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/front-component/components/FrontComponentWidgetRenderer.tsx new file mode 100644 index 0000000000..7aa08c1f2a --- /dev/null +++ b/packages/twenty-front/src/modules/page-layout/widgets/front-component/components/FrontComponentWidgetRenderer.tsx @@ -0,0 +1,23 @@ +import { isDefined } from 'twenty-shared/utils'; + +import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; +import { PageLayoutWidgetNoDataDisplay } from '@/page-layout/widgets/components/PageLayoutWidgetNoDataDisplay'; +import { FrontComponentContent } from '@/page-layout/widgets/front-component/components/FrontComponentContent'; + +type FrontComponentWidgetRendererProps = { + widget: PageLayoutWidget; +}; + +export const FrontComponentWidgetRenderer = ({ + widget, +}: FrontComponentWidgetRendererProps) => { + const configuration = widget.configuration; + + if (!isDefined(configuration) || !('frontComponentId' in configuration)) { + return ; + } + + const frontComponentId = configuration.frontComponentId; + + return ; +}; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/front-component/graphql/queries/getFrontComponentCode.ts b/packages/twenty-front/src/modules/page-layout/widgets/front-component/graphql/queries/getFrontComponentCode.ts new file mode 100644 index 0000000000..57d42238ad --- /dev/null +++ b/packages/twenty-front/src/modules/page-layout/widgets/front-component/graphql/queries/getFrontComponentCode.ts @@ -0,0 +1,9 @@ +import { gql } from '@apollo/client'; + +export const GET_FRONT_COMPONENT_CODE = gql` + query GetFrontComponentCode($id: UUID!) { + getFrontComponentCode(id: $id) { + sourceCode + } + } +`; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidget.tsx index d809ef6acb..7b634ee0a0 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidget.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidget.tsx @@ -1,6 +1,6 @@ import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById'; import { PageLayoutWidgetNoDataDisplay } from '@/page-layout/widgets/components/PageLayoutWidgetNoDataDisplay'; -import { ChartSkeletonLoader } from '@/page-layout/widgets/graph/components/ChartSkeletonLoader'; +import { WidgetSkeletonLoader } from '@/page-layout/widgets/components/WidgetSkeletonLoader'; import { GraphWidgetAggregateChartRenderer } from '@/page-layout/widgets/graph/graphWidgetAggregateChart/components/GraphWidgetAggregateChartRenderer'; import { GraphWidgetBarChartRenderer } from '@/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChartRenderer'; import { GraphWidgetLineChartRenderer } from '@/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChartRenderer'; @@ -54,7 +54,7 @@ export const GraphWidget = ({ objectMetadataId }: GraphWidgetProps) => { }; return ( - }> + }> import( @@ -23,11 +23,11 @@ export const GraphWidgetAggregateChartRenderer = () => { }); if (loading) { - return ; + return ; } return ( - }> + }> { }; if (loading) { - return ; + return ; } return ( - }> + }> diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChartRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChartRenderer.tsx index 345bb36de5..79fa540b97 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChartRenderer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChartRenderer.tsx @@ -1,5 +1,5 @@ import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; -import { ChartSkeletonLoader } from '@/page-layout/widgets/graph/components/ChartSkeletonLoader'; +import { WidgetSkeletonLoader } from '@/page-layout/widgets/components/WidgetSkeletonLoader'; import { GraphWidgetChartHasTooManyGroupsEffect } from '@/page-layout/widgets/graph/components/GraphWidgetChartHasTooManyGroupsEffect'; import { LINE_CHART_CONSTANTS } from '@/page-layout/widgets/graph/graphWidgetLineChart/constants/LineChartConstants'; import { useGraphLineChartWidgetData } from '@/page-layout/widgets/graph/graphWidgetLineChart/hooks/useGraphLineChartWidgetData'; @@ -125,11 +125,11 @@ export const GraphWidgetLineChartRenderer = () => { }; if (loading) { - return ; + return ; } return ( - }> + }> diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChartRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChartRenderer.tsx index 6ea5ecaedb..91baf61616 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChartRenderer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChartRenderer.tsx @@ -1,5 +1,5 @@ import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; -import { ChartSkeletonLoader } from '@/page-layout/widgets/graph/components/ChartSkeletonLoader'; +import { WidgetSkeletonLoader } from '@/page-layout/widgets/components/WidgetSkeletonLoader'; import { GraphWidgetChartHasTooManyGroupsEffect } from '@/page-layout/widgets/graph/components/GraphWidgetChartHasTooManyGroupsEffect'; import { useGraphPieChartWidgetData } from '@/page-layout/widgets/graph/graphWidgetPieChart/hooks/useGraphPieChartWidgetData'; import { type PieChartDataItemWithColor } from '@/page-layout/widgets/graph/graphWidgetPieChart/types/PieChartDataItem'; @@ -92,11 +92,11 @@ export const GraphWidgetPieChartRenderer = () => { }; if (loading) { - return ; + return ; } return ( - }> + }> diff --git a/packages/twenty-front/src/modules/page-layout/widgets/iframe/components/IframeWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/iframe/components/IframeWidget.tsx index 1e54a2ca8b..e76a1df7b9 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/iframe/components/IframeWidget.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/iframe/components/IframeWidget.tsx @@ -1,7 +1,7 @@ import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { PageLayoutWidgetNoDataDisplay } from '@/page-layout/widgets/components/PageLayoutWidgetNoDataDisplay'; -import { ChartSkeletonLoader } from '@/page-layout/widgets/graph/components/ChartSkeletonLoader'; +import { WidgetSkeletonLoader } from '@/page-layout/widgets/components/WidgetSkeletonLoader'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import styled from '@emotion/styled'; import { useState } from 'react'; @@ -95,7 +95,7 @@ export const IframeWidget = ({ widget }: IframeWidgetProps) => { {isLoading && ( - + )} @@ -18,7 +18,7 @@ export const StandaloneRichTextWidgetRenderer = ({ widget, }: StandaloneRichTextWidgetRendererProps) => { return ( - }> + }> ); diff --git a/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/SettingsAdminWorkerQueueMetricsSection.tsx b/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/SettingsAdminWorkerQueueMetricsSection.tsx index 4f6d675e7a..e79cfe62d9 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/SettingsAdminWorkerQueueMetricsSection.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/SettingsAdminWorkerQueueMetricsSection.tsx @@ -1,4 +1,4 @@ -import { ChartSkeletonLoader } from '@/page-layout/widgets/graph/components/ChartSkeletonLoader'; +import { WidgetSkeletonLoader } from '@/page-layout/widgets/components/WidgetSkeletonLoader'; import { WORKER_QUEUE_METRICS_SELECT_OPTIONS } from '@/settings/admin-panel/health-status/constants/WorkerQueueMetricsSelectOptions'; import { Select } from '@/ui/input/components/Select'; import styled from '@emotion/styled'; @@ -76,7 +76,7 @@ export const SettingsAdminWorkerQueueMetricsSection = ({ - }> + }> { + await queryRunner.query( + `ALTER TYPE "core"."pageLayoutWidget_type_enum" RENAME TO "pageLayoutWidget_type_enum_old"`, + ); + await queryRunner.query( + `CREATE TYPE "core"."pageLayoutWidget_type_enum" AS ENUM('VIEW', 'IFRAME', 'FIELD', 'FIELDS', 'GRAPH', 'STANDALONE_RICH_TEXT', 'TIMELINE', 'TASKS', 'NOTES', 'FILES', 'EMAILS', 'CALENDAR', 'FIELD_RICH_TEXT', 'WORKFLOW', 'WORKFLOW_VERSION', 'WORKFLOW_RUN', 'FRONT_COMPONENT')`, + ); + await queryRunner.query( + `ALTER TABLE "core"."pageLayoutWidget" ALTER COLUMN "type" DROP DEFAULT`, + ); + await queryRunner.query( + `ALTER TABLE "core"."pageLayoutWidget" ALTER COLUMN "type" TYPE "core"."pageLayoutWidget_type_enum" USING "type"::"text"::"core"."pageLayoutWidget_type_enum"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."pageLayoutWidget" ALTER COLUMN "type" SET DEFAULT 'VIEW'`, + ); + await queryRunner.query( + `DROP TYPE "core"."pageLayoutWidget_type_enum_old"`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TYPE "core"."pageLayoutWidget_type_enum_old" AS ENUM('VIEW', 'IFRAME', 'FIELD', 'FIELDS', 'GRAPH', 'STANDALONE_RICH_TEXT', 'TIMELINE', 'TASKS', 'NOTES', 'FILES', 'EMAILS', 'CALENDAR', 'FIELD_RICH_TEXT', 'WORKFLOW', 'WORKFLOW_VERSION', 'WORKFLOW_RUN')`, + ); + await queryRunner.query( + `ALTER TABLE "core"."pageLayoutWidget" ALTER COLUMN "type" DROP DEFAULT`, + ); + await queryRunner.query( + `ALTER TABLE "core"."pageLayoutWidget" ALTER COLUMN "type" TYPE "core"."pageLayoutWidget_type_enum_old" USING "type"::"text"::"core"."pageLayoutWidget_type_enum_old"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."pageLayoutWidget" ALTER COLUMN "type" SET DEFAULT 'VIEW'`, + ); + await queryRunner.query(`DROP TYPE "core"."pageLayoutWidget_type_enum"`); + await queryRunner.query( + `ALTER TYPE "core"."pageLayoutWidget_type_enum_old" RENAME TO "pageLayoutWidget_type_enum"`, + ); + } +} diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/services/flat-page-layout-widget-type-validator.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/services/flat-page-layout-widget-type-validator.service.ts index 896e65bb1e..85312abc84 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/services/flat-page-layout-widget-type-validator.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/services/flat-page-layout-widget-type-validator.service.ts @@ -10,6 +10,8 @@ import { } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget-type-validator.type'; import { type FlatPageLayoutWidgetValidationError } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget-validation-error.type'; import { rejectWidgetType } from 'src/engine/metadata-modules/flat-page-layout-widget/validators/utils/reject-widget-type.util'; +import { validateFrontComponentFlatPageLayoutWidgetForCreation } from 'src/engine/metadata-modules/flat-page-layout-widget/validators/utils/validate-front-component-flat-page-layout-widget-for-creation.util'; +import { validateFrontComponentFlatPageLayoutWidgetForUpdate } from 'src/engine/metadata-modules/flat-page-layout-widget/validators/utils/validate-front-component-flat-page-layout-widget-for-update.util'; import { validateGraphFlatPageLayoutWidgetForCreation } from 'src/engine/metadata-modules/flat-page-layout-widget/validators/utils/validate-graph-flat-page-layout-widget-for-creation.util'; import { validateGraphFlatPageLayoutWidgetForUpdate } from 'src/engine/metadata-modules/flat-page-layout-widget/validators/utils/validate-graph-flat-page-layout-widget-for-update.util'; import { validateIframeFlatPageLayoutWidgetForCreation } from 'src/engine/metadata-modules/flat-page-layout-widget/validators/utils/validate-iframe-flat-page-layout-widget-for-creation.util'; @@ -58,6 +60,7 @@ export class FlatPageLayoutWidgetTypeValidatorService { GRAPH: validateGraphFlatPageLayoutWidgetForCreation, STANDALONE_RICH_TEXT: validateStandaloneRichTextFlatPageLayoutWidgetForCreation, + FRONT_COMPONENT: validateFrontComponentFlatPageLayoutWidgetForCreation, TIMELINE: rejectWidgetType( WidgetType.TIMELINE, 'Widget type TIMELINE is not supported yet.', @@ -131,6 +134,7 @@ export class FlatPageLayoutWidgetTypeValidatorService { GRAPH: validateGraphFlatPageLayoutWidgetForUpdate, STANDALONE_RICH_TEXT: validateStandaloneRichTextFlatPageLayoutWidgetForUpdate, + FRONT_COMPONENT: validateFrontComponentFlatPageLayoutWidgetForUpdate, TIMELINE: rejectWidgetType( WidgetType.TIMELINE, 'Widget type TIMELINE is not supported yet.', diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/validators/utils/validate-front-component-configuration-type.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/validators/utils/validate-front-component-configuration-type.util.ts new file mode 100644 index 0000000000..bb17cff18b --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/validators/utils/validate-front-component-configuration-type.util.ts @@ -0,0 +1,39 @@ +import { msg, t } from '@lingui/core/macro'; +import { isDefined } from 'twenty-shared/utils'; + +import { type FlatPageLayoutWidgetValidationError } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget-validation-error.type'; +import { type FrontComponentConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/front-component-configuration.dto'; +import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type'; +import { PageLayoutWidgetExceptionCode } from 'src/engine/metadata-modules/page-layout-widget/exceptions/page-layout-widget.exception'; + +export const validateFrontComponentConfigurationType = ( + configuration: FrontComponentConfigurationDTO, + widgetTitle: string, +): FlatPageLayoutWidgetValidationError[] => { + const errors: FlatPageLayoutWidgetValidationError[] = []; + + if (!isDefined(configuration.configurationType)) { + errors.push({ + code: PageLayoutWidgetExceptionCode.INVALID_PAGE_LAYOUT_WIDGET_DATA, + message: t`Configuration type is required for widget "${widgetTitle}"`, + userFriendlyMessage: msg`Configuration type is required`, + }); + + return errors; + } + + if ( + configuration.configurationType !== WidgetConfigurationType.FRONT_COMPONENT + ) { + const configurationTypeString = String(configuration.configurationType); + + errors.push({ + code: PageLayoutWidgetExceptionCode.INVALID_PAGE_LAYOUT_WIDGET_DATA, + message: t`Invalid configuration type for front component widget "${widgetTitle}". Expected FRONT_COMPONENT, got ${configurationTypeString}`, + userFriendlyMessage: msg`Invalid configuration type for front component widget`, + value: configuration.configurationType, + }); + } + + return errors; +}; diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/validators/utils/validate-front-component-flat-page-layout-widget-for-creation.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/validators/utils/validate-front-component-flat-page-layout-widget-for-creation.util.ts new file mode 100644 index 0000000000..fb06b085e2 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/validators/utils/validate-front-component-flat-page-layout-widget-for-creation.util.ts @@ -0,0 +1,38 @@ +import { msg, t } from '@lingui/core/macro'; +import { isDefined } from 'twenty-shared/utils'; + +import { type ValidateFlatPageLayoutWidgetTypeSpecificitiesForCreationArgs } from 'src/engine/metadata-modules/flat-page-layout-widget/services/flat-page-layout-widget-type-validator.service'; +import { type FlatPageLayoutWidgetValidationError } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget-validation-error.type'; +import { validateFrontComponentConfigurationType } from 'src/engine/metadata-modules/flat-page-layout-widget/validators/utils/validate-front-component-configuration-type.util'; +import { type FrontComponentConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/front-component-configuration.dto'; +import { PageLayoutWidgetExceptionCode } from 'src/engine/metadata-modules/page-layout-widget/exceptions/page-layout-widget.exception'; + +export const validateFrontComponentFlatPageLayoutWidgetForCreation = ( + args: ValidateFlatPageLayoutWidgetTypeSpecificitiesForCreationArgs, +): FlatPageLayoutWidgetValidationError[] => { + const { flatEntityToValidate } = args; + const { configuration, title } = flatEntityToValidate; + const errors: FlatPageLayoutWidgetValidationError[] = []; + + if (!isDefined(configuration)) { + errors.push({ + code: PageLayoutWidgetExceptionCode.INVALID_PAGE_LAYOUT_WIDGET_DATA, + message: t`Configuration is required for front component widget "${title}"`, + userFriendlyMessage: msg`Configuration is required for front component widget`, + }); + + return errors; + } + + const frontComponentConfiguration = + configuration as FrontComponentConfigurationDTO; + + const configurationTypeErrors = validateFrontComponentConfigurationType( + frontComponentConfiguration, + title, + ); + + errors.push(...configurationTypeErrors); + + return errors; +}; diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/validators/utils/validate-front-component-flat-page-layout-widget-for-update.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/validators/utils/validate-front-component-flat-page-layout-widget-for-update.util.ts new file mode 100644 index 0000000000..83ae7aefd6 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/validators/utils/validate-front-component-flat-page-layout-widget-for-update.util.ts @@ -0,0 +1,30 @@ +import { isDefined } from 'twenty-shared/utils'; + +import { type ValidateFlatPageLayoutWidgetTypeSpecificitiesForUpdateArgs } from 'src/engine/metadata-modules/flat-page-layout-widget/services/flat-page-layout-widget-type-validator.service'; +import { type FlatPageLayoutWidgetValidationError } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget-validation-error.type'; +import { validateFrontComponentConfigurationType } from 'src/engine/metadata-modules/flat-page-layout-widget/validators/utils/validate-front-component-configuration-type.util'; +import { type FrontComponentConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/front-component-configuration.dto'; + +export const validateFrontComponentFlatPageLayoutWidgetForUpdate = ( + args: ValidateFlatPageLayoutWidgetTypeSpecificitiesForUpdateArgs, +): FlatPageLayoutWidgetValidationError[] => { + const { flatEntityToValidate } = args; + const { configuration, title } = flatEntityToValidate; + const errors: FlatPageLayoutWidgetValidationError[] = []; + + if (!isDefined(configuration)) { + return []; + } + + const frontComponentConfiguration = + configuration as FrontComponentConfigurationDTO; + + const configurationTypeErrors = validateFrontComponentConfigurationType( + frontComponentConfiguration, + title, + ); + + errors.push(...configurationTypeErrors); + + return errors; +}; diff --git a/packages/twenty-server/src/engine/metadata-modules/front-component/dtos/front-component-code.dto.ts b/packages/twenty-server/src/engine/metadata-modules/front-component/dtos/front-component-code.dto.ts new file mode 100644 index 0000000000..c97ae19547 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/front-component/dtos/front-component-code.dto.ts @@ -0,0 +1,11 @@ +import { Field, ObjectType } from '@nestjs/graphql'; + +import { IsNotEmpty, IsString } from 'class-validator'; + +@ObjectType('FrontComponentCode') +export class FrontComponentCodeDTO { + @IsString() + @IsNotEmpty() + @Field() + sourceCode: string; +} diff --git a/packages/twenty-server/src/engine/metadata-modules/front-component/front-component.resolver.ts b/packages/twenty-server/src/engine/metadata-modules/front-component/front-component.resolver.ts index b74139e235..95b3a75b2a 100644 --- a/packages/twenty-server/src/engine/metadata-modules/front-component/front-component.resolver.ts +++ b/packages/twenty-server/src/engine/metadata-modules/front-component/front-component.resolver.ts @@ -10,6 +10,7 @@ import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard'; import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard'; import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard'; import { CreateFrontComponentInput } from 'src/engine/metadata-modules/front-component/dtos/create-front-component.input'; +import { FrontComponentCodeDTO } from 'src/engine/metadata-modules/front-component/dtos/front-component-code.dto'; import { FrontComponentDTO } from 'src/engine/metadata-modules/front-component/dtos/front-component.dto'; import { UpdateFrontComponentInput } from 'src/engine/metadata-modules/front-component/dtos/update-front-component.input'; import { FrontComponentService } from 'src/engine/metadata-modules/front-component/front-component.service'; @@ -42,6 +43,18 @@ export class FrontComponentResolver { return await this.frontComponentService.findById(id, workspace.id); } + @Query(() => FrontComponentCodeDTO) + @UseGuards(NoPermissionGuard) + async getFrontComponentCode( + @Args('id', { type: () => UUIDScalarType }) id: string, + @AuthWorkspace() workspace: WorkspaceEntity, + ): Promise { + return await this.frontComponentService.getFrontComponentCode( + id, + workspace.id, + ); + } + @Mutation(() => FrontComponentDTO) @UseGuards(SettingsPermissionGuard(PermissionFlagType.APPLICATIONS)) async createFrontComponent( diff --git a/packages/twenty-server/src/engine/metadata-modules/front-component/front-component.service.ts b/packages/twenty-server/src/engine/metadata-modules/front-component/front-component.service.ts index be34be565a..a2c78b1c7c 100644 --- a/packages/twenty-server/src/engine/metadata-modules/front-component/front-component.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/front-component/front-component.service.ts @@ -11,6 +11,7 @@ import { fromDeleteFrontComponentInputToFlatFrontComponentOrThrow } from 'src/en import { fromFlatFrontComponentToFrontComponentDto } from 'src/engine/metadata-modules/flat-front-component/utils/from-flat-front-component-to-front-component-dto.util'; import { fromUpdateFrontComponentInputToFlatFrontComponentToUpdateOrThrow } from 'src/engine/metadata-modules/flat-front-component/utils/from-update-front-component-input-to-flat-front-component-to-update-or-throw.util'; import { type CreateFrontComponentInput } from 'src/engine/metadata-modules/front-component/dtos/create-front-component.input'; +import { type FrontComponentCodeDTO } from 'src/engine/metadata-modules/front-component/dtos/front-component-code.dto'; import { type FrontComponentDTO } from 'src/engine/metadata-modules/front-component/dtos/front-component.dto'; import { type UpdateFrontComponentInput } from 'src/engine/metadata-modules/front-component/dtos/update-front-component.input'; import { @@ -234,4 +235,14 @@ export class FrontComponentService { return frontComponent; } + + async getFrontComponentCode( + _id: string, + _workspaceId: string, + ): Promise { + // TODO: get the source code from the front component here, we will implement a mock version for now + const sourceCode = ''; + + return { sourceCode }; + } } diff --git a/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/constants/all-widget-configuration-type-validator-by-widget-configuration-type.constant.ts b/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/constants/all-widget-configuration-type-validator-by-widget-configuration-type.constant.ts index eab707adc1..2e7d0f97e5 100644 --- a/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/constants/all-widget-configuration-type-validator-by-widget-configuration-type.constant.ts +++ b/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/constants/all-widget-configuration-type-validator-by-widget-configuration-type.constant.ts @@ -6,6 +6,7 @@ import { FieldConfigurationDTO } from 'src/engine/metadata-modules/page-layout-w import { FieldRichTextConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/field-rich-text-configuration.dto'; import { FieldsConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/fields-configuration.dto'; import { FilesConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/files-configuration.dto'; +import { FrontComponentConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/front-component-configuration.dto'; import { GaugeChartConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/gauge-chart-configuration.dto'; import { IframeConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/iframe-configuration.dto'; import { LineChartConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/line-chart-configuration.dto'; @@ -31,6 +32,7 @@ export const ALL_WIDGET_CONFIGURATION_TYPE_VALIDATOR_BY_WIDGET_CONFIGURATION_TYP GAUGE_CHART: GaugeChartConfigurationDTO, BAR_CHART: BarChartConfigurationDTO, CALENDAR: CalendarConfigurationDTO, + FRONT_COMPONENT: FrontComponentConfigurationDTO, EMAILS: EmailsConfigurationDTO, FIELD: FieldConfigurationDTO, FIELD_RICH_TEXT: FieldRichTextConfigurationDTO, diff --git a/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/dtos/front-component-configuration.dto.ts b/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/dtos/front-component-configuration.dto.ts new file mode 100644 index 0000000000..9cf9502997 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/dtos/front-component-configuration.dto.ts @@ -0,0 +1,22 @@ +import { Field, ObjectType } from '@nestjs/graphql'; + +import { IsIn, IsNotEmpty, IsUUID } from 'class-validator'; + +import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; +import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type'; +import { PageLayoutWidgetConfigurationBase } from 'src/engine/metadata-modules/page-layout-widget/types/page-layout-widget-configurationt-base.type'; + +@ObjectType('FrontComponentConfiguration') +export class FrontComponentConfigurationDTO + implements PageLayoutWidgetConfigurationBase +{ + @Field(() => WidgetConfigurationType) + @IsIn([WidgetConfigurationType.FRONT_COMPONENT]) + @IsNotEmpty() + configurationType: WidgetConfigurationType.FRONT_COMPONENT; + + @Field(() => UUIDScalarType) + @IsNotEmpty() + @IsUUID() + frontComponentId: string; +} diff --git a/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type.ts b/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type.ts index f53724ce62..056cd2a085 100644 --- a/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type.ts +++ b/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type.ts @@ -25,6 +25,7 @@ export enum WidgetConfigurationType { WORKFLOW = 'WORKFLOW', WORKFLOW_VERSION = 'WORKFLOW_VERSION', WORKFLOW_RUN = 'WORKFLOW_RUN', + FRONT_COMPONENT = 'FRONT_COMPONENT', } registerEnumType(WidgetConfigurationType, { diff --git a/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/enums/widget-type.enum.ts b/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/enums/widget-type.enum.ts index 156d008fdf..56e7fa1cc5 100644 --- a/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/enums/widget-type.enum.ts +++ b/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/enums/widget-type.enum.ts @@ -15,4 +15,5 @@ export enum WidgetType { WORKFLOW = 'WORKFLOW', WORKFLOW_VERSION = 'WORKFLOW_VERSION', WORKFLOW_RUN = 'WORKFLOW_RUN', + FRONT_COMPONENT = 'FRONT_COMPONENT', } diff --git a/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/utils/validate-widget-configuration-input.util.ts b/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/utils/validate-widget-configuration-input.util.ts index f93cd26127..586b1b9bb6 100644 --- a/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/utils/validate-widget-configuration-input.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/utils/validate-widget-configuration-input.util.ts @@ -2,6 +2,7 @@ import { isNotEmptyObject, type ValidationError } from 'class-validator'; import { AggregateChartConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/aggregate-chart-configuration.dto'; import { BarChartConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/bar-chart-configuration.dto'; +import { FrontComponentConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/front-component-configuration.dto'; import { GaugeChartConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/gauge-chart-configuration.dto'; import { IframeConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/iframe-configuration.dto'; import { LineChartConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/line-chart-configuration.dto'; @@ -113,6 +114,12 @@ export const validateWidgetConfigurationInput = ({ configuration, ); break; + case WidgetConfigurationType.FRONT_COMPONENT: + errors = validateWidgetConfigurationByDto( + FrontComponentConfigurationDTO, + configuration, + ); + break; case WidgetConfigurationType.VIEW: throw new PageLayoutWidgetException( 'View configuration is not supported yet', diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/constants/page-layout-widget-seeds.constant.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/constants/page-layout-widget-seeds.constant.ts index ddeff53361..4b3d8c4983 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/constants/page-layout-widget-seeds.constant.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/constants/page-layout-widget-seeds.constant.ts @@ -19,4 +19,6 @@ export const PAGE_LAYOUT_WIDGET_SEEDS = { TEAM_GEOGRAPHIC_DISTRIBUTION: 'TEAM_GEOGRAPHIC_DISTRIBUTION_WIDGET', TEAM_CONTACT_ROLES: 'TEAM_CONTACT_ROLES_WIDGET', TEAM_OPEN_TASKS: 'TEAM_OPEN_TASKS_WIDGET', + + FRONT_COMPONENT: 'FRONT_COMPONENT_WIDGET', }; diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/get-page-layout-widget-data-seeds.util.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/get-page-layout-widget-data-seeds.util.ts index a85925d80d..3485e300fc 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/get-page-layout-widget-data-seeds.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/get-page-layout-widget-data-seeds.util.ts @@ -393,6 +393,23 @@ export const getPageLayoutWidgetDataSeeds = ( objectMetadataId: taskObject?.id ?? null, } satisfies SeederFlatPageLayoutWidget) : null, + + // Sales Overview Tab Widgets - Front Component + { + id: generateSeedId(workspaceId, PAGE_LAYOUT_WIDGET_SEEDS.FRONT_COMPONENT), + pageLayoutTabId: generateSeedId( + workspaceId, + PAGE_LAYOUT_TAB_SEEDS.SALES_OVERVIEW, + ), + title: 'Front Component', + type: WidgetType.FRONT_COMPONENT, + gridPosition: { row: 2, column: 7, rowSpan: 2, columnSpan: 5 }, + configuration: { + configurationType: WidgetConfigurationType.FRONT_COMPONENT, + frontComponentId: '6cdf2607-4b28-40e6-8c53-cc06799ddc88', + } as const, + objectMetadataId: null, + } satisfies SeederFlatPageLayoutWidget, ].filter(isDefined); const v2Widgets = isDashboardV2Enabled