Skip to content

Commit 8930ce7

Browse files
authored
Merge pull request #776 from objectstack-ai/copilot/add-page-dashboard-editor
2 parents 4da92a7 + 498ab8b commit 8930ce7

File tree

16 files changed

+963
-57
lines changed

16 files changed

+963
-57
lines changed

ROADMAP.md

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -444,13 +444,27 @@ ObjectUI is a universal Server-Driven UI (SDUI) engine built on React + Tailwind
444444
- [x] Property panel for selected component (label, type, ID)
445445
- [x] Add/remove/reorder components
446446
- [x] Syncs PageSchema children on every change
447+
- [x] Undo/Redo integration via `useUndoRedo` hook (Ctrl+Z / Ctrl+Y keyboard shortcuts)
448+
- [x] JSON Schema export/import (Download/Upload toolbar buttons with `onExport`/`onImport` callbacks)
449+
- [x] Preview mode toggle (Eye icon, renders PagePreview panel)
450+
- [x] Page/Dashboard mode tab switching (role="tablist" with aria-selected)
451+
- [x] i18n integration via `useDesignerTranslation` (all labels use translation keys)
452+
- [x] Keyboard shortcuts (Delete/Backspace to remove selected component)
453+
- [x] Mobile responsive layout (flex-col on mobile, sm:flex-row on desktop)
447454

448455
**Dashboard Editor:**
449456
- [x] 6 widget types (KPI Metric, Bar Chart, Line Chart, Pie Chart, Table, Grid)
450457
- [x] Widget card grid with selection, drag handles, reorder
451458
- [x] Widget property panel (title, type, data source, value field, aggregate, color variant)
452459
- [x] Add/remove/reorder widgets
453460
- [x] Grid layout based on DashboardSchema columns
461+
- [x] Undo/Redo integration via `useUndoRedo` hook (Ctrl+Z / Ctrl+Y keyboard shortcuts)
462+
- [x] JSON Schema export/import (Download/Upload toolbar buttons with `onExport`/`onImport` callbacks)
463+
- [x] Preview mode toggle (Eye icon, renders DashboardPreview panel)
464+
- [x] Widget layout size editing (width/height inputs in property panel)
465+
- [x] i18n integration via `useDesignerTranslation` (all labels use translation keys)
466+
- [x] Keyboard shortcuts (Delete/Backspace to remove selected widget)
467+
- [x] Mobile responsive layout (flex-col on mobile, sm:flex-row on desktop)
454468

455469
**Object View Configurator:**
456470
- [x] 7 view type switcher (Grid, Kanban, Calendar, Gallery, Timeline, Map, Gantt)
@@ -466,10 +480,12 @@ ObjectUI is a universal Server-Driven UI (SDUI) engine built on React + Tailwind
466480
- [x] Disabled state support
467481

468482
**i18n:**
469-
- [x] `appDesigner` section with 103 keys added to all 10 locales (en, zh, ja, de, fr, es, ar, ru, pt, ko)
483+
- [x] `appDesigner` section with 119 keys added to all 10 locales (en, zh, ja, de, fr, es, ar, ru, pt, ko)
470484
- [x] `useDesignerTranslation` safe wrapper hook with English fallback (no I18nProvider required)
471485
- [x] AppCreationWizard fully i18n-integrated (all labels, buttons, step names, validation messages)
472486
- [x] NavigationDesigner fully i18n-integrated (type badges, quick-add labels, aria-labels, preview, icon editing, visibility, export/import)
487+
- [x] DashboardEditor fully i18n-integrated (toolbar labels, preview text)
488+
- [x] PageCanvasEditor fully i18n-integrated (toolbar labels, mode tabs, preview text)
473489

