From 7d94e686d3a20bab932516977b23d20988373f5d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Feb 2026 12:22:32 +0000 Subject: [PATCH 1/4] Initial plan From eb98fa88adce3376bef392e18fc4bf2efd9746c8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Feb 2026 12:29:26 +0000 Subject: [PATCH 2/4] feat: userActions drives toolbar visibility + AddRecord button with position support - Gate addRecord button with userActions.addRecordForm !== false - Support addRecord.position (top/bottom) for button placement - Use i18n key list.addRecord for button label - Add addRecord i18n key to all 10 locale files - Add 3 new unit tests for addRecordForm and position Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- packages/i18n/src/locales/ar.ts | 1 + packages/i18n/src/locales/de.ts | 1 + packages/i18n/src/locales/en.ts | 1 + packages/i18n/src/locales/es.ts | 1 + packages/i18n/src/locales/fr.ts | 1 + packages/i18n/src/locales/ja.ts | 1 + packages/i18n/src/locales/ko.ts | 1 + packages/i18n/src/locales/pt.ts | 1 + packages/i18n/src/locales/ru.ts | 1 + packages/i18n/src/locales/zh.ts | 1 + packages/plugin-list/src/ListView.tsx | 23 ++++++++-- .../src/__tests__/ListView.test.tsx | 46 +++++++++++++++++++ 12 files changed, 76 insertions(+), 3 deletions(-) diff --git a/packages/i18n/src/locales/ar.ts b/packages/i18n/src/locales/ar.ts index 27a6175c9..78c574f0f 100644 --- a/packages/i18n/src/locales/ar.ts +++ b/packages/i18n/src/locales/ar.ts @@ -101,6 +101,7 @@ const ar = { list: { recordCount: '{{count}} سجلات', recordCountOne: '{{count}} سجل', + addRecord: 'إضافة سجل', }, kanban: { addCard: 'إضافة بطاقة', diff --git a/packages/i18n/src/locales/de.ts b/packages/i18n/src/locales/de.ts index c74d2508e..d79de08a2 100644 --- a/packages/i18n/src/locales/de.ts +++ b/packages/i18n/src/locales/de.ts @@ -100,6 +100,7 @@ const de = { list: { recordCount: '{{count}} Datensätze', recordCountOne: '{{count}} Datensatz', + addRecord: 'Datensatz hinzufügen', }, kanban: { addCard: 'Karte hinzufügen', diff --git a/packages/i18n/src/locales/en.ts b/packages/i18n/src/locales/en.ts index 6850dca62..8522c898a 100644 --- a/packages/i18n/src/locales/en.ts +++ b/packages/i18n/src/locales/en.ts @@ -100,6 +100,7 @@ const en = { list: { recordCount: '{{count}} records', recordCountOne: '{{count}} record', + addRecord: 'Add record', }, kanban: { addCard: 'Add card', diff --git a/packages/i18n/src/locales/es.ts b/packages/i18n/src/locales/es.ts index a79d879c1..3cd1ed9bf 100644 --- a/packages/i18n/src/locales/es.ts +++ b/packages/i18n/src/locales/es.ts @@ -100,6 +100,7 @@ const es = { list: { recordCount: '{{count}} registros', recordCountOne: '{{count}} registro', + addRecord: 'Agregar registro', }, kanban: { addCard: 'Añadir tarjeta', diff --git a/packages/i18n/src/locales/fr.ts b/packages/i18n/src/locales/fr.ts index 6d107ef3f..2cd91d6dc 100644 --- a/packages/i18n/src/locales/fr.ts +++ b/packages/i18n/src/locales/fr.ts @@ -100,6 +100,7 @@ const fr = { list: { recordCount: '{{count}} enregistrements', recordCountOne: '{{count}} enregistrement', + addRecord: 'Ajouter un enregistrement', }, kanban: { addCard: 'Ajouter une carte', diff --git a/packages/i18n/src/locales/ja.ts b/packages/i18n/src/locales/ja.ts index cecf26ed5..7b5cdc943 100644 --- a/packages/i18n/src/locales/ja.ts +++ b/packages/i18n/src/locales/ja.ts @@ -100,6 +100,7 @@ const ja = { list: { recordCount: '{{count}} 件のレコード', recordCountOne: '{{count}} 件のレコード', + addRecord: 'レコードを追加', }, kanban: { addCard: 'カードを追加', diff --git a/packages/i18n/src/locales/ko.ts b/packages/i18n/src/locales/ko.ts index 73f278252..4ef44aec3 100644 --- a/packages/i18n/src/locales/ko.ts +++ b/packages/i18n/src/locales/ko.ts @@ -100,6 +100,7 @@ const ko = { list: { recordCount: '{{count}}개 레코드', recordCountOne: '{{count}}개 레코드', + addRecord: '레코드 추가', }, kanban: { addCard: '카드 추가', diff --git a/packages/i18n/src/locales/pt.ts b/packages/i18n/src/locales/pt.ts index 3b245550e..347350d53 100644 --- a/packages/i18n/src/locales/pt.ts +++ b/packages/i18n/src/locales/pt.ts @@ -100,6 +100,7 @@ const pt = { list: { recordCount: '{{count}} registros', recordCountOne: '{{count}} registro', + addRecord: 'Adicionar registro', }, kanban: { addCard: 'Adicionar cartão', diff --git a/packages/i18n/src/locales/ru.ts b/packages/i18n/src/locales/ru.ts index 3bb174dbc..48502c540 100644 --- a/packages/i18n/src/locales/ru.ts +++ b/packages/i18n/src/locales/ru.ts @@ -100,6 +100,7 @@ const ru = { list: { recordCount: '{{count}} записей', recordCountOne: '{{count}} запись', + addRecord: 'Добавить запись', }, kanban: { addCard: 'Добавить карточку', diff --git a/packages/i18n/src/locales/zh.ts b/packages/i18n/src/locales/zh.ts index 0244e6242..5382241ca 100644 --- a/packages/i18n/src/locales/zh.ts +++ b/packages/i18n/src/locales/zh.ts @@ -100,6 +100,7 @@ const zh = { list: { recordCount: '{{count}} 条记录', recordCountOne: '{{count}} 条记录', + addRecord: '添加记录', }, kanban: { addCard: '添加卡片', diff --git a/packages/plugin-list/src/ListView.tsx b/packages/plugin-list/src/ListView.tsx index fc93be0a1..ca7f15db8 100644 --- a/packages/plugin-list/src/ListView.tsx +++ b/packages/plugin-list/src/ListView.tsx @@ -202,6 +202,7 @@ const LIST_DEFAULT_TRANSLATIONS: Record = { 'list.pullToRefresh': 'Pull to refresh', 'list.refreshing': 'Refreshing…', 'list.dataLimitReached': 'Showing first {{limit}} records. More data may be available.', + 'list.addRecord': 'Add record', }; /** @@ -1324,8 +1325,8 @@ export const ListView: React.FC = ({ {/* Right: Add Record + Search */}
- {/* Add Record */} - {schema.addRecord?.enabled && ( + {/* Add Record (top position) */} + {schema.addRecord?.enabled && schema.userActions?.addRecordForm !== false && schema.addRecord?.position !== 'bottom' && ( )} @@ -1453,6 +1454,22 @@ export const ListView: React.FC = ({ )}
+ {/* Add Record (bottom position) */} + {schema.addRecord?.enabled && schema.userActions?.addRecordForm !== false && schema.addRecord?.position === 'bottom' && ( +
+ +
+ )} + {/* Bulk Actions Bar — skip for grid view since ObjectGrid renders its own BulkActionBar */} {schema.bulkActions && schema.bulkActions.length > 0 && selectedRows.length > 0 && currentView !== 'grid' && (
{ renderWithProvider(); expect(screen.queryByTestId('add-record-button')).not.toBeInTheDocument(); }); + + it('should hide add record button when userActions.addRecordForm is false', () => { + const schema: ListViewSchema = { + type: 'list-view', + objectName: 'contacts', + viewType: 'grid', + fields: ['name', 'email'], + addRecord: { enabled: true }, + userActions: { addRecordForm: false }, + }; + + renderWithProvider(); + expect(screen.queryByTestId('add-record-button')).not.toBeInTheDocument(); + }); + + it('should render add record button at bottom when position is bottom', () => { + const schema: ListViewSchema = { + type: 'list-view', + objectName: 'contacts', + viewType: 'grid', + fields: ['name', 'email'], + addRecord: { enabled: true, position: 'bottom' }, + }; + + renderWithProvider(); + const btn = screen.getByTestId('add-record-button'); + expect(btn).toBeInTheDocument(); + // The bottom button is wrapped in a border-t div outside the toolbar + expect(btn.closest('div.border-t')).toBeTruthy(); + }); + + it('should render add record button in toolbar when position is top', () => { + const schema: ListViewSchema = { + type: 'list-view', + objectName: 'contacts', + viewType: 'grid', + fields: ['name', 'email'], + addRecord: { enabled: true, position: 'top' }, + }; + + renderWithProvider(); + const btn = screen.getByTestId('add-record-button'); + expect(btn).toBeInTheDocument(); + // The top button is inside the toolbar border-b div + expect(btn.closest('div.border-b')).toBeTruthy(); + }); }); // ============================ From 07d4f53343d4ba0a14969b6635d8647bccb7a2c9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Feb 2026 12:42:53 +0000 Subject: [PATCH 3/4] refactor: extract addRecord visibility into toolbarFlags to reduce duplication Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- packages/plugin-list/src/ListView.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/plugin-list/src/ListView.tsx b/packages/plugin-list/src/ListView.tsx index ca7f15db8..980b4acce 100644 --- a/packages/plugin-list/src/ListView.tsx +++ b/packages/plugin-list/src/ListView.tsx @@ -266,6 +266,7 @@ export const ListView: React.FC = ({ // Resolve toolbar visibility flags: userActions overrides showX flags const toolbarFlags = React.useMemo(() => { const ua = schema.userActions; + const addRecordEnabled = schema.addRecord?.enabled === true && ua?.addRecordForm !== false; return { showSearch: ua?.search !== undefined ? ua.search : schema.showSearch !== false, showSort: ua?.sort !== undefined ? ua.sort : schema.showSort !== false, @@ -274,8 +275,10 @@ export const ListView: React.FC = ({ showHideFields: schema.showHideFields !== false, showGroup: schema.showGroup !== false, showColor: schema.showColor !== false, + showAddRecord: addRecordEnabled, + addRecordPosition: (schema.addRecord?.position === 'bottom' ? 'bottom' : 'top') as 'top' | 'bottom', }; - }, [schema.userActions, schema.showSearch, schema.showSort, schema.showFilters, schema.showDensity, schema.showHideFields, schema.showGroup, schema.showColor]); + }, [schema.userActions, schema.showSearch, schema.showSort, schema.showFilters, schema.showDensity, schema.showHideFields, schema.showGroup, schema.showColor, schema.addRecord, schema.userActions?.addRecordForm]); const [currentView, setCurrentView] = React.useState( (schema.viewType as ViewType) @@ -1326,7 +1329,7 @@ export const ListView: React.FC = ({ {/* Right: Add Record + Search */}
{/* Add Record (top position) */} - {schema.addRecord?.enabled && schema.userActions?.addRecordForm !== false && schema.addRecord?.position !== 'bottom' && ( + {toolbarFlags.showAddRecord && toolbarFlags.addRecordPosition === 'top' && (
{/* Add Record (bottom position) */} - {schema.addRecord?.enabled && schema.userActions?.addRecordForm !== false && schema.addRecord?.position === 'bottom' && ( + {toolbarFlags.showAddRecord && toolbarFlags.addRecordPosition === 'bottom' && (