Skip to content

Commit 1d87e06

Browse files
authored
Merge pull request #463 from objectstack-ai/copilot/complete-development-roadmap
2 parents 11f9daa + 7e920c0 commit 1d87e06

26 files changed

Lines changed: 3892 additions & 59 deletions

ROADMAP.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,10 @@ ObjectUI's current overall compliance stands at **82%** (down from 91% against v
6060
| Category | Current | Target |
6161
|----------|---------|--------|
6262
| **UI Types** | 100% | 100% |
63-
| **API Protocol** | 89% | 100% |
64-
| **Feature Completeness** | 95% | 100% |
65-
| **v2.0.7 New Areas** | 96% | 100% |
66-
| **Overall** | **96%** | **100%** |
63+
| **API Protocol** | 95% | 100% |
64+
| **Feature Completeness** | 98% | 100% |
65+
| **v2.0.7 New Areas** | 100% | 100% |
66+
| **Overall** | **98%** | **100%** |
6767

6868
> Source: [SPEC_COMPLIANCE_EVALUATION.md](./SPEC_COMPLIANCE_EVALUATION.md) §8
6969
@@ -224,7 +224,7 @@ The v2.0.7 spec introduces 70+ new UI types across 12 domains. This section maps
224224
- [x] Refactor plugin-kanban card drag to use spec DnD schemas — DndBridge bridges @dnd-kit events to ObjectUI DndProvider
225225
- [x] Refactor plugin-dashboard widget drag to use spec DnD schemas — DndEditModeBridge bridges edit mode to DndProvider
226226
- [x] Add drag-to-reschedule for calendar events — native HTML5 DnD in MonthView with `onEventDrop` callback
227-
- [ ] Add drag-and-drop sidebar navigation reordering
227+
- [x] Add drag-and-drop sidebar navigation reordering — HTML5 native DnD in AppSidebar with localStorage persistence per app
228228

229229
**Spec Reference:** `DndConfigSchema`, `DragItemSchema`, `DropZoneSchema`, `DragConstraintSchema`, `DragHandleSchema`, `DropEffectSchema`
230230

@@ -311,19 +311,19 @@ The v2.0.7 spec introduces 70+ new UI types across 12 domains. This section maps
311311
- [x] Implement ConflictResolutionSchema strategies (last-write-wins, manual merge, server-wins) — configurable via `sync.conflictResolution`
312312
- [x] Implement EvictionPolicySchema for cache management (LRU, TTL, size-based) — configurable via `cache.evictionPolicy`
313313
- [x] Implement PersistStorageSchema for IndexedDB/localStorage persistence — localStorage queue persistence
314-
- [ ] Integrate with @objectstack/client ETag caching and Service Worker
314+
- [x] Integrate with @objectstack/client ETag caching and Service Worker`useETagCache` hook with ETag-aware fetch, LRU cache, Service Worker registration
315315
- [x] Add offline indicator UI with sync status — `showIndicator` + `offlineMessage` in `useOffline`
316316

317317
**Spec Reference:** `OfflineConfigSchema`, `OfflineCacheConfigSchema`, `OfflineStrategySchema`, `SyncConfigSchema`, `ConflictResolutionSchema`, `PersistStorageSchema`, `EvictionPolicySchema`
318318

319319
#### 3.2 Real-time Collaboration (4 weeks)
320320
**Target:** Multi-user real-time editing and presence
321321

322-
- [ ] Integrate `client.realtime.*` WebSocket API for live data subscriptions
323-
- [ ] Live cursors and presence indicators
324-
- [ ] Comment threads and @mentions
325-
- [ ] Conflict resolution with version history
326-
- [ ] Complete CollaborationProvider in plugin-designer
322+
- [x] Integrate `client.realtime.*` WebSocket API for live data subscriptions`useRealtimeSubscription` hook in @object-ui/collaboration
323+
- [x] Live cursors and presence indicators`LiveCursors`, `PresenceAvatars`, `usePresence` in @object-ui/collaboration
324+
- [x] Comment threads and @mentions`CommentThread` component in @object-ui/collaboration
325+
- [x] Conflict resolution with version history`useConflictResolution` hook in @object-ui/collaboration
326+
- [x] Complete CollaborationProvider in plugin-designer — enhanced with WebSocket transport, presence tracking, version counting
327327

