Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ ObjectUI's current overall compliance stands at **82%** (down from 91% against v
| Category | Current | Target |
|----------|---------|--------|
| **UI Types** | 100% | 100% |
| **API Protocol** | 89% | 100% |
| **Feature Completeness** | 95% | 100% |
| **v2.0.7 New Areas** | 96% | 100% |
| **Overall** | **96%** | **100%** |
| **API Protocol** | 95% | 100% |
| **Feature Completeness** | 98% | 100% |
| **v2.0.7 New Areas** | 100% | 100% |
| **Overall** | **98%** | **100%** |

> Source: [SPEC_COMPLIANCE_EVALUATION.md](./SPEC_COMPLIANCE_EVALUATION.md) §8

Expand Down Expand Up @@ -224,7 +224,7 @@ The v2.0.7 spec introduces 70+ new UI types across 12 domains. This section maps
- [x] Refactor plugin-kanban card drag to use spec DnD schemas — DndBridge bridges @dnd-kit events to ObjectUI DndProvider
- [x] Refactor plugin-dashboard widget drag to use spec DnD schemas — DndEditModeBridge bridges edit mode to DndProvider
- [x] Add drag-to-reschedule for calendar events — native HTML5 DnD in MonthView with `onEventDrop` callback
- [ ] Add drag-and-drop sidebar navigation reordering
- [x] Add drag-and-drop sidebar navigation reordering — HTML5 native DnD in AppSidebar with localStorage persistence per app

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

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

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

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

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

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

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

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

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

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

Expand Down
42 changes: 24 additions & 18 deletions apps/console/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BrowserRouter, Routes, Route, Navigate, useNavigate, useLocation, useSearchParams } from 'react-router-dom';
import { useState, useEffect } from 'react';
import { useState, useEffect, lazy, Suspense } from 'react';
import { ObjectForm } from '@object-ui/plugin-form';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Empty, EmptyTitle } from '@object-ui/components';
import { toast } from 'sonner';
Expand All @@ -9,35 +9,37 @@ import type { ConnectionState } from './dataSource';
import appConfig from '../objectstack.shared';
import { AuthGuard, useAuth } from '@object-ui/auth';

// Components
// Components (eagerly loaded — always needed)
import { ConsoleLayout } from './components/ConsoleLayout';
import { CommandPalette } from './components/CommandPalette';
import { ErrorBoundary } from './components/ErrorBoundary';
import { LoadingScreen } from './components/LoadingScreen';
import { ObjectView } from './components/ObjectView';
import { RecordDetailView } from './components/RecordDetailView';
import { DashboardView } from './components/DashboardView';
import { PageView } from './components/PageView';
import { ReportView } from './components/ReportView';
import { ViewDesignerPage } from './components/ViewDesignerPage';
import { ExpressionProvider } from './context/ExpressionProvider';
import { ConditionalAuthWrapper } from './components/ConditionalAuthWrapper';
import { KeyboardShortcutsDialog } from './components/KeyboardShortcutsDialog';
import { OnboardingWalkthrough } from './components/OnboardingWalkthrough';
import { SearchResultsPage } from './components/SearchResultsPage';
import { useRecentItems } from './hooks/useRecentItems';

// Auth Pages
import { LoginPage } from './pages/LoginPage';
import { RegisterPage } from './pages/RegisterPage';
import { ForgotPasswordPage } from './pages/ForgotPasswordPage';
// Route-based code splitting — lazy-load less-frequently-used routes
const RecordDetailView = lazy(() => import('./components/RecordDetailView').then(m => ({ default: m.RecordDetailView })));
const DashboardView = lazy(() => import('./components/DashboardView').then(m => ({ default: m.DashboardView })));
const PageView = lazy(() => import('./components/PageView').then(m => ({ default: m.PageView })));
const ReportView = lazy(() => import('./components/ReportView').then(m => ({ default: m.ReportView })));
const ViewDesignerPage = lazy(() => import('./components/ViewDesignerPage').then(m => ({ default: m.ViewDesignerPage })));
const SearchResultsPage = lazy(() => import('./components/SearchResultsPage').then(m => ({ default: m.SearchResultsPage })));

// System Admin Pages
import { UserManagementPage } from './pages/system/UserManagementPage';
import { OrgManagementPage } from './pages/system/OrgManagementPage';
import { RoleManagementPage } from './pages/system/RoleManagementPage';
import { AuditLogPage } from './pages/system/AuditLogPage';
import { ProfilePage } from './pages/system/ProfilePage';
// Auth Pages (lazy — only needed before login)
const LoginPage = lazy(() => import('./pages/LoginPage').then(m => ({ default: m.LoginPage })));
const RegisterPage = lazy(() => import('./pages/RegisterPage').then(m => ({ default: m.RegisterPage })));
const ForgotPasswordPage = lazy(() => import('./pages/ForgotPasswordPage').then(m => ({ default: m.ForgotPasswordPage })));

// System Admin Pages (lazy — rarely accessed)
const UserManagementPage = lazy(() => import('./pages/system/UserManagementPage').then(m => ({ default: m.UserManagementPage })));
const OrgManagementPage = lazy(() => import('./pages/system/OrgManagementPage').then(m => ({ default: m.OrgManagementPage })));
const RoleManagementPage = lazy(() => import('./pages/system/RoleManagementPage').then(m => ({ default: m.RoleManagementPage })));
const AuditLogPage = lazy(() => import('./pages/system/AuditLogPage').then(m => ({ default: m.AuditLogPage })));
const ProfilePage = lazy(() => import('./pages/system/ProfilePage').then(m => ({ default: m.ProfilePage })));

import { useParams } from 'react-router-dom';
import { ThemeProvider } from './components/theme-provider';
Expand Down Expand Up @@ -219,6 +221,7 @@ export function AppContent() {
<OnboardingWalkthrough />
<SchemaRendererProvider dataSource={dataSource || {}}>
<ErrorBoundary>
<Suspense fallback={<LoadingScreen />}>
<Routes>
<Route path="/" element={
// Redirect to first route within the app
Expand Down Expand Up @@ -278,6 +281,7 @@ export function AppContent() {
<Route path="system/audit-log" element={<AuditLogPage />} />
<Route path="system/profile" element={<ProfilePage />} />
</Routes>
</Suspense>
</ErrorBoundary>

<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
Expand Down Expand Up @@ -365,6 +369,7 @@ export function App() {
<ConsoleToaster position="bottom-right" />
<ConditionalAuthWrapper authUrl="/api/auth">
<BrowserRouter basename="/">
<Suspense fallback={<LoadingScreen />}>
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route path="/register" element={<RegisterPage />} />
Expand All @@ -376,6 +381,7 @@ export function App() {
} />
<Route path="/" element={<RootRedirect />} />
</Routes>
</Suspense>
</BrowserRouter>
</ConditionalAuthWrapper>
</ThemeProvider>
Expand Down
Loading
Loading