474490
**UX Enhancements:**
475491
- [x] Cancel confirmation dialog with unsaved-changes detection
@@ -481,10 +497,10 @@ ObjectUI is a universal Server-Driven UI (SDUI) engine built on React + Tailwind
481497
- [x] 41 AppCreationWizard tests (rendering, steps 1-4, navigation, callbacks, cancel confirm, save draft, i18n, read-only)
482498
- [x] 33 NavigationDesigner tests (rendering, add, remove, groups, badges, i18n, read-only, icon editing, visibility toggle, export/import, responsive)
483499
- [x] 7 EditorModeToggle tests (render, active mode, onChange, accessibility, disabled)
484-
- [x] 10 DashboardEditor tests (rendering, add/remove widgets, property panel, read-only)
485-
- [x] 9 PageCanvasEditor tests (rendering, add/remove components, property panel, read-only)
500+
- [x] 22 DashboardEditor tests (rendering, add/remove widgets, property panel, read-only, undo/redo, export/import, preview mode, widget layout)
501+
- [x] 23 PageCanvasEditor tests (rendering, add/remove components, property panel, read-only, mode tabs, undo/redo, export/import, preview mode)
486502
- [x] 12 ObjectViewConfigurator tests (rendering, view type switch, column visibility, toggles, read-only)
487-
- [x] **Total: 180 tests across 9 files, all passing**
503+
- [x] **Total: 206 tests across 9 files, all passing**
488504

489505
**ComponentRegistry:**
490506
- [x] Registered: `app-creation-wizard`, `navigation-designer`, `dashboard-editor`, `page-canvas-editor`, `object-view-configurator`

