@umituz/web-dashboard 6.8.0 → 6.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/web-dashboard",
3
- "version": "6.8.0",
3
+ "version": "6.9.0",
4
4
  "description": "Installable app skeleton for the fleet — layouts, analytics (dependency-free SVG charts), calendar, onboarding flow, i18n via @umituz/web-localization, permissions/module registry; udb-* stylesheet on design-system tokens",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -98,4 +98,28 @@ describe("DashboardLayout (command palette)", () => {
98
98
  expect(onActivate).toHaveBeenCalledTimes(1);
99
99
  expect(screen.queryByRole("dialog")).toBeNull();
100
100
  });
101
+
102
+ it("derives navigation groups from the sidebar when includeSidebar is set", async () => {
103
+ renderAt("/", undefined, {
104
+ ...config,
105
+ commandPalette: {
106
+ includeSidebar: true,
107
+ groups: [{ heading: "Quick", items: [{ id: "q", label: "Quick action", onSelect: () => {} }] }],
108
+ },
109
+ });
110
+ fireEvent.keyDown(window, { key: "k", metaKey: true });
111
+ expect(await screen.findByRole("option", { name: "Quick action" })).toBeTruthy();
112
+ // The custom group has no "Home" — the one present is derived from the sidebar,
113
+ // carrying the path as its hint (accessible name "Home /").
114
+ const derived = screen.getByRole("option", { name: /home/i });
115
+ expect(derived.textContent).toContain("/");
116
+ });
117
+
118
+ it("omits sidebar-derived items from the palette by default", async () => {
119
+ renderAt("/", undefined, paletteConfig());
120
+ fireEvent.keyDown(window, { key: "k", metaKey: true });
121
+ // Only the palette's own "Home" (no path hint) — nothing derived from the sidebar.
122
+ const own = await screen.findByRole("option", { name: "Home" });
123
+ expect(own.textContent).toBe("Home");
124
+ });
101
125
  });
@@ -1,5 +1,5 @@
1
1
  import { useState, useEffect, type ReactNode } from "react";
2
- import { useLocation, Outlet, Navigate } from "react-router-dom";
2
+ import { useLocation, useNavigate, Outlet, Navigate } from "react-router-dom";
3
3
  import { useT } from "@umituz/web-localization/react";
4
4
  import { Skeleton } from "@umituz/web-design-system/atoms";
5
5
  import { CommandPalette } from "@umituz/web-design-system/organisms";
@@ -61,6 +61,7 @@ export const DashboardLayout = ({
61
61
  skipToContentLabel,
62
62
  }: DashboardLayoutProps) => {
63
63
  const location = useLocation();
64
+ const navigate = useNavigate();
64
65
  const t = useT();
65
66
  const [collapsed, setCollapsed] = useState(() => readCollapsed(collapsedStorageKey));
66
67
  const [mobileOpen, setMobileOpen] = useState(false);
@@ -132,6 +133,23 @@ export const DashboardLayout = ({
132
133
 
133
134
  const currentTitle = getTitle();
134
135
 
136
+ // Sidebar-derived navigation groups — one nav definition feeds both chrome surfaces.
137
+ const paletteGroups = palette?.includeSidebar
138
+ ? [
139
+ ...palette.groups,
140
+ ...config.sidebarGroups.map((group) => ({
141
+ heading: group.title,
142
+ items: group.items.map((item) => ({
143
+ id: `nav-${item.path}`,
144
+ label: item.raw ? item.label : t(item.label),
145
+ icon: <item.icon size={16} aria-hidden="true" />,
146
+ hint: item.path,
147
+ onSelect: () => navigate(item.path),
148
+ })),
149
+ })),
150
+ ]
151
+ : undefined;
152
+
135
153
  const sidebarProps = {
136
154
  sidebarGroups: config.sidebarGroups,
137
155
  brandName: config.brandName,
@@ -225,7 +243,7 @@ export const DashboardLayout = ({
225
243
  <CommandPalette
226
244
  open={paletteOpen}
227
245
  onOpenChange={setPaletteOpen}
228
- groups={palette.groups}
246
+ groups={paletteGroups ?? palette.groups}
229
247
  placeholder={palette.placeholder}
230
248
  emptyLabel={palette.emptyLabel}
231
249
  label={palette.label}
@@ -42,6 +42,9 @@ export interface CommandPaletteConfig {
42
42
  label?: string;
43
43
  /** Bind ⌘K/Ctrl+K to open the palette (default true). */
44
44
  shortcut?: boolean;
45
+ /** Append the sidebar groups as navigation groups — derived from
46
+ * sidebarGroups and routed internally, so apps never map their nav twice. */
47
+ includeSidebar?: boolean;
45
48
  }
46
49
 
47
50
  export interface DashboardSidebarProps {