diff --git a/ROADMAP.md b/ROADMAP.md index e0f1d8df9..71d012632 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -13,7 +13,7 @@ ObjectUI is a universal Server-Driven UI (SDUI) engine built on React + Tailwind + Shadcn. It renders JSON metadata from the @objectstack/spec protocol into pixel-perfect, accessible, and interactive enterprise interfaces. -**Where We Are:** Foundation is **solid and shipping** — 35 packages, 99+ components, 5,700+ tests, 78 Storybook stories, 42/42 builds passing, ~85% protocol alignment. SpecBridge, Expression Engine, Action Engine, data binding, all view plugins (Grid/Kanban/Calendar/Gantt/Timeline/Map/Gallery), Record components, Report engine, Dashboard BI features, mobile UX, i18n (11 locales), WCAG AA accessibility, Designer Phase 1 (ViewDesigner drag-to-reorder ✅), Console through Phase 20 (L3), **AppShell Navigation Renderer** (P0.1), **Flow Designer** (P2.4), **Feed/Chatter UI** (P1.5), **App Creation & Editing Flow** (P1.11), and **System Settings & App Management** (P1.12) — all ✅ complete. +**Where We Are:** Foundation is **solid and shipping** — 35 packages, 99+ components, 5,700+ tests, 78 Storybook stories, 43/43 builds passing, ~85% protocol alignment. SpecBridge, Expression Engine, Action Engine, data binding, all view plugins (Grid/Kanban/Calendar/Gantt/Timeline/Map/Gallery), Record components, Report engine, Dashboard BI features, mobile UX, i18n (11 locales), WCAG AA accessibility, Designer Phase 1 (ViewDesigner drag-to-reorder ✅), Console through Phase 20 (L3), **AppShell Navigation Renderer** (P0.1), **Flow Designer** (P2.4), **Feed/Chatter UI** (P1.5), **App Creation & Editing Flow** (P1.11), and **System Settings & App Management** (P1.12) — all ✅ complete. **What Remains:** The gap to **Airtable-level UX** is primarily in: 1. ~~**AppShell** — No dynamic navigation renderer from spec JSON (last P0 blocker)~~ ✅ Complete diff --git a/apps/console/src/__tests__/ViewConfigPanel.test.tsx b/apps/console/src/__tests__/ViewConfigPanel.test.tsx index c2533f263..9a833250f 100644 --- a/apps/console/src/__tests__/ViewConfigPanel.test.tsx +++ b/apps/console/src/__tests__/ViewConfigPanel.test.tsx @@ -51,7 +51,7 @@ vi.mock('@object-ui/components', () => { // ConfigPanelRenderer mock — renders schema sections with proper collapse/visibility function ConfigPanelRenderer({ open, onClose, schema, draft, isDirty, onFieldChange, onSave, onDiscard, panelRef, role, ariaLabel, tabIndex, testId, saveLabel, discardLabel, className }: any) { - const [collapsed, setCollapsed] = React.useState>({}); + const [collapsed, setCollapsed] = React.useState({}); if (!open) return null; return React.createElement('div', { diff --git a/apps/console/src/__tests__/view-config-schema.test.tsx b/apps/console/src/__tests__/view-config-schema.test.tsx index a66e8b1d5..38acf2680 100644 --- a/apps/console/src/__tests__/view-config-schema.test.tsx +++ b/apps/console/src/__tests__/view-config-schema.test.tsx @@ -665,7 +665,7 @@ describe('spec alignment', () => { emptyState: '_emptyState', aria: '_ariaLabel', // compound: label/describedBy/live }; - for (const [specProp, fieldKey] of Object.entries(specPropertyToFieldKey)) { + for (const [_specProp, fieldKey] of Object.entries(specPropertyToFieldKey)) { expect(keys).toContain(fieldKey); } }); diff --git a/apps/console/src/pages/system/AppManagementPage.tsx b/apps/console/src/pages/system/AppManagementPage.tsx index f221f1eaa..4efa787a3 100644 --- a/apps/console/src/pages/system/AppManagementPage.tsx +++ b/apps/console/src/pages/system/AppManagementPage.tsx @@ -24,7 +24,6 @@ import { Star, ExternalLink, Search, - Loader2, } from 'lucide-react'; import { toast } from 'sonner'; import { useMetadata } from '../../context/MetadataProvider'; diff --git a/apps/console/src/pages/system/PermissionManagementPage.tsx b/apps/console/src/pages/system/PermissionManagementPage.tsx index 5f6190bd3..b914ef855 100644 --- a/apps/console/src/pages/system/PermissionManagementPage.tsx +++ b/apps/console/src/pages/system/PermissionManagementPage.tsx @@ -7,7 +7,7 @@ import { useState, useEffect, useCallback } from 'react'; import { useAuth } from '@object-ui/auth'; -import { Button, Card, CardContent, Badge, Input } from '@object-ui/components'; +import { Button, Badge, Input } from '@object-ui/components'; import { Plus, Key, Loader2, Trash2, Search } from 'lucide-react'; import { toast } from 'sonner'; import { useAdapter } from '../../context/AdapterProvider'; diff --git a/apps/console/src/utils/view-config-schema.tsx b/apps/console/src/utils/view-config-schema.tsx index e8a8108e5..b59087894 100644 --- a/apps/console/src/utils/view-config-schema.tsx +++ b/apps/console/src/utils/view-config-schema.tsx @@ -12,7 +12,7 @@ */ import React from 'react'; -import { Input, Switch, Checkbox, FilterBuilder, SortBuilder, ConfigRow, SectionHeader } from '@object-ui/components'; +import { Input, Switch, Checkbox, FilterBuilder, SortBuilder, ConfigRow } from '@object-ui/components'; import type { ConfigPanelSchema, ConfigField } from '@object-ui/components'; import type { FilterGroup, SortItem } from '@object-ui/components'; import { ArrowUp, ArrowDown } from 'lucide-react'; @@ -98,7 +98,7 @@ export function buildViewConfigSchema(opts: ViewSchemaFactoryOptions): ConfigPan function buildPageConfigSection( t: ViewSchemaFactoryOptions['t'], - fieldOptions: FieldOption[], + _fieldOptions: FieldOption[], objectDef: ViewSchemaFactoryOptions['objectDef'], updateField: ViewSchemaFactoryOptions['updateField'], ): ConfigPanelSchema['sections'][number] { @@ -426,7 +426,7 @@ function buildPageConfigSection( function buildDataSection( t: ViewSchemaFactoryOptions['t'], fieldOptions: FieldOption[], - fieldSelectWithNone: Array<{ value: string; label: string }>, + _fieldSelectWithNone: Array<{ value: string; label: string }>, objectDef: ViewSchemaFactoryOptions['objectDef'], updateField: ViewSchemaFactoryOptions['updateField'], filterGroupValue: FilterGroup, @@ -551,7 +551,7 @@ function buildDataSection( key: '_filterBy', label: t('console.objectView.filterBy'), type: 'custom', - render: (_value, _onChange, draft) => { + render: (_value, _onChange, _draft) => { const filterCount = filterGroupValue.conditions.length; const filterSummary = filterCount > 0 ? t('console.objectView.filtersCount', { count: filterCount }) @@ -964,7 +964,7 @@ function buildDataSection( function buildAppearanceSection( t: ViewSchemaFactoryOptions['t'], fieldOptions: FieldOption[], - fieldSelectWithNone: Array<{ value: string; label: string }>, + _fieldSelectWithNone: Array<{ value: string; label: string }>, updateField: ViewSchemaFactoryOptions['updateField'], ): ConfigPanelSchema['sections'][number] { return { diff --git a/packages/plugin-detail/src/RecordActivityTimeline.tsx b/packages/plugin-detail/src/RecordActivityTimeline.tsx index 695efbbc5..084cf7c91 100644 --- a/packages/plugin-detail/src/RecordActivityTimeline.tsx +++ b/packages/plugin-detail/src/RecordActivityTimeline.tsx @@ -133,7 +133,7 @@ export const RecordActivityTimeline: React.FC = ({ onFilterChange, hasMore = false, onLoadMore, - loading = false, + loading: _loading = false, onAddComment, onAddReply, onToggleReaction,