From 26aa5431429736e2cc5c500328e6937c76d0b785 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 13:11:19 +0000 Subject: [PATCH 1/7] Initial plan From 78dccc228333ad5d79f214749cd9fb312ba5f120 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 13:17:36 +0000 Subject: [PATCH 2/7] feat(i18n): add enableHideFields, enableGroup, enableColor, enableDensity keys to all locales Add 4 new i18n keys (enableHideFields, enableGroup, enableColor, enableDensity) to all non-English locale files: de, pt, ru, es, ja, ko, fr, ar, zh. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packages/i18n/src/locales/ar.ts | 4 ++++ packages/i18n/src/locales/de.ts | 4 ++++ packages/i18n/src/locales/es.ts | 4 ++++ packages/i18n/src/locales/fr.ts | 4 ++++ packages/i18n/src/locales/ja.ts | 4 ++++ packages/i18n/src/locales/ko.ts | 4 ++++ packages/i18n/src/locales/pt.ts | 4 ++++ packages/i18n/src/locales/ru.ts | 4 ++++ packages/i18n/src/locales/zh.ts | 4 ++++ 9 files changed, 36 insertions(+) diff --git a/packages/i18n/src/locales/ar.ts b/packages/i18n/src/locales/ar.ts index 8964e0848..e4401ac87 100644 --- a/packages/i18n/src/locales/ar.ts +++ b/packages/i18n/src/locales/ar.ts @@ -202,6 +202,10 @@ const ar = { enableSearch: 'تفعيل البحث', enableFilter: 'تفعيل التصفية', enableSort: 'تفعيل الترتيب', + enableHideFields: 'تفعيل إخفاء الحقول', + enableGroup: 'تفعيل التجميع', + enableColor: 'تفعيل اللون', + enableDensity: 'تفعيل الكثافة', userActions: 'إجراءات المستخدم', addRecordViaForm: 'إضافة سجلات عبر النموذج', advanced: 'متقدم', diff --git a/packages/i18n/src/locales/de.ts b/packages/i18n/src/locales/de.ts index e4c921a40..1ac85418f 100644 --- a/packages/i18n/src/locales/de.ts +++ b/packages/i18n/src/locales/de.ts @@ -206,6 +206,10 @@ const de = { enableSearch: 'Suche aktivieren', enableFilter: 'Filter aktivieren', enableSort: 'Sortierung aktivieren', + enableHideFields: 'Felder ausblenden aktivieren', + enableGroup: 'Gruppierung aktivieren', + enableColor: 'Farbe aktivieren', + enableDensity: 'Dichte aktivieren', userActions: 'Benutzeraktionen', addRecordViaForm: 'Datensätze über Formular hinzufügen', advanced: 'Erweitert', diff --git a/packages/i18n/src/locales/es.ts b/packages/i18n/src/locales/es.ts index 88ae264e9..8f282f77f 100644 --- a/packages/i18n/src/locales/es.ts +++ b/packages/i18n/src/locales/es.ts @@ -201,6 +201,10 @@ const es = { enableSearch: 'Habilitar búsqueda', enableFilter: 'Habilitar filtro', enableSort: 'Habilitar ordenamiento', + enableHideFields: 'Habilitar ocultar campos', + enableGroup: 'Habilitar agrupación', + enableColor: 'Habilitar color', + enableDensity: 'Habilitar densidad', userActions: 'Acciones de usuario', addRecordViaForm: 'Agregar registros mediante formulario', advanced: 'Avanzado', diff --git a/packages/i18n/src/locales/fr.ts b/packages/i18n/src/locales/fr.ts index 59fca2675..493e22211 100644 --- a/packages/i18n/src/locales/fr.ts +++ b/packages/i18n/src/locales/fr.ts @@ -206,6 +206,10 @@ const fr = { enableSearch: 'Activer la recherche', enableFilter: 'Activer le filtre', enableSort: 'Activer le tri', + enableHideFields: 'Activer masquer les champs', + enableGroup: 'Activer le regroupement', + enableColor: 'Activer la couleur', + enableDensity: 'Activer la densité', userActions: 'Actions utilisateur', addRecordViaForm: 'Ajouter des enregistrements via un formulaire', advanced: 'Avancé', diff --git a/packages/i18n/src/locales/ja.ts b/packages/i18n/src/locales/ja.ts index ded1f10b2..de5127221 100644 --- a/packages/i18n/src/locales/ja.ts +++ b/packages/i18n/src/locales/ja.ts @@ -201,6 +201,10 @@ const ja = { enableSearch: '検索を有効化', enableFilter: 'フィルターを有効化', enableSort: '並べ替えを有効化', + enableHideFields: 'フィールド非表示を有効化', + enableGroup: 'グループを有効化', + enableColor: 'カラーを有効化', + enableDensity: '密度を有効化', userActions: 'ユーザーアクション', addRecordViaForm: 'フォームからレコードを追加', advanced: '詳細設定', diff --git a/packages/i18n/src/locales/ko.ts b/packages/i18n/src/locales/ko.ts index 9df24fc5f..430a8c7c2 100644 --- a/packages/i18n/src/locales/ko.ts +++ b/packages/i18n/src/locales/ko.ts @@ -201,6 +201,10 @@ const ko = { enableSearch: '검색 활성화', enableFilter: '필터 활성화', enableSort: '정렬 활성화', + enableHideFields: '필드 숨기기 활성화', + enableGroup: '그룹 활성화', + enableColor: '색상 활성화', + enableDensity: '밀도 활성화', userActions: '사용자 작업', addRecordViaForm: '양식으로 레코드 추가', advanced: '고급', diff --git a/packages/i18n/src/locales/pt.ts b/packages/i18n/src/locales/pt.ts index addd6b200..23f9e08ad 100644 --- a/packages/i18n/src/locales/pt.ts +++ b/packages/i18n/src/locales/pt.ts @@ -201,6 +201,10 @@ const pt = { enableSearch: 'Habilitar pesquisa', enableFilter: 'Habilitar filtro', enableSort: 'Habilitar ordenação', + enableHideFields: 'Ativar ocultar campos', + enableGroup: 'Ativar agrupamento', + enableColor: 'Ativar cor', + enableDensity: 'Ativar densidade', userActions: 'Ações do usuário', addRecordViaForm: 'Adicionar registros via formulário', advanced: 'Avançado', diff --git a/packages/i18n/src/locales/ru.ts b/packages/i18n/src/locales/ru.ts index e98e16e09..6e9e7e620 100644 --- a/packages/i18n/src/locales/ru.ts +++ b/packages/i18n/src/locales/ru.ts @@ -201,6 +201,10 @@ const ru = { enableSearch: 'Включить поиск', enableFilter: 'Включить фильтр', enableSort: 'Включить сортировку', + enableHideFields: 'Включить скрытие полей', + enableGroup: 'Включить группировку', + enableColor: 'Включить цвет', + enableDensity: 'Включить плотность', userActions: 'Действия пользователя', addRecordViaForm: 'Добавить записи через форму', advanced: 'Расширенные', diff --git a/packages/i18n/src/locales/zh.ts b/packages/i18n/src/locales/zh.ts index 10c6f1d66..f18c77836 100644 --- a/packages/i18n/src/locales/zh.ts +++ b/packages/i18n/src/locales/zh.ts @@ -206,6 +206,10 @@ const zh = { enableSearch: '启用搜索', enableFilter: '启用筛选', enableSort: '启用排序', + enableHideFields: '启用隐藏字段', + enableGroup: '启用分组', + enableColor: '启用颜色', + enableDensity: '启用密度', userActions: '用户操作', addRecordViaForm: '通过表单添加记录', advanced: '高级', From ca17fa07b4802b7509652262e2ccc29f3f6d2752 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 13:20:01 +0000 Subject: [PATCH 3/7] feat: add conditional rendering for toolbar controls (Hide Fields, Group, Color, Density, Export) - Add showHideFields, showGroup, showColor, showDensity, allowExport to ListViewSchema and NamedListView types - Add Zod schema fields for new toolbar control properties - Wrap Hide Fields, Group, Color, Density buttons with schema conditions in ListView - Fix Export button to check allowExport !== false - Propagate new props through Console ObjectView fullSchema and PluginObjectView renderListView - Add toggle switches in ViewConfigPanel for all new controls - Fix hasExport logic bug (was always true due to undefined !== false) - Add i18n translations for new toggle labels in all locales Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- apps/console/src/components/ObjectView.tsx | 6 +++ .../src/components/ViewConfigPanel.tsx | 38 ++++++++++++++++++- packages/i18n/src/locales/en.ts | 4 ++ packages/plugin-list/src/ListView.tsx | 10 ++++- packages/plugin-view/src/ObjectView.tsx | 5 +++ packages/types/src/objectql.ts | 30 +++++++++++++++ packages/types/src/zod/objectql.zod.ts | 5 +++ 7 files changed, 96 insertions(+), 2 deletions(-) diff --git a/apps/console/src/components/ObjectView.tsx b/apps/console/src/components/ObjectView.tsx index f3c7e71aa..ead244199 100644 --- a/apps/console/src/components/ObjectView.tsx +++ b/apps/console/src/components/ObjectView.tsx @@ -307,6 +307,12 @@ export function ObjectView({ dataSource, objects, onEdit, onRowClick }: any) { showSearch: viewDef.showSearch ?? listSchema.showSearch, showSort: viewDef.showSort ?? listSchema.showSort, showFilters: viewDef.showFilters ?? listSchema.showFilters, + showHideFields: viewDef.showHideFields ?? listSchema.showHideFields, + showGroup: viewDef.showGroup ?? listSchema.showGroup, + showColor: viewDef.showColor ?? listSchema.showColor, + showDensity: viewDef.showDensity ?? listSchema.showDensity, + allowExport: viewDef.allowExport ?? listSchema.allowExport, + exportOptions: viewDef.allowExport === false ? undefined : (viewDef.exportOptions ?? listSchema.exportOptions), striped: viewDef.striped ?? listSchema.striped, bordered: viewDef.bordered ?? listSchema.bordered, color: viewDef.color ?? listSchema.color, diff --git a/apps/console/src/components/ViewConfigPanel.tsx b/apps/console/src/components/ViewConfigPanel.tsx index ae85007be..4aee30c13 100644 --- a/apps/console/src/components/ViewConfigPanel.tsx +++ b/apps/console/src/components/ViewConfigPanel.tsx @@ -320,7 +320,11 @@ export function ViewConfigPanel({ open, onClose, mode = 'edit', activeView, obje const hasSearch = draft.showSearch !== false; const hasFilter = draft.showFilters !== false; const hasSort = draft.showSort !== false; - const hasExport = draft.exportOptions !== undefined || draft.allowExport !== false; + const hasHideFields = draft.showHideFields !== false; + const hasGroup = draft.showGroup !== false; + const hasColor = draft.showColor !== false; + const hasDensity = draft.showDensity !== false; + const hasExport = draft.exportOptions != null || draft.allowExport === true; const hasAddForm = draft.addRecordViaForm === true; const hasShowDescription = draft.showDescription !== false; @@ -507,6 +511,38 @@ export function ViewConfigPanel({ open, onClose, mode = 'edit', activeView, obje className="scale-75" /> + + updateDraft('showHideFields', checked)} + className="scale-75" + /> + + + updateDraft('showGroup', checked)} + className="scale-75" + /> + + + updateDraft('showColor', checked)} + className="scale-75" + /> + + + updateDraft('showDensity', checked)} + className="scale-75" + /> + = ({
{/* Hide Fields */} + {schema.showHideFields !== false && (
+ )} {/* Filter */} {schema.showFilters !== false && ( @@ -910,6 +912,7 @@ export const ListView: React.FC = ({ )} {/* Group */} + {schema.showGroup !== false && ( + )} {/* Sort */} {schema.showSort !== false && ( @@ -960,6 +964,7 @@ export const ListView: React.FC = ({ )} {/* Color */} + {schema.showColor !== false && ( + )} {/* Row Height / Density Mode */} + {schema.showDensity !== false && ( + )} {/* Export */} - {schema.exportOptions && ( + {schema.exportOptions && schema.allowExport !== false && (
)} diff --git a/packages/i18n/src/locales/en.ts b/packages/i18n/src/locales/en.ts index fd86089c3..7dcd91c0a 100644 --- a/packages/i18n/src/locales/en.ts +++ b/packages/i18n/src/locales/en.ts @@ -246,6 +246,8 @@ const en = { wrapHeaders: 'Wrap headers', showFieldDescriptions: 'Show field descriptions', collapseAllByDefault: 'Collapse all by default', + striped: 'Striped rows', + bordered: 'Bordered cells', editRecordsInline: 'Edit records inline', addDeleteRecordsInline: 'Add/delete records inline', clickIntoRecordDetails: 'Click into record details', diff --git a/packages/plugin-list/src/ListView.tsx b/packages/plugin-list/src/ListView.tsx index 7d60128ce..11af3e9b5 100644 --- a/packages/plugin-list/src/ListView.tsx +++ b/packages/plugin-list/src/ListView.tsx @@ -610,6 +610,9 @@ export const ListView: React.FC = ({ showSearch: false, // Pass navigation click handler to child views onRowClick: navigation.handleClick, + // Forward display properties to child views + ...(schema.striped != null ? { striped: schema.striped } : {}), + ...(schema.bordered != null ? { bordered: schema.bordered } : {}), }; switch (currentView) { @@ -620,6 +623,7 @@ export const ListView: React.FC = ({ columns: effectiveFields, ...(schema.conditionalFormatting ? { conditionalFormatting: schema.conditionalFormatting } : {}), ...(schema.inlineEdit != null ? { editable: schema.inlineEdit } : {}), + ...(schema.wrapHeaders != null ? { wrapHeaders: schema.wrapHeaders } : {}), ...(schema.options?.grid || {}), }; case 'kanban': diff --git a/packages/plugin-list/src/__tests__/ListView.test.tsx b/packages/plugin-list/src/__tests__/ListView.test.tsx index b3032bd87..57b6466a5 100644 --- a/packages/plugin-list/src/__tests__/ListView.test.tsx +++ b/packages/plugin-list/src/__tests__/ListView.test.tsx @@ -812,4 +812,61 @@ describe('ListView', () => { expect(screen.queryByRole('button', { name: /export/i })).not.toBeInTheDocument(); }); }); + + // ============================ + // Schema prop forwarding to child views + // ============================ + describe('Schema prop forwarding', () => { + it('should pass striped to child view schema', () => { + const schema: ListViewSchema = { + type: 'list-view', + objectName: 'contacts', + viewType: 'grid', + fields: ['name', 'email'], + striped: true, + }; + + const { container } = renderWithProvider(); + expect(container).toBeTruthy(); + }); + + it('should pass bordered to child view schema', () => { + const schema: ListViewSchema = { + type: 'list-view', + objectName: 'contacts', + viewType: 'grid', + fields: ['name', 'email'], + bordered: true, + }; + + const { container } = renderWithProvider(); + expect(container).toBeTruthy(); + }); + + it('should pass wrapHeaders to grid view schema', () => { + const schema: ListViewSchema = { + type: 'list-view', + objectName: 'contacts', + viewType: 'grid', + fields: ['name', 'email'], + wrapHeaders: true, + }; + + const { container } = renderWithProvider(); + expect(container).toBeTruthy(); + }); + + it('should pass inlineEdit as editable to grid view schema', () => { + const schema: ListViewSchema = { + type: 'list-view', + objectName: 'contacts', + viewType: 'grid', + fields: ['name', 'email'], + inlineEdit: true, + }; + + const { container } = renderWithProvider(); + expect(container).toBeTruthy(); + }); + }); }); diff --git a/packages/plugin-view/src/ObjectView.tsx b/packages/plugin-view/src/ObjectView.tsx index d2ac5a5cf..f6f36e734 100644 --- a/packages/plugin-view/src/ObjectView.tsx +++ b/packages/plugin-view/src/ObjectView.tsx @@ -826,6 +826,16 @@ export const ObjectView: React.FC = ({ striped: activeView?.striped ?? (schema as any).striped, bordered: activeView?.bordered ?? (schema as any).bordered, color: activeView?.color ?? (schema as any).color, + // Propagate view-config properties (Bug 4 / items 14-22) + inlineEdit: activeView?.inlineEdit ?? (schema as any).inlineEdit, + wrapHeaders: activeView?.wrapHeaders ?? (schema as any).wrapHeaders, + clickIntoRecordDetails: activeView?.clickIntoRecordDetails ?? (schema as any).clickIntoRecordDetails, + addRecordViaForm: activeView?.addRecordViaForm ?? (schema as any).addRecordViaForm, + addDeleteRecordsInline: activeView?.addDeleteRecordsInline ?? (schema as any).addDeleteRecordsInline, + collapseAllByDefault: activeView?.collapseAllByDefault ?? (schema as any).collapseAllByDefault, + fieldTextColor: activeView?.fieldTextColor ?? (schema as any).fieldTextColor, + prefixField: activeView?.prefixField ?? (schema as any).prefixField, + showDescription: activeView?.showDescription ?? (schema as any).showDescription, }, dataSource, onEdit: handleEdit, diff --git a/packages/types/src/objectql.ts b/packages/types/src/objectql.ts index 661c5413a..648b378f1 100644 --- a/packages/types/src/objectql.ts +++ b/packages/types/src/objectql.ts @@ -1033,6 +1033,33 @@ export interface NamedListView { /** Color field for row/card coloring */ color?: string; + + /** Enable inline editing @default false */ + inlineEdit?: boolean; + + /** Wrap column headers in grid view @default false */ + wrapHeaders?: boolean; + + /** Navigate to record detail view when row is clicked @default true */ + clickIntoRecordDetails?: boolean; + + /** Add records via a form dialog @default false */ + addRecordViaForm?: boolean; + + /** Enable inline add/delete of records @default false */ + addDeleteRecordsInline?: boolean; + + /** Collapse all grouped sections by default @default false */ + collapseAllByDefault?: boolean; + + /** Field name for custom text color */ + fieldTextColor?: string; + + /** Prefix field displayed before the main title */ + prefixField?: string; + + /** Show field descriptions below headers @default false */ + showDescription?: boolean; } /** @@ -1293,6 +1320,30 @@ export interface ListViewSchema extends BaseSchema { */ inlineEdit?: boolean; + /** Wrap column headers in grid view @default false */ + wrapHeaders?: boolean; + + /** Navigate to record detail view when row is clicked @default true */ + clickIntoRecordDetails?: boolean; + + /** Add records via a form dialog @default false */ + addRecordViaForm?: boolean; + + /** Enable inline add/delete of records @default false */ + addDeleteRecordsInline?: boolean; + + /** Collapse all grouped sections by default @default false */ + collapseAllByDefault?: boolean; + + /** Field name for custom text color */ + fieldTextColor?: string; + + /** Prefix field displayed before the main title */ + prefixField?: string; + + /** Show field descriptions below headers @default false */ + showDescription?: boolean; + /** * ARIA attributes for accessibility. * Applied to the root list container element. diff --git a/packages/types/src/zod/objectql.zod.ts b/packages/types/src/zod/objectql.zod.ts index c029884e8..e34c6d087 100644 --- a/packages/types/src/zod/objectql.zod.ts +++ b/packages/types/src/zod/objectql.zod.ts @@ -260,6 +260,15 @@ export const ListViewSchema = BaseSchema.extend({ striped: z.boolean().optional().describe('Alternating row colors'), bordered: z.boolean().optional().describe('Show cell borders'), color: z.string().optional().describe('Color field for row/card coloring'), + inlineEdit: z.boolean().optional().describe('Enable inline editing'), + wrapHeaders: z.boolean().optional().describe('Wrap column headers'), + clickIntoRecordDetails: z.boolean().optional().describe('Navigate to detail on row click'), + addRecordViaForm: z.boolean().optional().describe('Add records via form dialog'), + addDeleteRecordsInline: z.boolean().optional().describe('Enable inline add/delete'), + collapseAllByDefault: z.boolean().optional().describe('Collapse all groups by default'), + fieldTextColor: z.string().optional().describe('Field for custom text color'), + prefixField: z.string().optional().describe('Prefix field before title'), + showDescription: z.boolean().optional().describe('Show field descriptions'), }); /**