328328
**Deliverables:**
329329
- @object-ui/collaboration package
@@ -332,9 +332,9 @@ The v2.0.7 spec introduces 70+ new UI types across 12 domains. This section maps
332332
**Target:** Implement PerformanceConfigSchema monitoring
333333

334334
- [x] Implement PerformanceConfigSchema runtime (LCP, FCP, TTI tracking) — `usePerformance` hook with Web Vitals
335-
- [ ] Add performance budget enforcement (bundle size, render time thresholds)
336-
- [ ] Optimize lazy loading with route-based code splitting
337-
- [ ] Add performance dashboard in console (dev mode)
335+
- [x] Add performance budget enforcement (bundle size, render time thresholds)`usePerformanceBudget` hook with violation tracking and dev-mode warnings
336+
- [x] Optimize lazy loading with route-based code splitting — Console app uses `React.lazy()` + `Suspense` for auth, admin, detail, dashboard, and designer routes
337+
- [x] Add performance dashboard in console (dev mode) — `PerformanceDashboard` floating panel with LCP, FCP, memory, render count, budget violations (Ctrl+Shift+P toggle)
338338
- [ ] Target: LCP < 600ms, bundle < 140KB gzipped
339339

340340
**Spec Reference:** `PerformanceConfigSchema`
@@ -344,8 +344,8 @@ The v2.0.7 spec introduces 70+ new UI types across 12 domains. This section maps
344344

345345
- [x] Implement PageTransitionSchema for route-level transitions (fade, slide, scale) — `usePageTransition` hook (9 transition types)
346346
- [x] Consume PageComponentType for page variant resolution — types re-exported from @object-ui/types
347-
- [ ] Add view transition animations between view types (grid ↔ kanban ↔ calendar)
348-
- [ ] Integrate with browser View Transitions API where supported
347+
- [x] Add view transition animations between view types (grid ↔ kanban ↔ calendar)`ViewSwitcher` enhanced with `animated` prop and `document.startViewTransition()` integration
348+
- [x] Integrate with browser View Transitions API where supported`useViewTransition` hook with native API support, CSS fallback, and reduced-motion awareness
349349

350350
**Spec Reference:** `PageTransitionSchema`, `PageComponentType`
351351

apps/console/src/App.tsx

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { BrowserRouter, Routes, Route, Navigate, useNavigate, useLocation, useSearchParams } from 'react-router-dom';
2-
import { useState, useEffect } from 'react';
2+
import { useState, useEffect, lazy, Suspense } from 'react';
33
import { ObjectForm } from '@object-ui/plugin-form';
44
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Empty, EmptyTitle } from '@object-ui/components';
55
import { toast } from 'sonner';
@@ -9,35 +9,37 @@ import type { ConnectionState } from './dataSource';
99
import appConfig from '../objectstack.shared';
1010
import { AuthGuard, useAuth } from '@object-ui/auth';
1111

12-
// Components
12+
// Components (eagerly loaded — always needed)
1313
import { ConsoleLayout } from './components/ConsoleLayout';
1414
import { CommandPalette } from './components/CommandPalette';
1515
import { ErrorBoundary } from './components/ErrorBoundary';
1616
import { LoadingScreen } from './components/LoadingScreen';
1717
import { ObjectView } from './components/ObjectView';
18-
import { RecordDetailView } from './components/RecordDetailView';
19-
import { DashboardView } from './components/DashboardView';
20-
import { PageView } from './components/PageView';
21-
import { ReportView } from './components/ReportView';
22-
import { ViewDesignerPage } from './components/ViewDesignerPage';
2318
import { ExpressionProvider } from './context/ExpressionProvider';
2419
import { ConditionalAuthWrapper } from './components/ConditionalAuthWrapper';
2520
import { KeyboardShortcutsDialog } from './components/KeyboardShortcutsDialog';
2621
import { OnboardingWalkthrough } from './components/OnboardingWalkthrough';
27-
import { SearchResultsPage } from './components/SearchResultsPage';
2822
import { useRecentItems } from './hooks/useRecentItems';
2923