packages/i18n/src/locales/ar.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,21 @@ const ar = {
239239
navImportSuccess: 'تم استيراد هيكل التنقل',
240240
navImportError: 'ملف JSON تنقل غير صالح',
241241
navIconPlaceholder: 'اسم الأيقونة (مثل Users)',
242+
dashboardEditor: 'محرر لوحة المعلومات',
243+
noWidgets: 'لا توجد عناصر. انقر على زر أعلاه لإضافة واحد.',
244+
widgetLayoutSize: 'حجم التخطيط',
245+
widgetWidth: 'العرض',
246+
widgetHeight: 'الارتفاع',
247+
dashboardPreview: 'معاينة لوحة المعلومات',
248+
noWidgetsPreview: 'لا توجد عناصر للمعاينة',
249+
pageCanvasEditor: 'محرر لوحة الصفحة',
250+
emptyPage: 'صفحة فارغة. انقر على زر أعلاه لإضافة مكون.',
251+
pagePreview: 'معاينة الصفحة',
252+
noComponentsPreview: 'لا توجد مكونات للمعاينة',
253+
modePage: 'صفحة',
254+
modeDashboard: 'لوحة المعلومات',
255+
undo: 'تراجع',
256+
redo: 'إعادة',
242257
},
243258
console: {
244259
title: 'وحدة تحكم ObjectStack',

packages/i18n/src/locales/de.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,21 @@ const de = {
238238
navImportSuccess: 'Navigationsstruktur importiert',
239239
navImportError: 'Ungültiges Navigations-JSON',
240240
navIconPlaceholder: 'Symbolname (z.B. Users)',
241+
dashboardEditor: 'Dashboard-Editor',
242+
noWidgets: 'Keine Widgets. Klicken Sie oben auf eine Schaltfläche, um eines hinzuzufügen.',
243+
widgetLayoutSize: 'Layoutgröße',
244+
widgetWidth: 'Breite',
245+
widgetHeight: 'Höhe',
246+
dashboardPreview: 'Dashboard-Vorschau',
247+
noWidgetsPreview: 'Keine Widgets zur Vorschau',
248+
pageCanvasEditor: 'Seiten-Canvas-Editor',
249+
emptyPage: 'Leere Seite. Klicken Sie oben auf eine Schaltfläche, um eine Komponente hinzuzufügen.',
250+
pagePreview: 'Seitenvorschau',
251+
noComponentsPreview: 'Keine Komponenten zur Vorschau',
252+
modePage: 'Seite',
253+
modeDashboard: 'Dashboard',
254+
undo: 'Rückgängig',
255+
redo: 'Wiederholen',
241256
},
242257
console: {
243258
title: 'ObjectStack Konsole',

packages/i18n/src/locales/en.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,21 @@ const en = {
238238
navImportSuccess: 'Navigation schema imported',
239239
navImportError: 'Invalid navigation JSON',
240240
navIconPlaceholder: 'Icon name (e.g. Users)',
241+
dashboardEditor: 'Dashboard Editor',
242+
noWidgets: 'No widgets. Click a button above to add one.',
243+
widgetLayoutSize: 'Layout Size',
244+
widgetWidth: 'Width',
245+
widgetHeight: 'Height',
246+
dashboardPreview: 'Dashboard Preview',
247+
noWidgetsPreview: 'No widgets to preview',
248+
pageCanvasEditor: 'Page Canvas Editor',
249+
emptyPage: 'Empty page. Click a button above to add a component.',
250+
pagePreview: 'Page Preview',
251+
noComponentsPreview: 'No components to preview',
252+
modePage: 'Page',
253+
modeDashboard: 'Dashboard',
254+
undo: 'Undo',
255+
redo: 'Redo',
241256
},
242257
console: {
243258
title: 'ObjectStack Console',

packages/i18n/src/locales/es.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,21 @@ const es = {
238238
navImportSuccess: 'Estructura de navegación importada',
239239
navImportError: 'JSON de navegación inválido',
240240
navIconPlaceholder: 'Nombre del icono (ej: Users)',
241+
dashboardEditor: 'Editor de panel',
242+
noWidgets: 'Sin widgets. Haz clic en un botón arriba para agregar uno.',
243+
widgetLayoutSize: 'Tamaño de diseño',
244+
widgetWidth: 'Ancho',
245+
widgetHeight: 'Alto',
246+
dashboardPreview: 'Vista previa del panel',
247+
noWidgetsPreview: 'Sin widgets para previsualizar',
248+
pageCanvasEditor: 'Editor de lienzo de página',
249+
emptyPage: 'Página vacía. Haz clic en un botón arriba para agregar un componente.',
250+
pagePreview: 'Vista previa de página',
251+
noComponentsPreview: 'Sin componentes para previsualizar',
252+
modePage: 'Página',
253+
modeDashboard: 'Panel',
254+
undo: 'Deshacer',
255+
redo: 'Rehacer',
241256
},
242257
console: {
243258
title: 'Consola ObjectStack',

packages/i18n/src/locales/fr.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,21 @@ const fr = {
238238
navImportSuccess: 'Structure de navigation importée',
239239
navImportError: 'JSON de navigation invalide',
240240
navIconPlaceholder: 'Nom d\'icône (ex: Users)',
241+
dashboardEditor: 'Éditeur de tableau de bord',
242+
noWidgets: 'Aucun widget. Cliquez sur un bouton ci-dessus pour en ajouter un.',
243+
widgetLayoutSize: 'Taille de mise en page',
244+
widgetWidth: 'Largeur',
245+
widgetHeight: 'Hauteur',
246+
dashboardPreview: 'Aperçu du tableau de bord',
247+
noWidgetsPreview: 'Aucun widget à prévisualiser',
248+
pageCanvasEditor: 'Éditeur de canevas de page',
249+
emptyPage: 'Page vide. Cliquez sur un bouton ci-dessus pour ajouter un composant.',
250+
pagePreview: 'Aperçu de la page',
251+
noComponentsPreview: 'Aucun composant à prévisualiser',
252+
modePage: 'Page',
253+
modeDashboard: 'Tableau de bord',
254+
undo: 'Annuler',
255+
redo: 'Rétablir',
241256
},
242257
console: {
243258
title: 'Console ObjectStack',

packages/i18n/src/locales/ja.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,21 @@ const ja = {
238238
navImportSuccess: 'ナビゲーション構造をインポートしました',
239239
navImportError: '無効なナビゲーション JSON',
240240
navIconPlaceholder: 'アイコン名(例: Users)',
241+
dashboardEditor: 'ダッシュボードエディター',
242+
noWidgets: 'ウィジェットがありません。上のボタンをクリックして追加してください。',
243+
widgetLayoutSize: 'レイアウトサイズ',
244+
widgetWidth: '幅',
245+
widgetHeight: '高さ',
246+
dashboardPreview: 'ダッシュボードプレビュー',
247+
noWidgetsPreview: 'プレビューするウィジェットがありません',
248+
pageCanvasEditor: 'ページキャンバスエディター',
249+
emptyPage: '空のページです。上のボタンをクリックしてコンポーネントを追加してください。',
250+
pagePreview: 'ページプレビュー',
251+
noComponentsPreview: 'プレビューするコンポーネントがありません',
252+
modePage: 'ページ',
253+
modeDashboard: 'ダッシュボード',
254+
undo: '元に戻す',
255+
redo: 'やり直し',
241256
},
242257
console: {
243258
title: 'ObjectStack コンソール',

packages/i18n/src/locales/ko.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,21 @@ const ko = {
238238
navImportSuccess: '내비게이션 구조를 가져왔습니다',
239239
navImportError: '잘못된 내비게이션 JSON',
240240
navIconPlaceholder: '아이콘 이름 (예: Users)',
241+
dashboardEditor: '대시보드 편집기',
242+
noWidgets: '위젯이 없습니다. 위의 버튼을 클릭하여 추가하세요.',
243+
widgetLayoutSize: '레이아웃 크기',
244+
widgetWidth: '너비',
245+
widgetHeight: '높이',
246+
dashboardPreview: '대시보드 미리보기',
247+
noWidgetsPreview: '미리볼 위젯이 없습니다',
248+
pageCanvasEditor: '페이지 캔버스 편집기',
249+
emptyPage: '빈 페이지입니다. 위의 버튼을 클릭하여 컴포넌트를 추가하세요.',
250+
pagePreview: '페이지 미리보기',
251+
noComponentsPreview: '미리볼 컴포넌트가 없습니다',
252+
modePage: '페이지',
253+
modeDashboard: '대시보드',
254+
undo: '실행 취소',
255+
redo: '다시 실행',
241256
},
242257
console: {
243258
title: 'ObjectStack 콘솔',

packages/i18n/src/locales/pt.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,21 @@ const pt = {
238238
navImportSuccess: 'Estrutura de navegação importada',
239239
navImportError: 'JSON de navegação inválido',
240240
navIconPlaceholder: 'Nome do ícone (ex: Users)',
241+
dashboardEditor: 'Editor de painel',
242+
noWidgets: 'Sem widgets. Clique em um botão acima para adicionar.',
243+
widgetLayoutSize: 'Tamanho do layout',
244+
widgetWidth: 'Largura',
245+
widgetHeight: 'Altura',
246+
dashboardPreview: 'Pré-visualização do painel',
247+
noWidgetsPreview: 'Sem widgets para pré-visualizar',
248+
pageCanvasEditor: 'Editor de tela de página',
249+
emptyPage: 'Página vazia. Clique em um botão acima para adicionar um componente.',
250+
pagePreview: 'Pré-visualização da página',
251+
noComponentsPreview: 'Sem componentes para pré-visualizar',
252+
modePage: 'Página',
253+
modeDashboard: 'Painel',
254+
undo: 'Desfazer',
255+
redo: 'Refazer',
241256
},
242257
console: {
243258
title: 'Console ObjectStack',

packages/i18n/src/locales/ru.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,21 @@ const ru = {
238238
navImportSuccess: 'Структура навигации импортирована',
239239
navImportError: 'Недопустимый JSON навигации',
240240
navIconPlaceholder: 'Имя иконки (напр. Users)',
241+
dashboardEditor: 'Редактор панели',
242+
noWidgets: 'Нет виджетов. Нажмите кнопку выше, чтобы добавить.',
243+
widgetLayoutSize: 'Размер макета',
244+
widgetWidth: 'Ширина',
245+
widgetHeight: 'Высота',
246+
dashboardPreview: 'Предпросмотр панели',
247+
noWidgetsPreview: 'Нет виджетов для предпросмотра',
248+
pageCanvasEditor: 'Редактор холста страницы',
249+
emptyPage: 'Пустая страница. Нажмите кнопку выше, чтобы добавить компонент.',
250+
pagePreview: 'Предпросмотр страницы',
251+
noComponentsPreview: 'Нет компонентов для предпросмотра',
252+
modePage: 'Страница',
253+
modeDashboard: 'Панель',
254+
undo: 'Отменить',
255+
redo: 'Повторить',
241256
},
242257
console: {
243258
title: 'Консоль ObjectStack',

0 commit comments

Comments
 (0)