Disable reset to default when custom tab or widget (#19814)

## Context
"Reset to default" action is rejected by the backend for custom entities
because there is no "default" concept for them

## Implementation
Grey out the Reset to default action on record page-layout tabs and
widgets when the entity either has no applicationId yet (unsaved draft —
previously slipped through the existing check), or belongs to the
workspace custom application.

<img width="926" height="370" alt="Screenshot 2026-04-17 at 18 50 31"
src="https://github.com/user-attachments/assets/c7c163f4-17a6-4b69-a66d-90f9085d27a2"
/>
This commit is contained in:
Weiko
2026-04-17 19:30:57 +02:00
committed by GitHub
parent 619ea13649
commit df9c4e26b5
44 changed files with 218 additions and 49 deletions
@@ -890,6 +890,7 @@ type GridPosition {
type PageLayoutWidget {
id: UUID!
applicationId: UUID!
pageLayoutTabId: UUID!
title: String!
type: WidgetType!
@@ -664,6 +664,7 @@ export interface GridPosition {
export interface PageLayoutWidget {
id: Scalars['UUID']
applicationId: Scalars['UUID']
pageLayoutTabId: Scalars['UUID']
title: Scalars['String']
type: WidgetType
@@ -3886,6 +3887,7 @@ export interface GridPositionGenqlSelection{
export interface PageLayoutWidgetGenqlSelection{
id?: boolean | number
applicationId?: boolean | number
pageLayoutTabId?: boolean | number
title?: boolean | number
type?: boolean | number
@@ -1873,6 +1873,9 @@ export default {
"id": [
3
],
"applicationId": [
3
],
"pageLayoutTabId": [
3
],
File diff suppressed because one or more lines are too long
@@ -75,6 +75,7 @@ const mixedGraphsPageLayoutMocks = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'number-widget',
pageLayoutTabId: 'mixed-tab',
@@ -100,6 +101,7 @@ const mixedGraphsPageLayoutMocks = {
} satisfies PageLayoutWidget,
{
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'gauge-widget',
pageLayoutTabId: 'mixed-tab',
@@ -126,6 +128,7 @@ const mixedGraphsPageLayoutMocks = {
} satisfies PageLayoutWidget,
{
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'pie-widget',
pageLayoutTabId: 'mixed-tab',
@@ -153,6 +156,7 @@ const mixedGraphsPageLayoutMocks = {
} satisfies PageLayoutWidget,
{
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'bar-widget',
pageLayoutTabId: 'mixed-tab',
@@ -33,6 +33,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'company-widget-fields',
isActive: true,
pageLayoutTabId: 'company-tab-fields',
@@ -73,6 +74,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'company-widget-timeline',
isActive: true,
pageLayoutTabId: 'company-tab-timeline',
@@ -113,6 +115,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'company-widget-tasks',
isActive: true,
pageLayoutTabId: 'company-tab-tasks',
@@ -153,6 +156,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'company-widget-notes',
isActive: true,
pageLayoutTabId: 'company-tab-notes',
@@ -193,6 +197,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'company-widget-files',
isActive: true,
pageLayoutTabId: 'company-tab-files',
@@ -233,6 +238,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'company-widget-emails',
isActive: true,
pageLayoutTabId: 'company-tab-emails',
@@ -273,6 +279,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'company-widget-calendar',
isActive: true,
pageLayoutTabId: 'company-tab-calendar',
@@ -33,6 +33,7 @@ export const DEFAULT_MESSAGE_THREAD_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'message-thread-widget-email-thread',
isActive: true,
pageLayoutTabId: 'message-thread-tab-home',
@@ -33,6 +33,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'note-widget-fields',
isActive: true,
pageLayoutTabId: 'note-tab-fields',
@@ -60,6 +61,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
},
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'note-widget-note',
isActive: true,
pageLayoutTabId: 'note-tab-fields',
@@ -107,6 +109,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'note-widget-note',
isActive: true,
pageLayoutTabId: 'note-tab-note',
@@ -154,6 +157,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'note-widget-timeline',
isActive: true,
pageLayoutTabId: 'note-tab-timeline',
@@ -194,6 +198,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'note-widget-files',
isActive: true,
pageLayoutTabId: 'note-tab-files',
@@ -33,6 +33,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'opportunity-widget-fields',
isActive: true,
pageLayoutTabId: 'opportunity-tab-fields',
@@ -73,6 +74,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'opportunity-widget-timeline',
isActive: true,
pageLayoutTabId: 'opportunity-tab-timeline',
@@ -113,6 +115,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'opportunity-widget-tasks',
isActive: true,
pageLayoutTabId: 'opportunity-tab-tasks',
@@ -153,6 +156,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'opportunity-widget-notes',
isActive: true,
pageLayoutTabId: 'opportunity-tab-notes',
@@ -193,6 +197,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'opportunity-widget-files',
isActive: true,
pageLayoutTabId: 'opportunity-tab-files',
@@ -233,6 +238,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'opportunity-widget-emails',
isActive: true,
pageLayoutTabId: 'opportunity-tab-emails',
@@ -273,6 +279,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'opportunity-widget-calendar',
isActive: true,
pageLayoutTabId: 'opportunity-tab-calendar',
@@ -33,6 +33,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'person-widget-fields',
isActive: true,
pageLayoutTabId: 'person-tab-fields',
@@ -73,6 +74,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'person-widget-timeline',
isActive: true,
pageLayoutTabId: 'person-tab-timeline',
@@ -113,6 +115,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'person-widget-tasks',
isActive: true,
pageLayoutTabId: 'person-tab-tasks',
@@ -153,6 +156,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'person-widget-notes',
isActive: true,
pageLayoutTabId: 'person-tab-notes',
@@ -193,6 +197,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'person-widget-files',
isActive: true,
pageLayoutTabId: 'person-tab-files',
@@ -233,6 +238,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'person-widget-emails',
isActive: true,
pageLayoutTabId: 'person-tab-emails',
@@ -273,6 +279,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'person-widget-calendar',
isActive: true,
pageLayoutTabId: 'person-tab-calendar',
@@ -33,6 +33,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'default-widget-fields',
isActive: true,
pageLayoutTabId: 'default-tab-fields',
@@ -73,6 +74,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'default-widget-timeline',
isActive: true,
pageLayoutTabId: 'default-tab-timeline',
@@ -113,6 +115,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'default-widget-tasks',
isActive: true,
pageLayoutTabId: 'default-tab-tasks',
@@ -153,6 +156,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'default-widget-notes',
isActive: true,
pageLayoutTabId: 'default-tab-notes',
@@ -193,6 +197,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'default-widget-files',
isActive: true,
pageLayoutTabId: 'default-tab-files',
@@ -33,6 +33,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'task-widget-fields',
isActive: true,
pageLayoutTabId: 'task-tab-fields',
@@ -57,6 +58,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
},
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'task-widget-note',
isActive: true,
pageLayoutTabId: 'task-tab-fields',
@@ -104,6 +106,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'task-widget-note',
isActive: true,
pageLayoutTabId: 'task-tab-note',
@@ -151,6 +154,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'task-widget-timeline',
isActive: true,
pageLayoutTabId: 'task-tab-timeline',
@@ -191,6 +195,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'task-widget-files',
isActive: true,
pageLayoutTabId: 'task-tab-files',
@@ -38,6 +38,7 @@ export const DEFAULT_WORKFLOW_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'workflow-widget-flow',
isActive: true,
pageLayoutTabId: 'workflow-tab-flow',
@@ -39,6 +39,7 @@ export const DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'workflow-run-widget-fields',
isActive: true,
pageLayoutTabId: 'workflow-run-tab-fields',
@@ -80,6 +81,7 @@ export const DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'workflow-run-widget-flow',
isActive: true,
pageLayoutTabId: 'workflow-run-tab-flow',
@@ -39,6 +39,7 @@ export const DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'workflow-version-widget-fields',
isActive: true,
pageLayoutTabId: 'workflow-version-tab-fields',
@@ -80,6 +81,7 @@ export const DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT: PageLayout = {
widgets: [
{
__typename: 'PageLayoutWidget',
applicationId: '',
id: 'workflow-version-widget-flow',
isActive: true,
pageLayoutTabId: 'workflow-version-tab-flow',
@@ -3,6 +3,7 @@ import { gql } from '@apollo/client';
export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql`
fragment PageLayoutWidgetFragment on PageLayoutWidget {
id
applicationId
title
type
objectMetadataId
@@ -99,6 +99,7 @@ describe('usePageLayoutDraftState', () => {
widgets: [
{
id: 'widget-1',
applicationId: '',
pageLayoutTabId: 'tab-1',
title: 'New Widget',
isActive: true,
@@ -47,6 +47,7 @@ describe('usePageLayoutWithRelationWidgets', () => {
{
__typename: 'PageLayoutWidget',
id: 'widget-fields',
applicationId: '',
pageLayoutTabId: 'tab-1',
title: 'Fields',
isActive: true,
@@ -71,6 +72,7 @@ describe('usePageLayoutWithRelationWidgets', () => {
{
__typename: 'PageLayoutWidget',
id: 'widget-notes',
applicationId: '',
pageLayoutTabId: 'tab-1',
title: 'Notes',
isActive: true,
@@ -94,6 +96,7 @@ describe('usePageLayoutWithRelationWidgets', () => {
{
__typename: 'PageLayoutWidget',
id: 'widget-other',
applicationId: '',
pageLayoutTabId: 'tab-1',
title: 'Other',
isActive: true,
@@ -219,6 +222,7 @@ describe('usePageLayoutWithRelationWidgets', () => {
{
__typename: 'PageLayoutWidget',
id: 'widget-other',
applicationId: '',
pageLayoutTabId: 'tab-1',
title: 'Other',
isActive: true,
@@ -11,6 +11,7 @@ describe('addWidgetToTab', () => {
const mockWidget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
id: 'widget-1',
applicationId: '',
isActive: true,
pageLayoutTabId: 'tab-1',
title: 'Test Widget',
@@ -12,6 +12,7 @@ describe('convertLayoutsToWidgets', () => {
const mockWidgets: PageLayoutWidget[] = [
{
id: 'widget-1',
applicationId: '',
isActive: true,
pageLayoutTabId: 'tab-1',
title: 'Widget 1',
@@ -35,6 +36,7 @@ describe('convertLayoutsToWidgets', () => {
},
{
id: 'widget-2',
applicationId: '',
isActive: true,
pageLayoutTabId: 'tab-1',
title: 'Widget 2',
@@ -28,6 +28,7 @@ describe('convertPageLayoutToTabLayouts', () => {
{
__typename: 'PageLayoutWidget',
id: 'widget-1',
applicationId: '',
isActive: true,
pageLayoutTabId: 'tab-1',
title: 'Widget 1',
@@ -47,6 +48,7 @@ describe('convertPageLayoutToTabLayouts', () => {
{
__typename: 'PageLayoutWidget',
id: 'widget-2',
applicationId: '',
isActive: true,
pageLayoutTabId: 'tab-1',
title: 'Widget 2',
@@ -110,6 +112,7 @@ describe('convertPageLayoutToTabLayouts', () => {
{
__typename: 'PageLayoutWidget',
id: 'rich-text-widget',
applicationId: '',
isActive: true,
pageLayoutTabId: 'tab-1',
title: 'Rich Text',
@@ -23,6 +23,7 @@ const createMockWidget = (
},
): PageLayoutWidget => ({
id: 'widget-1',
applicationId: '',
isActive: true,
type: WidgetType.GRAPH,
title: 'Test',
@@ -12,6 +12,7 @@ describe('filterVisibleWidgets', () => {
): PageLayoutTab['widgets'][0] => ({
__typename: 'PageLayoutWidget',
id,
applicationId: '',
isActive: true,
pageLayoutTabId: 'tab-1',
title: `Widget ${id}`,
@@ -12,6 +12,7 @@ describe('getTabsWithVisibleWidgets', () => {
): PageLayoutTab['widgets'][0] => ({
__typename: 'PageLayoutWidget',
id,
applicationId: '',
isActive: true,
pageLayoutTabId: 'tab-1',
title: `Widget ${id}`,
@@ -10,6 +10,7 @@ import {
describe('prepareGridLayoutItemsWithPlaceholders', () => {
const createMockWidget = (id: string): PageLayoutWidget => ({
id,
applicationId: '',
isActive: true,
pageLayoutTabId: 'tab-1',
title: `Test Widget ${id}`,
@@ -20,6 +20,7 @@ describe('removeWidgetFromTab', () => {
{
__typename: 'PageLayoutWidget' as const,
id: 'widget-1',
applicationId: '',
isActive: true,
pageLayoutTabId: 'tab-1',
title: 'Widget 1',
@@ -39,6 +40,7 @@ describe('removeWidgetFromTab', () => {
{
__typename: 'PageLayoutWidget' as const,
id: 'widget-2',
applicationId: '',
isActive: true,
pageLayoutTabId: 'tab-1',
title: 'Widget 2',
@@ -73,6 +75,7 @@ describe('removeWidgetFromTab', () => {
{
__typename: 'PageLayoutWidget' as const,
id: 'widget-3',
applicationId: '',
isActive: true,
pageLayoutTabId: 'tab-2',
title: 'Widget 3',
@@ -26,6 +26,7 @@ export const createDefaultFieldWidget = ({
return {
__typename: 'PageLayoutWidget',
id,
applicationId: '',
pageLayoutTabId,
title,
isActive: true,
@@ -21,6 +21,7 @@ export const createDefaultFieldsWidget = ({
return {
__typename: 'PageLayoutWidget',
id,
applicationId: '',
pageLayoutTabId,
title: 'Fields',
isActive: true,
@@ -16,6 +16,7 @@ export const createDefaultFrontComponentWidget = (
return {
__typename: 'PageLayoutWidget',
id,
applicationId: '',
pageLayoutTabId,
title,
isActive: true,
@@ -70,6 +70,7 @@ export const createDefaultGraphWidget = ({
return {
__typename: 'PageLayoutWidget',
id,
applicationId: '',
pageLayoutTabId,
title,
isActive: true,
@@ -17,6 +17,7 @@ export const createDefaultIframeWidget = (
return {
__typename: 'PageLayoutWidget',
id,
applicationId: '',
pageLayoutTabId,
title,
isActive: true,
@@ -22,6 +22,7 @@ export const createDefaultRecordTableWidget = ({
return {
__typename: 'PageLayoutWidget',
id,
applicationId: '',
pageLayoutTabId,
title,
isActive: true,
@@ -17,6 +17,7 @@ export const createDefaultStandaloneRichTextWidget = (
return {
__typename: 'PageLayoutWidget',
id,
applicationId: '',
pageLayoutTabId,
title: 'Untitled Rich Text',
isActive: true,
@@ -16,6 +16,7 @@ const getRelationFieldWidgetToInsert = (
): PageLayoutWidget => ({
__typename: 'PageLayoutWidget' as const,
id: `${DYNAMIC_RELATION_WIDGET_ID_PREFIX}${field.id}-${field.label}`,
applicationId: '',
pageLayoutTabId: tabId,
title: field.label,
isActive: true,
@@ -253,6 +253,7 @@ export const WithNumberChart: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: WIDGET_ID_NUMBER_CHART,
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -340,6 +341,7 @@ export const WithGaugeChart: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: WIDGET_ID_GAUGE_CHART,
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -427,6 +429,7 @@ export const WithBarChart: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: WIDGET_ID_BAR_CHART,
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -525,6 +528,7 @@ export const SmallWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: WIDGET_ID_SMALL,
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -619,6 +623,7 @@ export const MediumWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: WIDGET_ID_MEDIUM,
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -717,6 +722,7 @@ export const LargeWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: WIDGET_ID_LARGE,
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -815,6 +821,7 @@ export const WideWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: WIDGET_ID_WIDE,
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -909,6 +916,7 @@ export const TallWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: WIDGET_ID_TALL,
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -1008,6 +1016,7 @@ export const WithManyToOneRelationFieldWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: WIDGET_ID_MANY_TO_ONE_RELATION,
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -1127,6 +1136,7 @@ export const WithOneToManyRelationFieldWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: WIDGET_ID_ONE_TO_MANY_RELATION,
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -1238,6 +1248,7 @@ export const OneToManyRelationFieldWidgetWithSeeAllButton: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: WIDGET_ID_ONE_TO_MANY_RELATION,
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -1375,6 +1386,7 @@ export const OnMobile: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-mobile',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -1473,6 +1485,7 @@ export const InSidePanel: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-side-panel',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -1631,6 +1644,7 @@ export const Catalog: CatalogStory<Story, typeof WidgetRenderer> = {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: WIDGET_ID_CATALOG,
pageLayoutTabId:
@@ -333,6 +333,7 @@ export const TextFieldWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-text-field',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -427,6 +428,7 @@ export const AddressFieldWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-address-field',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -524,6 +526,7 @@ export const NumberFieldWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-number-field',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -618,6 +621,7 @@ export const LinkFieldWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-link-field',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -712,6 +716,7 @@ export const ManyToOneRelationFieldWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-relation-field',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -816,6 +821,7 @@ export const OneToManyRelationFieldWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-one-to-many-relation-field',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -912,6 +918,7 @@ export const BooleanFieldWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-boolean-field',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -1005,6 +1012,7 @@ export const CurrencyFieldWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-currency-field',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -1098,6 +1106,7 @@ export const EmailsFieldWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-emails-field',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -1192,6 +1201,7 @@ export const PhonesFieldWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-phones-field',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -1286,6 +1296,7 @@ export const SelectFieldWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-select-field',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -1381,6 +1392,7 @@ export const MultiSelectFieldWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-multi-select-field',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -1479,6 +1491,7 @@ export const TimelineActivityRelationFieldWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-timeline-activity-relation-field',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -1578,6 +1591,7 @@ export const ManyToOneRelationCardWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-relation-card',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -1690,6 +1704,7 @@ export const OneToManyRelationCardWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-one-to-many-relation-card',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -1785,6 +1800,7 @@ export const TimelineActivityRelationCardWidget: Story = {
render: () => {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-timeline-activity-relation-card',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -1946,6 +1962,7 @@ export const OneToManyRelationCardWidgetWithProgressiveLoading: Story = {
const widget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-one-to-many-relation-card-progressive',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -160,6 +160,7 @@ const createPageLayoutWithWidget = (
const createFieldsWidget = (viewId: string | null): PageLayoutWidget => ({
__typename: 'PageLayoutWidget',
applicationId: '',
isActive: true,
id: 'widget-fields',
pageLayoutTabId: TAB_ID_OVERVIEW,
@@ -13,6 +13,7 @@ import { SelectableListItem } from '@/ui/layout/selectable-list/components/Selec
import { useLingui } from '@lingui/react/macro';
import { isDefined } from 'twenty-shared/utils';
import {
AppTooltip,
IconChevronLeft,
IconChevronRight,
IconEyeX,
@@ -22,6 +23,8 @@ import {
} from 'twenty-ui/display';
const RESET_TAB_TO_DEFAULT_MODAL_ID = 'reset-canvas-tab-to-default-modal';
const RESET_TAB_TO_DEFAULT_MENU_ITEM_ID =
'reset-canvas-tab-to-default-menu-item';
type CanvasTabSettingsContentProps = {
pageLayoutId: string;
@@ -29,7 +32,7 @@ type CanvasTabSettingsContentProps = {
canSetAsPinned: boolean;
canMoveLeft: boolean;
canMoveRight: boolean;
canShowResetToDefault: boolean;
isResetToDefaultDisabled: boolean;
canDelete: boolean;
onMoveLeft: () => void;
onMoveRight: () => void;
@@ -44,7 +47,7 @@ export const CanvasTabSettingsContent = ({
canSetAsPinned,
canMoveLeft,
canMoveRight,
canShowResetToDefault,
isResetToDefaultDisabled,
canDelete,
onMoveLeft,
onMoveRight,
@@ -60,6 +63,9 @@ export const CanvasTabSettingsContent = ({
);
const handleResetToDefault = () => {
if (isResetToDefaultDisabled) {
return;
}
openModal(RESET_TAB_TO_DEFAULT_MODAL_ID);
};
@@ -70,9 +76,7 @@ export const CanvasTabSettingsContent = ({
...(isDefined(canvasWidget)
? [TAB_SETTINGS_SELECTABLE_ITEM_IDS.VISIBILITY_RESTRICTION]
: []),
...(canShowResetToDefault
? [TAB_SETTINGS_SELECTABLE_ITEM_IDS.RESET_TO_DEFAULT]
: []),
TAB_SETTINGS_SELECTABLE_ITEM_IDS.RESET_TO_DEFAULT,
...(canDelete ? [TAB_SETTINGS_SELECTABLE_ITEM_IDS.DELETE] : []),
];
@@ -149,7 +153,7 @@ export const CanvasTabSettingsContent = ({
/>
</SelectableListItem>
)}
{canShowResetToDefault && (
<div id={RESET_TAB_TO_DEFAULT_MENU_ITEM_ID}>
<SelectableListItem
itemId={TAB_SETTINGS_SELECTABLE_ITEM_IDS.RESET_TO_DEFAULT}
onEnter={handleResetToDefault}
@@ -159,8 +163,17 @@ export const CanvasTabSettingsContent = ({
Icon={IconRefreshDot}
label={t`Reset to default`}
onClick={handleResetToDefault}
disabled={isResetToDefaultDisabled}
/>
</SelectableListItem>
</div>
{isResetToDefaultDisabled && (
<AppTooltip
anchorSelect={`#${RESET_TAB_TO_DEFAULT_MENU_ITEM_ID}`}
content={t`No default configuration available for this tab`}
noArrow
place="bottom"
/>
)}
{canDelete && (
<SelectableListItem
@@ -7,6 +7,7 @@ import { useModal } from '@/ui/layout/modal/hooks/useModal';
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { useLingui } from '@lingui/react/macro';
import {
AppTooltip,
IconChevronLeft,
IconChevronRight,
IconCopyPlus,
@@ -16,12 +17,14 @@ import {
} from 'twenty-ui/display';
const RESET_TAB_TO_DEFAULT_MODAL_ID = 'reset-regular-tab-to-default-modal';
const RESET_TAB_TO_DEFAULT_MENU_ITEM_ID =
'reset-regular-tab-to-default-menu-item';
type RegularTabSettingsContentProps = {
canSetAsPinned: boolean;
canMoveLeft: boolean;
canMoveRight: boolean;
canShowResetToDefault: boolean;
isResetToDefaultDisabled: boolean;
canDelete: boolean;
onMoveLeft: () => void;
onMoveRight: () => void;
@@ -35,7 +38,7 @@ export const RegularTabSettingsContent = ({
canSetAsPinned,
canMoveLeft,
canMoveRight,
canShowResetToDefault,
isResetToDefaultDisabled,
canDelete,
onMoveLeft,
onMoveRight,
@@ -48,6 +51,9 @@ export const RegularTabSettingsContent = ({
const { openModal } = useModal();
const handleResetToDefault = () => {
if (isResetToDefaultDisabled) {
return;
}
openModal(RESET_TAB_TO_DEFAULT_MODAL_ID);
};
@@ -56,9 +62,7 @@ export const RegularTabSettingsContent = ({
...(canMoveRight ? [TAB_SETTINGS_SELECTABLE_ITEM_IDS.MOVE_RIGHT] : []),
...(canSetAsPinned ? [TAB_SETTINGS_SELECTABLE_ITEM_IDS.SET_AS_PINNED] : []),
TAB_SETTINGS_SELECTABLE_ITEM_IDS.DUPLICATE,
...(canShowResetToDefault
? [TAB_SETTINGS_SELECTABLE_ITEM_IDS.RESET_TO_DEFAULT]
: []),
TAB_SETTINGS_SELECTABLE_ITEM_IDS.RESET_TO_DEFAULT,
...(canDelete ? [TAB_SETTINGS_SELECTABLE_ITEM_IDS.DELETE] : []),
];
@@ -116,7 +120,7 @@ export const RegularTabSettingsContent = ({
onClick={onDuplicate}
/>
</SelectableListItem>
{canShowResetToDefault && (
<div id={RESET_TAB_TO_DEFAULT_MENU_ITEM_ID}>
<SelectableListItem
itemId={TAB_SETTINGS_SELECTABLE_ITEM_IDS.RESET_TO_DEFAULT}
onEnter={handleResetToDefault}
@@ -126,8 +130,17 @@ export const RegularTabSettingsContent = ({
Icon={IconRefreshDot}
label={t`Reset to default`}
onClick={handleResetToDefault}
disabled={isResetToDefaultDisabled}
/>
</SelectableListItem>
</div>
{isResetToDefaultDisabled && (
<AppTooltip
anchorSelect={`#${RESET_TAB_TO_DEFAULT_MENU_ITEM_ID}`}
content={t`No default configuration available for this tab`}
noArrow
place="bottom"
/>
)}
{canDelete && (
<SelectableListItem
@@ -276,6 +276,7 @@ export const SidePanelPageLayoutRecordPageWidgetTypeSelect = () => {
const newWidget: PageLayoutWidget = {
__typename: 'PageLayoutWidget',
id: widgetId,
applicationId: '',
isActive: true,
pageLayoutTabId: tabId,
title: frontComponent.name,
@@ -14,6 +14,7 @@ import { RegularTabSettingsContent } from '@/side-panel/pages/page-layout/compon
import { useAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentState';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { isNonEmptyString } from '@sniptt/guards';
import { useNavigate } from 'react-router-dom';
import { isDefined } from 'twenty-shared/utils';
import {
@@ -85,11 +86,9 @@ export const SidePanelPageLayoutTabSettingsContent = ({
const canSetAsPinned =
isRecordPage && !isAlreadyPinned && tabsSorted.length > 1;
const isCustomTab =
isDefined(currentWorkspace?.workspaceCustomApplication) &&
tab.applicationId === currentWorkspace.workspaceCustomApplication.id;
const canShowResetToDefault = !isCustomTab;
const isResetToDefaultDisabled =
!isNonEmptyString(tab.applicationId) ||
tab.applicationId === currentWorkspace?.workspaceCustomApplication?.id;
const handleDelete = () => {
deleteTab(tab.id);
@@ -111,7 +110,7 @@ export const SidePanelPageLayoutTabSettingsContent = ({
canSetAsPinned={canSetAsPinned}
canMoveLeft={canMoveLeft}
canMoveRight={canMoveRight}
canShowResetToDefault={canShowResetToDefault}
isResetToDefaultDisabled={isResetToDefaultDisabled}
canDelete={canDelete}
onMoveLeft={() => moveLeft(tab.id)}
onMoveRight={() => moveRight(tab.id)}
@@ -127,7 +126,7 @@ export const SidePanelPageLayoutTabSettingsContent = ({
canSetAsPinned={canSetAsPinned}
canMoveLeft={canMoveLeft}
canMoveRight={canMoveRight}
canShowResetToDefault={canShowResetToDefault}
isResetToDefaultDisabled={isResetToDefaultDisabled}
canDelete={canDelete}
onMoveLeft={() => moveLeft(tab.id)}
onMoveRight={() => moveRight(tab.id)}
@@ -1,3 +1,4 @@
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { CommandMenuItem } from '@/command-menu/components/CommandMenuItem';
import { CommandMenuItemDropdown } from '@/command-menu/components/CommandMenuItemDropdown';
import { useDeletePageLayoutWidget } from '@/page-layout/hooks/useDeletePageLayoutWidget';
@@ -14,10 +15,13 @@ import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModa
import { useModal } from '@/ui/layout/modal/hooks/useModal';
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { useLingui } from '@lingui/react/macro';
import { isNonEmptyString } from '@sniptt/guards';
import { SidePanelPages } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import {
AppTooltip,
IconEyeX,
IconRefreshDot,
IconSwitchHorizontal,
@@ -25,6 +29,8 @@ import {
} from 'twenty-ui/display';
const RESET_WIDGET_TO_DEFAULT_MODAL_ID = 'reset-widget-to-default-modal';
const RESET_WIDGET_TO_DEFAULT_MENU_ITEM_ID =
'reset-widget-to-default-menu-item';
type WidgetSettingsManageSectionProps = {
pageLayoutId: string;
@@ -42,6 +48,8 @@ export const WidgetSettingsManageSection = ({
pageLayoutId,
);
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
const { deletePageLayoutWidget } = useDeletePageLayoutWidget(pageLayoutId);
const { resetPageLayoutWidgetToDefault } =
@@ -59,7 +67,15 @@ export const WidgetSettingsManageSection = ({
return null;
}
const isResetToDefaultDisabled =
!isNonEmptyString(widgetInEditMode?.applicationId) ||
widgetInEditMode.applicationId ===
currentWorkspace?.workspaceCustomApplication?.id;
const handleResetToDefault = () => {
if (isResetToDefaultDisabled) {
return;
}
openModal(RESET_WIDGET_TO_DEFAULT_MODAL_ID);
};
@@ -100,17 +116,28 @@ export const WidgetSettingsManageSection = ({
contextualTextPosition="right"
/>
</SelectableListItem>
<SelectableListItem
itemId={WIDGET_SETTINGS_SELECTABLE_ITEM_IDS.RESET_TO_DEFAULT}
onEnter={handleResetToDefault}
>
<CommandMenuItem
id={WIDGET_SETTINGS_SELECTABLE_ITEM_IDS.RESET_TO_DEFAULT}
Icon={IconRefreshDot}
label={t`Reset to default`}
onClick={handleResetToDefault}
<div id={RESET_WIDGET_TO_DEFAULT_MENU_ITEM_ID}>
<SelectableListItem
itemId={WIDGET_SETTINGS_SELECTABLE_ITEM_IDS.RESET_TO_DEFAULT}
onEnter={handleResetToDefault}
>
<CommandMenuItem
id={WIDGET_SETTINGS_SELECTABLE_ITEM_IDS.RESET_TO_DEFAULT}
Icon={IconRefreshDot}
label={t`Reset to default`}
onClick={handleResetToDefault}
disabled={isResetToDefaultDisabled}
/>
</SelectableListItem>
</div>
{isResetToDefaultDisabled && (
<AppTooltip
anchorSelect={`#${RESET_WIDGET_TO_DEFAULT_MENU_ITEM_ID}`}
content={t`No default configuration available for this widget`}
noArrow
place="bottom"
/>
</SelectableListItem>
)}
<SelectableListItem
itemId={WIDGET_SETTINGS_SELECTABLE_ITEM_IDS.REPLACE_WIDGET}
onEnter={handleReplaceWidget}
@@ -123,6 +123,7 @@ export const createTestWidget = (
): PageLayoutWidget => ({
__typename: 'PageLayoutWidget',
id: 'widget-1',
applicationId: 'test-application-id',
pageLayoutTabId: 'tab-1',
title: 'Test Widget',
type: WidgetType.GRAPH,
@@ -41,6 +41,9 @@ export class PageLayoutWidgetDTO {
@IDField(() => UUIDScalarType)
id: string;
@Field(() => UUIDScalarType, { nullable: false })
applicationId: string;
@Field(() => UUIDScalarType, { nullable: false })
pageLayoutTabId: string;