Skip to content

Commit 42f89b3

Browse files
authored
Merge pull request #698 from objectstack-ai/copilot/enhance-console-navigation
2 parents adb82b5 + 864a2f2 commit 42f89b3

File tree

7 files changed

+750
-28
lines changed

7 files changed

+750
-28
lines changed

ROADMAP.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,10 @@ ObjectUI is a universal Server-Driven UI (SDUI) engine built on React + Tailwind
110110

111111
### P1.7 Console — Navigation Enhancements
112112

113-
- [ ] AppShell `AppSchema` renderer (spec-driven sidebar from JSON)
114-
- [ ] Area switcher with grouped navigation
115-
- [ ] User-customizable sidebar (drag reorder, pin favorites)
116-
- [ ] Search within sidebar navigation
113+
- [x] AppShell `AppSchema` renderer (spec-driven sidebar from JSON)
114+
- [x] Area switcher with grouped navigation
115+
- [x] User-customizable sidebar (drag reorder, pin favorites)
116+
- [x] Search within sidebar navigation
117117

118118
### P1.8 Console — View Config Panel (Phase 20)
119119

packages/layout/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
"lint": "eslint ."
1919
},
2020
"dependencies": {
21+
"@dnd-kit/core": "^6.3.1",
22+
"@dnd-kit/sortable": "^10.0.0",
23+
"@dnd-kit/utilities": "^3.2.2",
2124
"@object-ui/components": "workspace:*",
2225
"@object-ui/core": "workspace:*",
2326
"@object-ui/react": "workspace:*",

packages/layout/src/AppSchemaRenderer.tsx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
SidebarGroup,
3434
SidebarGroupLabel,
3535
SidebarGroupContent,
36+
SidebarInput,
3637
useSidebar,
3738
} from '@object-ui/components';
3839
import type { AppSchema, NavigationItem, NavigationArea } from '@object-ui/types';
@@ -85,6 +86,23 @@ export interface AppSchemaRendererProps {
8586

8687
/** Whether the sidebar starts open @default true */
8788
defaultOpen?: boolean;
89+
90+
// --- P1.7 Navigation Enhancements ---
91+
92+
/** Show a search input in the sidebar to filter navigation items */
93+
enableSearch?: boolean;
94+
95+
/** Enable pin/favorite toggle on navigation items */
96+
enablePinning?: boolean;
97+
98+
/** Called when a navigation item is pinned or unpinned */
99+
onPinToggle?: (itemId: string, pinned: boolean) => void;
100+
101+
/** Enable drag-to-reorder for navigation items */
102+
enableReorder?: boolean;
103+
104+
/** Called when navigation items are reordered via drag */
105+
onReorder?: (reorderedItems: NavigationItem[]) => void;
88106
}
89107

90108
// ---------------------------------------------------------------------------
@@ -209,6 +227,11 @@ function InternalSidebar({
209227
activeAreaId,
210228
setActiveAreaId,
211229
resolvedNavigation,
230+
enableSearch,
231+
enablePinning,
232+
onPinToggle,
233+
enableReorder,
234+
onReorder,
212235
}: {
213236
schema: AppSchema;
214237
basePath: string;
@@ -219,9 +242,15 @@ function InternalSidebar({
219242
activeAreaId: string | null;
220243
setActiveAreaId: (id: string) => void;
221244
resolvedNavigation: NavigationItem[];
245+
enableSearch?: boolean;
246+
enablePinning?: boolean;
247+
onPinToggle?: (itemId: string, pinned: boolean) => void;
248+
enableReorder?: boolean;
249+
onReorder?: (reorderedItems: NavigationItem[]) => void;
222250
}) {
223251
const Icon = resolveIcon(schema.logo);
224252
const areas = schema.areas ?? [];
253+
const [searchQuery, setSearchQuery] = useState('');
225254

226255
return (
227256
<Sidebar collapsible="icon">
@@ -254,6 +283,15 @@ function InternalSidebar({
254283
</SidebarMenuButton>
255284
</SidebarMenuItem>
256285
</SidebarMenu>
286+
{/* Search input */}
287+
{enableSearch && (
288+
<SidebarInput
289+
placeholder="Search navigation…"
290+
value={searchQuery}
291+
onChange={(e) => setSearchQuery(e.target.value)}
292+
aria-label="Search navigation"
293+
/>
294+
)}
257295
</SidebarHeader>
258296

259297
<SidebarContent>
@@ -275,6 +313,11 @@ function InternalSidebar({
275313
evaluateVisibility={evalVis}
276314
checkPermission={checkPerm}
277315
onAction={onAction}
316+
searchQuery={searchQuery}
317+
enablePinning={enablePinning}
318+
onPinToggle={onPinToggle}
319+
enableReorder={enableReorder}
320+
onReorder={onReorder}
278321
/>
279322
</SidebarContent>
280323

@@ -324,6 +367,11 @@ export function AppSchemaRenderer({
324367
children,
325368
className,
326369
defaultOpen = true,
370+
enableSearch,
371+
enablePinning,
372+
onPinToggle,
373+
enableReorder,
374+
onReorder,
327375
}: AppSchemaRendererProps) {
328376
// Default evaluators
329377
const evalVis: VisibilityEvaluator = evalVisProp ?? ((expr) => {
@@ -379,6 +427,11 @@ export function AppSchemaRenderer({
379427
activeAreaId={activeAreaId}
380428
setActiveAreaId={setActiveAreaId}
381429
resolvedNavigation={resolvedNavigation}
430+
enableSearch={enableSearch}
431+
enablePinning={enablePinning}
432+
onPinToggle={onPinToggle}
433+
enableReorder={enableReorder}
434+
onReorder={onReorder}
382435
/>
383436
);
384437

0 commit comments

Comments
 (0)