30-
// Auth Pages
31-
import { LoginPage } from './pages/LoginPage';
32-
import { RegisterPage } from './pages/RegisterPage';
33-
import { ForgotPasswordPage } from './pages/ForgotPasswordPage';
24+
// Route-based code splitting — lazy-load less-frequently-used routes
25+
const RecordDetailView = lazy(() => import('./components/RecordDetailView').then(m => ({ default: m.RecordDetailView })));
26+
const DashboardView = lazy(() => import('./components/DashboardView').then(m => ({ default: m.DashboardView })));
27+
const PageView = lazy(() => import('./components/PageView').then(m => ({ default: m.PageView })));
28+
const ReportView = lazy(() => import('./components/ReportView').then(m => ({ default: m.ReportView })));
29+
const ViewDesignerPage = lazy(() => import('./components/ViewDesignerPage').then(m => ({ default: m.ViewDesignerPage })));
30+
const SearchResultsPage = lazy(() => import('./components/SearchResultsPage').then(m => ({ default: m.SearchResultsPage })));
3431

35-
// System Admin Pages
36-
import { UserManagementPage } from './pages/system/UserManagementPage';
37-
import { OrgManagementPage } from './pages/system/OrgManagementPage';
38-
import { RoleManagementPage } from './pages/system/RoleManagementPage';
39-
import { AuditLogPage } from './pages/system/AuditLogPage';
40-
import { ProfilePage } from './pages/system/ProfilePage';
32+
// Auth Pages (lazy — only needed before login)
33+
const LoginPage = lazy(() => import('./pages/LoginPage').then(m => ({ default: m.LoginPage })));
34+
const RegisterPage = lazy(() => import('./pages/RegisterPage').then(m => ({ default: m.RegisterPage })));
35+
const ForgotPasswordPage = lazy(() => import('./pages/ForgotPasswordPage').then(m => ({ default: m.ForgotPasswordPage })));
36+
37+
// System Admin Pages (lazy — rarely accessed)
38+
const UserManagementPage = lazy(() => import('./pages/system/UserManagementPage').then(m => ({ default: m.UserManagementPage })));
39+
const OrgManagementPage = lazy(() => import('./pages/system/OrgManagementPage').then(m => ({ default: m.OrgManagementPage })));
40+
const RoleManagementPage = lazy(() => import('./pages/system/RoleManagementPage').then(m => ({ default: m.RoleManagementPage })));
41+
const AuditLogPage = lazy(() => import('./pages/system/AuditLogPage').then(m => ({ default: m.AuditLogPage })));
42+
const ProfilePage = lazy(() => import('./pages/system/ProfilePage').then(m => ({ default: m.ProfilePage })));
4143

4244
import { useParams } from 'react-router-dom';
4345
import { ThemeProvider } from './components/theme-provider';
@@ -219,6 +221,7 @@ export function AppContent() {
219221
<OnboardingWalkthrough />
220222
<SchemaRendererProvider dataSource={dataSource || {}}>
221223
<ErrorBoundary>
224+
<Suspense fallback={<LoadingScreen />}>
222225
<Routes>
223226
<Route path="/" element={
224227
// Redirect to first route within the app
@@ -278,6 +281,7 @@ export function AppContent() {
278281
<Route path="system/audit-log" element={<AuditLogPage />} />
279282
<Route path="system/profile" element={<ProfilePage />} />
280283
</Routes>
284+
</Suspense>
281285
</ErrorBoundary>
282286

283287
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
@@ -365,6 +369,7 @@ export function App() {
365369
<ConsoleToaster position="bottom-right" />
366370
<ConditionalAuthWrapper authUrl="/api/auth">
367371
<BrowserRouter basename="/">
372+
<Suspense fallback={<LoadingScreen />}>
368373
<Routes>
369374
<Route path="/login" element={<LoginPage />} />
370375
<Route path="/register" element={<RegisterPage />} />
@@ -376,6 +381,7 @@ export function App() {
376381
} />
377382
<Route path="/" element={<RootRedirect />} />
378383
</Routes>
384+
</Suspense>
379385
</BrowserRouter>
380386
</ConditionalAuthWrapper>
381387
</ThemeProvider>

0 commit comments

Comments
 (0)