@pablo2410/shared-ui 0.9.2 → 0.9.4

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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  readActiveEnterpriseCookie
3
- } from "./chunk-YVMCOFHL.js";
3
+ } from "./chunk-ZLOUWBQN.js";
4
4
  import {
5
5
  Avatar,
6
6
  AvatarFallback,
@@ -90,43 +90,110 @@ function useSidebarResize(config) {
90
90
  // src/layout/DashboardLayout.tsx
91
91
  import { ArrowLeft, LogOut, PanelLeft, Settings } from "lucide-react";
92
92
 
93
+ // src/layout/CrossServiceNav.tsx
94
+ import {
95
+ ClipboardCheck,
96
+ Gauge,
97
+ LayoutGrid,
98
+ Target,
99
+ ExternalLink
100
+ } from "lucide-react";
101
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
102
+ var ICONS = {
103
+ Target,
104
+ LayoutGrid,
105
+ Gauge,
106
+ ClipboardCheck
107
+ };
108
+ function CrossServiceNav({
109
+ links,
110
+ label = "Services"
111
+ }) {
112
+ const { state } = useSidebar();
113
+ const isCollapsed = state === "collapsed";
114
+ if (links.length === 0) return null;
115
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
116
+ !isCollapsed && /* @__PURE__ */ jsx("div", { className: "px-4 pt-2", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wider", children: label }) }),
117
+ /* @__PURE__ */ jsx(SidebarMenu, { className: "px-2 py-1", children: links.map((link) => {
118
+ const Icon = ICONS[link.icon] ?? ExternalLink;
119
+ return /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(
120
+ SidebarMenuButton,
121
+ {
122
+ onClick: () => {
123
+ window.location.href = link.url;
124
+ },
125
+ tooltip: link.name,
126
+ className: "h-10 transition-all font-normal text-muted-foreground hover:text-foreground",
127
+ children: [
128
+ /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }),
129
+ /* @__PURE__ */ jsx("span", { children: link.name })
130
+ ]
131
+ }
132
+ ) }, link.slug);
133
+ }) })
134
+ ] });
135
+ }
136
+
93
137
  // src/layout/HealthFooter.tsx
94
- import { jsx, jsxs } from "react/jsx-runtime";
138
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
139
+ function formatBuildDate(iso) {
140
+ if (!iso) return void 0;
141
+ const d = new Date(iso);
142
+ if (Number.isNaN(d.getTime())) return void 0;
143
+ const day = d.getUTCDate();
144
+ const month = d.toLocaleString("en-GB", { month: "short", timeZone: "UTC" });
145
+ const hh = String(d.getUTCHours()).padStart(2, "0");
146
+ const mm = String(d.getUTCMinutes()).padStart(2, "0");
147
+ return `${day} ${month} ${hh}:${mm}Z`;
148
+ }
95
149
  function HealthFooter({
96
150
  user,
97
151
  enterprise,
98
152
  className,
99
- style
153
+ style,
154
+ buildVersion,
155
+ buildDate,
156
+ commitHash
100
157
  }) {
101
- return /* @__PURE__ */ jsxs(
158
+ const version = buildVersion ?? (typeof __APP_VERSION__ !== "undefined" ? __APP_VERSION__ : void 0);
159
+ const commit = commitHash ?? (typeof __COMMIT_HASH__ !== "undefined" ? __COMMIT_HASH__ : void 0);
160
+ const builtAt = formatBuildDate(
161
+ buildDate ?? (typeof __BUILD_DATE__ !== "undefined" ? __BUILD_DATE__ : void 0)
162
+ );
163
+ const buildStamp = [version && `v${version}`, commit, builtAt].filter(Boolean).join(" \xB7 ");
164
+ return /* @__PURE__ */ jsxs2(
102
165
  "div",
103
166
  {
104
167
  className: "fixed bottom-0 left-0 right-0 h-8 bg-zinc-900 border-t border-zinc-800 flex items-center px-4 gap-6 text-[11px] text-zinc-400 z-50 font-mono" + (className ? ` ${className}` : ""),
105
168
  style,
106
169
  "data-slot": "health-footer",
107
170
  children: [
108
- /* @__PURE__ */ jsxs("span", { children: [
171
+ /* @__PURE__ */ jsxs2("span", { children: [
109
172
  "role: ",
110
- /* @__PURE__ */ jsx("span", { className: "text-zinc-200", children: user?.role ?? "\u2013" })
173
+ /* @__PURE__ */ jsx2("span", { className: "text-zinc-200", children: user?.role ?? "\u2013" })
111
174
  ] }),
112
- /* @__PURE__ */ jsxs("span", { children: [
175
+ /* @__PURE__ */ jsxs2("span", { children: [
113
176
  "jwt.eid:",
114
177
  " ",
115
- /* @__PURE__ */ jsx("span", { className: "text-zinc-200", children: user?.enterpriseId ?? "null" })
178
+ /* @__PURE__ */ jsx2("span", { className: "text-zinc-200", children: user?.enterpriseId ?? "null" })
116
179
  ] }),
117
- /* @__PURE__ */ jsxs("span", { children: [
180
+ /* @__PURE__ */ jsxs2("span", { children: [
118
181
  "hierarchy.eid:",
119
182
  " ",
120
- /* @__PURE__ */ jsx("span", { className: "text-zinc-200", children: enterprise?.id ?? "\u2013" })
183
+ /* @__PURE__ */ jsx2("span", { className: "text-zinc-200", children: enterprise?.id ?? "\u2013" })
121
184
  ] }),
122
- /* @__PURE__ */ jsxs("span", { children: [
185
+ /* @__PURE__ */ jsxs2("span", { children: [
123
186
  "enterprise:",
124
187
  " ",
125
- /* @__PURE__ */ jsx("span", { className: "text-zinc-200", children: enterprise?.name ?? "\u2013" })
188
+ /* @__PURE__ */ jsx2("span", { className: "text-zinc-200", children: enterprise?.name ?? "\u2013" })
126
189
  ] }),
127
- /* @__PURE__ */ jsxs("span", { children: [
190
+ /* @__PURE__ */ jsxs2("span", { children: [
128
191
  "user: ",
129
- /* @__PURE__ */ jsx("span", { className: "text-zinc-200", children: user?.openId ?? "\u2013" })
192
+ /* @__PURE__ */ jsx2("span", { className: "text-zinc-200", children: user?.openId ?? "\u2013" })
193
+ ] }),
194
+ buildStamp && /* @__PURE__ */ jsxs2("span", { className: "ml-auto text-zinc-500", title: "Deployed build (version \xB7 commit \xB7 build date UTC)", children: [
195
+ "build: ",
196
+ /* @__PURE__ */ jsx2("span", { className: "text-zinc-300", children: buildStamp })
130
197
  ] })
131
198
  ]
132
199
  }
@@ -135,7 +202,7 @@ function HealthFooter({
135
202
 
136
203
  // src/layout/EnterpriseDebugLabel.tsx
137
204
  import { useEffect as useEffect2, useState as useState2 } from "react";
138
- import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
205
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
139
206
  function EnterpriseDebugLabel({
140
207
  selectionEnterpriseId,
141
208
  cookieEnterpriseName,
@@ -156,7 +223,7 @@ function EnterpriseDebugLabel({
156
223
  const hasSelection = selectionEnterpriseId !== void 0 && selectionEnterpriseId !== null;
157
224
  const mismatch = hasSelection && cookieNum !== null && cookieNum !== selectionEnterpriseId;
158
225
  const noActive = cookieNum === null;
159
- return /* @__PURE__ */ jsxs2(
226
+ return /* @__PURE__ */ jsxs3(
160
227
  "div",
161
228
  {
162
229
  className: cn(
@@ -166,14 +233,14 @@ function EnterpriseDebugLabel({
166
233
  ),
167
234
  title: "TEMP DIAGNOSTIC: enterprise the loaded data is scoped to (cookie) vs. the UI hierarchy selection. Remove once subdomain data issue is fixed.",
168
235
  children: [
169
- /* @__PURE__ */ jsx2("span", { "aria-hidden": true, children: "\u{1F50D}" }),
170
- noActive ? /* @__PURE__ */ jsx2("span", { children: "no active enterprise (cookie unset)" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
171
- /* @__PURE__ */ jsxs2("span", { children: [
236
+ /* @__PURE__ */ jsx3("span", { "aria-hidden": true, children: "\u{1F50D}" }),
237
+ noActive ? /* @__PURE__ */ jsx3("span", { children: "no active enterprise (cookie unset)" }) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
238
+ /* @__PURE__ */ jsxs3("span", { children: [
172
239
  "data ENT #",
173
240
  cookieNum,
174
241
  cookieEnterpriseName ? ` \xB7 ${cookieEnterpriseName}` : ""
175
242
  ] }),
176
- hasSelection && /* @__PURE__ */ jsxs2("span", { children: [
243
+ hasSelection && /* @__PURE__ */ jsxs3("span", { children: [
177
244
  mismatch ? " \u26A0 \u2260 sel #" : " \xB7 sel #",
178
245
  selectionEnterpriseId
179
246
  ] })
@@ -184,7 +251,7 @@ function EnterpriseDebugLabel({
184
251
  }
185
252
 
186
253
  // src/layout/DashboardLayout.tsx
187
- import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
254
+ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
188
255
  var DEFAULT_SERVICE_HUB_URL = "https://portal.oplytics.digital/app";
189
256
  var DEFAULT_USER_SETTINGS_URL = "https://portal.oplytics.digital/account";
190
257
  function UserMenu({
@@ -194,24 +261,24 @@ function UserMenu({
194
261
  enterprise
195
262
  }) {
196
263
  const initials = (user.name || "U").split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2);
197
- return /* @__PURE__ */ jsxs3(DropdownMenu, { children: [
198
- /* @__PURE__ */ jsx3(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs3("button", { className: "flex items-center gap-2 rounded-md px-2 py-1 hover:bg-[#1E2738] transition-colors outline-none focus-visible:ring-1 focus-visible:ring-[#8C34E9]", children: [
199
- /* @__PURE__ */ jsx3(Avatar, { className: "h-7 w-7 border border-[#2A2A3E]", children: /* @__PURE__ */ jsx3(AvatarFallback, { className: "text-[10px] font-medium bg-[#8C34E9]/20 text-[#C084FC]", children: initials }) }),
200
- /* @__PURE__ */ jsx3("span", { className: "hidden md:block text-xs text-[#E2E8F0] truncate max-w-[100px]", children: user.name || "User" })
264
+ return /* @__PURE__ */ jsxs4(DropdownMenu, { children: [
265
+ /* @__PURE__ */ jsx4(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs4("button", { className: "flex items-center gap-2 rounded-md px-2 py-1 hover:bg-[#1E2738] transition-colors outline-none focus-visible:ring-1 focus-visible:ring-[#8C34E9]", children: [
266
+ /* @__PURE__ */ jsx4(Avatar, { className: "h-7 w-7 border border-[#2A2A3E]", children: /* @__PURE__ */ jsx4(AvatarFallback, { className: "text-[10px] font-medium bg-[#8C34E9]/20 text-[#C084FC]", children: initials }) }),
267
+ /* @__PURE__ */ jsx4("span", { className: "hidden md:block text-xs text-[#E2E8F0] truncate max-w-[100px]", children: user.name || "User" })
201
268
  ] }) }),
202
- /* @__PURE__ */ jsxs3(DropdownMenuContent, { align: "end", className: "w-48 bg-[#0D1220] border-[#1E2738]", children: [
203
- /* @__PURE__ */ jsxs3("div", { className: "px-3 py-2 border-b border-[#1E2738]", children: [
204
- /* @__PURE__ */ jsx3("p", { className: "text-xs font-medium text-[#E2E8F0] truncate", children: user.name }),
205
- /* @__PURE__ */ jsx3("p", { className: "text-[10px] text-[#596475] truncate", children: user.role })
269
+ /* @__PURE__ */ jsxs4(DropdownMenuContent, { align: "end", className: "w-48 bg-[#0D1220] border-[#1E2738]", children: [
270
+ /* @__PURE__ */ jsxs4("div", { className: "px-3 py-2 border-b border-[#1E2738]", children: [
271
+ /* @__PURE__ */ jsx4("p", { className: "text-xs font-medium text-[#E2E8F0] truncate", children: user.name }),
272
+ /* @__PURE__ */ jsx4("p", { className: "text-[10px] text-[#596475] truncate", children: user.role })
206
273
  ] }),
207
- /* @__PURE__ */ jsx3("div", { className: "px-2 py-2 border-b border-[#1E2738]", children: /* @__PURE__ */ jsx3(
274
+ /* @__PURE__ */ jsx4("div", { className: "px-2 py-2 border-b border-[#1E2738]", children: /* @__PURE__ */ jsx4(
208
275
  EnterpriseDebugLabel,
209
276
  {
210
277
  selectionEnterpriseId: enterprise?.id ?? null,
211
278
  cookieEnterpriseName: enterprise?.name ?? null
212
279
  }
213
280
  ) }),
214
- /* @__PURE__ */ jsxs3(
281
+ /* @__PURE__ */ jsxs4(
215
282
  DropdownMenuItem,
216
283
  {
217
284
  onClick: () => {
@@ -219,19 +286,19 @@ function UserMenu({
219
286
  },
220
287
  className: "text-xs text-[#E2E8F0] hover:bg-[#1E2738] cursor-pointer focus:bg-[#1E2738]",
221
288
  children: [
222
- /* @__PURE__ */ jsx3(Settings, { className: "h-3.5 w-3.5 mr-2 text-[#8890A0]" }),
289
+ /* @__PURE__ */ jsx4(Settings, { className: "h-3.5 w-3.5 mr-2 text-[#8890A0]" }),
223
290
  "User Settings"
224
291
  ]
225
292
  }
226
293
  ),
227
- /* @__PURE__ */ jsx3(DropdownMenuSeparator, { className: "bg-[#1E2738]" }),
228
- /* @__PURE__ */ jsxs3(
294
+ /* @__PURE__ */ jsx4(DropdownMenuSeparator, { className: "bg-[#1E2738]" }),
295
+ /* @__PURE__ */ jsxs4(
229
296
  DropdownMenuItem,
230
297
  {
231
298
  onClick: () => onLogout?.(),
232
299
  className: "text-xs text-[#EF4444] hover:bg-[#EF4444]/10 cursor-pointer focus:bg-[#EF4444]/10 focus:text-[#EF4444]",
233
300
  children: [
234
- /* @__PURE__ */ jsx3(LogOut, { className: "h-3.5 w-3.5 mr-2" }),
301
+ /* @__PURE__ */ jsx4(LogOut, { className: "h-3.5 w-3.5 mr-2" }),
235
302
  "Sign Out"
236
303
  ]
237
304
  }
@@ -241,9 +308,9 @@ function UserMenu({
241
308
  }
242
309
  function EnterpriseBadge({ enterprise }) {
243
310
  if (!enterprise) return null;
244
- return /* @__PURE__ */ jsxs3("div", { className: "hidden lg:flex items-center gap-1.5 px-2 py-1 rounded-md bg-[#8C34E9]/10 border border-[#8C34E9]/20", children: [
245
- /* @__PURE__ */ jsx3("div", { className: "h-4 w-4 rounded-sm bg-[#8C34E9]/30 flex items-center justify-center", children: /* @__PURE__ */ jsx3("span", { className: "text-[8px] font-bold text-[#C084FC]", children: enterprise.name.charAt(0).toUpperCase() }) }),
246
- /* @__PURE__ */ jsx3("span", { className: "text-[10px] font-medium text-[#C084FC] truncate max-w-[80px]", children: enterprise.code || enterprise.name })
311
+ return /* @__PURE__ */ jsxs4("div", { className: "hidden lg:flex items-center gap-1.5 px-2 py-1 rounded-md bg-[#8C34E9]/10 border border-[#8C34E9]/20", children: [
312
+ /* @__PURE__ */ jsx4("div", { className: "h-4 w-4 rounded-sm bg-[#8C34E9]/30 flex items-center justify-center", children: /* @__PURE__ */ jsx4("span", { className: "text-[8px] font-bold text-[#C084FC]", children: enterprise.name.charAt(0).toUpperCase() }) }),
313
+ /* @__PURE__ */ jsx4("span", { className: "text-[10px] font-medium text-[#C084FC] truncate max-w-[80px]", children: enterprise.code || enterprise.name })
247
314
  ] });
248
315
  }
249
316
  function NavSection({
@@ -254,12 +321,12 @@ function NavSection({
254
321
  onNavigate
255
322
  }) {
256
323
  const label = section.title ?? section.label;
257
- return /* @__PURE__ */ jsxs3(Fragment2, { children: [
258
- label && /* @__PURE__ */ jsx3("div", { className: cn("px-4 py-2", marginTop && "mt-2"), children: !isCollapsed && /* @__PURE__ */ jsx3("span", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wider", children: label }) }),
259
- /* @__PURE__ */ jsx3(SidebarMenu, { className: "px-2 py-1", children: section.items.map((item) => {
324
+ return /* @__PURE__ */ jsxs4(Fragment3, { children: [
325
+ label && /* @__PURE__ */ jsx4("div", { className: cn("px-4 py-2", marginTop && "mt-2"), children: !isCollapsed && /* @__PURE__ */ jsx4("span", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wider", children: label }) }),
326
+ /* @__PURE__ */ jsx4(SidebarMenu, { className: "px-2 py-1", children: section.items.map((item) => {
260
327
  const active = resolveActive(item.path);
261
328
  const Icon = item.icon;
262
- return /* @__PURE__ */ jsx3(SidebarMenuItem, { children: /* @__PURE__ */ jsxs3(
329
+ return /* @__PURE__ */ jsx4(SidebarMenuItem, { children: /* @__PURE__ */ jsxs4(
263
330
  SidebarMenuButton,
264
331
  {
265
332
  isActive: active,
@@ -267,8 +334,8 @@ function NavSection({
267
334
  tooltip: item.label,
268
335
  className: "h-10 transition-all font-normal",
269
336
  children: [
270
- Icon && /* @__PURE__ */ jsx3(Icon, { className: cn("h-4 w-4", active && "text-primary") }),
271
- /* @__PURE__ */ jsx3("span", { children: item.label })
337
+ Icon && /* @__PURE__ */ jsx4(Icon, { className: cn("h-4 w-4", active && "text-primary") }),
338
+ /* @__PURE__ */ jsx4("span", { children: item.label })
272
339
  ]
273
340
  }
274
341
  ) }, item.path);
@@ -285,6 +352,7 @@ function DashboardShell({
285
352
  onNavigate,
286
353
  isActive,
287
354
  serviceHubUrl = DEFAULT_SERVICE_HUB_URL,
355
+ crossServiceLinks,
288
356
  settingsPath,
289
357
  user,
290
358
  onLogout,
@@ -294,31 +362,34 @@ function DashboardShell({
294
362
  reportingToolbar,
295
363
  footer,
296
364
  showHealthFooter,
365
+ buildDate,
366
+ commitHash,
367
+ buildVersion,
297
368
  children
298
369
  }) {
299
370
  const { toggleSidebar, state } = useSidebar();
300
371
  const isCollapsed = state === "collapsed";
301
372
  const navigate = onNavigate;
302
373
  const resolveActive = (path) => isActive ? isActive(path, activePath) : isMenuItemActive(path, activePath);
303
- return /* @__PURE__ */ jsxs3(Fragment2, { children: [
304
- /* @__PURE__ */ jsxs3(Sidebar, { collapsible: "icon", className: "border-r-0", children: [
305
- /* @__PURE__ */ jsx3(SidebarHeader, { className: "h-16 justify-center", children: /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-3 px-2 transition-all w-full", children: [
306
- /* @__PURE__ */ jsx3(
374
+ return /* @__PURE__ */ jsxs4(Fragment3, { children: [
375
+ /* @__PURE__ */ jsxs4(Sidebar, { collapsible: "icon", className: "border-r-0", children: [
376
+ /* @__PURE__ */ jsx4(SidebarHeader, { className: "h-16 justify-center", children: /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-3 px-2 transition-all w-full", children: [
377
+ /* @__PURE__ */ jsx4(
307
378
  "button",
308
379
  {
309
380
  onClick: toggleSidebar,
310
381
  className: "h-8 w-8 flex items-center justify-center hover:bg-accent rounded-lg transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring shrink-0",
311
382
  "aria-label": "Toggle navigation",
312
- children: /* @__PURE__ */ jsx3(PanelLeft, { className: "h-4 w-4 text-muted-foreground" })
383
+ children: /* @__PURE__ */ jsx4(PanelLeft, { className: "h-4 w-4 text-muted-foreground" })
313
384
  }
314
385
  ),
315
- !isCollapsed ? /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 min-w-0", children: [
316
- serviceIcon && /* @__PURE__ */ jsx3("span", { className: "text-[#8C34E9] shrink-0", children: serviceIcon }),
317
- /* @__PURE__ */ jsx3("span", { className: "font-semibold tracking-tight truncate", children: serviceName })
386
+ !isCollapsed ? /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 min-w-0", children: [
387
+ serviceIcon && /* @__PURE__ */ jsx4("span", { className: "text-[#8C34E9] shrink-0", children: serviceIcon }),
388
+ /* @__PURE__ */ jsx4("span", { className: "font-semibold tracking-tight truncate", children: serviceName })
318
389
  ] }) : null
319
390
  ] }) }),
320
- /* @__PURE__ */ jsxs3(SidebarContent, { className: "gap-0", children: [
321
- serviceHubUrl && /* @__PURE__ */ jsx3(SidebarMenu, { className: "px-2 pt-2 pb-1", children: /* @__PURE__ */ jsx3(SidebarMenuItem, { children: /* @__PURE__ */ jsxs3(
391
+ /* @__PURE__ */ jsxs4(SidebarContent, { className: "gap-0", children: [
392
+ serviceHubUrl && /* @__PURE__ */ jsx4(SidebarMenu, { className: "px-2 pt-2 pb-1", children: /* @__PURE__ */ jsx4(SidebarMenuItem, { children: /* @__PURE__ */ jsxs4(
322
393
  SidebarMenuButton,
323
394
  {
324
395
  onClick: () => {
@@ -327,12 +398,13 @@ function DashboardShell({
327
398
  tooltip: "Back to Service Hub",
328
399
  className: "h-10 transition-all font-normal text-muted-foreground hover:text-foreground",
329
400
  children: [
330
- /* @__PURE__ */ jsx3(ArrowLeft, { className: "h-4 w-4" }),
331
- /* @__PURE__ */ jsx3("span", { children: "Service Hub" })
401
+ /* @__PURE__ */ jsx4(ArrowLeft, { className: "h-4 w-4" }),
402
+ /* @__PURE__ */ jsx4("span", { children: "Service Hub" })
332
403
  ]
333
404
  }
334
405
  ) }) }),
335
- menuSections.map((section, i) => /* @__PURE__ */ jsx3(
406
+ /* @__PURE__ */ jsx4(CrossServiceNav, { links: crossServiceLinks ?? [] }),
407
+ menuSections.map((section, i) => /* @__PURE__ */ jsx4(
336
408
  NavSection,
337
409
  {
338
410
  section,
@@ -342,7 +414,7 @@ function DashboardShell({
342
414
  },
343
415
  section.title ?? section.label ?? `section-${i}`
344
416
  )),
345
- isAdmin && adminSections?.map((section, i) => /* @__PURE__ */ jsx3(
417
+ isAdmin && adminSections?.map((section, i) => /* @__PURE__ */ jsx4(
346
418
  NavSection,
347
419
  {
348
420
  section,
@@ -354,21 +426,21 @@ function DashboardShell({
354
426
  section.title ?? section.label ?? `admin-${i}`
355
427
  ))
356
428
  ] }),
357
- settingsPath && /* @__PURE__ */ jsx3(SidebarFooter, { className: "p-2", children: /* @__PURE__ */ jsx3(SidebarMenu, { children: /* @__PURE__ */ jsx3(SidebarMenuItem, { children: /* @__PURE__ */ jsxs3(
429
+ settingsPath && /* @__PURE__ */ jsx4(SidebarFooter, { className: "p-2", children: /* @__PURE__ */ jsx4(SidebarMenu, { children: /* @__PURE__ */ jsx4(SidebarMenuItem, { children: /* @__PURE__ */ jsxs4(
358
430
  SidebarMenuButton,
359
431
  {
360
432
  onClick: () => navigate(settingsPath),
361
433
  tooltip: "Settings",
362
434
  className: "h-10 transition-all font-normal text-muted-foreground hover:text-foreground",
363
435
  children: [
364
- /* @__PURE__ */ jsx3(Settings, { className: "h-4 w-4" }),
365
- /* @__PURE__ */ jsx3("span", { children: "Settings" })
436
+ /* @__PURE__ */ jsx4(Settings, { className: "h-4 w-4" }),
437
+ /* @__PURE__ */ jsx4("span", { children: "Settings" })
366
438
  ]
367
439
  }
368
440
  ) }) }) })
369
441
  ] }),
370
- /* @__PURE__ */ jsxs3(SidebarInset, { children: [
371
- /* @__PURE__ */ jsxs3(
442
+ /* @__PURE__ */ jsxs4(SidebarInset, { children: [
443
+ /* @__PURE__ */ jsxs4(
372
444
  "header",
373
445
  {
374
446
  className: cn(
@@ -378,16 +450,16 @@ function DashboardShell({
378
450
  "sticky top-0 z-40"
379
451
  ),
380
452
  children: [
381
- /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: [
382
- /* @__PURE__ */ jsx3(SidebarTrigger, { className: "h-9 w-9 rounded-lg bg-background shrink-0 md:hidden" }),
383
- serviceIcon && /* @__PURE__ */ jsx3("span", { className: "text-[#8C34E9] shrink-0 hidden sm:block", children: serviceIcon }),
384
- hierarchyNavigator && /* @__PURE__ */ jsx3("div", { className: "min-w-0 overflow-x-auto scrollbar-none", children: hierarchyNavigator })
453
+ /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: [
454
+ /* @__PURE__ */ jsx4(SidebarTrigger, { className: "h-9 w-9 rounded-lg bg-background shrink-0 md:hidden" }),
455
+ serviceIcon && /* @__PURE__ */ jsx4("span", { className: "text-[#8C34E9] shrink-0 hidden sm:block", children: serviceIcon }),
456
+ hierarchyNavigator && /* @__PURE__ */ jsx4("div", { className: "min-w-0 overflow-x-auto scrollbar-none", children: hierarchyNavigator })
385
457
  ] }),
386
- /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 shrink-0", children: [
458
+ /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 shrink-0", children: [
387
459
  reportingToolbar,
388
- /* @__PURE__ */ jsx3(EnterpriseBadge, { enterprise }),
389
- /* @__PURE__ */ jsx3("div", { className: "w-px h-6 bg-[#1E2738] hidden md:block" }),
390
- user && /* @__PURE__ */ jsx3(
460
+ /* @__PURE__ */ jsx4(EnterpriseBadge, { enterprise }),
461
+ /* @__PURE__ */ jsx4("div", { className: "w-px h-6 bg-[#1E2738] hidden md:block" }),
462
+ user && /* @__PURE__ */ jsx4(
391
463
  UserMenu,
392
464
  {
393
465
  user,
@@ -400,21 +472,30 @@ function DashboardShell({
400
472
  ]
401
473
  }
402
474
  ),
403
- /* @__PURE__ */ jsx3("main", { className: "flex-1 p-4 md:p-6 pb-14", children })
475
+ /* @__PURE__ */ jsx4("main", { className: "flex-1 p-4 md:p-6 pb-14", children })
404
476
  ] }),
405
477
  footer,
406
- showHealthFooter && user?.role === "platform_admin" && /* @__PURE__ */ jsx3(HealthFooter, { user, enterprise })
478
+ showHealthFooter && user?.role === "platform_admin" && /* @__PURE__ */ jsx4(
479
+ HealthFooter,
480
+ {
481
+ user,
482
+ enterprise,
483
+ buildDate,
484
+ commitHash,
485
+ buildVersion
486
+ }
487
+ )
407
488
  ] });
408
489
  }
409
490
  function DashboardLayout(props) {
410
491
  const isMobile = useIsMobile();
411
- return /* @__PURE__ */ jsx3(SidebarProvider, { defaultOpen: props.defaultOpen ?? !isMobile, children: /* @__PURE__ */ jsx3(DashboardShell, { ...props }) });
492
+ return /* @__PURE__ */ jsx4(SidebarProvider, { defaultOpen: props.defaultOpen ?? !isMobile, children: /* @__PURE__ */ jsx4(DashboardShell, { ...props }) });
412
493
  }
413
494
 
414
495
  // src/layout/DashboardLayoutSkeleton.tsx
415
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
496
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
416
497
  function Skeleton({ className }) {
417
- return /* @__PURE__ */ jsx4(
498
+ return /* @__PURE__ */ jsx5(
418
499
  "div",
419
500
  {
420
501
  className: cn(
@@ -425,47 +506,47 @@ function Skeleton({ className }) {
425
506
  );
426
507
  }
427
508
  function DashboardLayoutSkeleton({ className }) {
428
- return /* @__PURE__ */ jsxs4("div", { className: cn("flex min-h-screen bg-[#0A0E1A]", className), children: [
429
- /* @__PURE__ */ jsxs4("div", { className: "w-[260px] border-r border-[#1E2738] bg-[#0D1220] p-4 space-y-6", children: [
430
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-3 px-2", children: [
431
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-8 w-8 rounded-md" }),
432
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-4 w-24" })
509
+ return /* @__PURE__ */ jsxs5("div", { className: cn("flex min-h-screen bg-[#0A0E1A]", className), children: [
510
+ /* @__PURE__ */ jsxs5("div", { className: "w-[260px] border-r border-[#1E2738] bg-[#0D1220] p-4 space-y-6", children: [
511
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-3 px-2", children: [
512
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-8 w-8 rounded-md" }),
513
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-4 w-24" })
433
514
  ] }),
434
- /* @__PURE__ */ jsxs4("div", { className: "space-y-2 px-2", children: [
435
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-9 w-full rounded-lg" }),
436
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-9 w-full rounded-lg" }),
437
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-9 w-full rounded-lg" }),
438
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-9 w-full rounded-lg" })
515
+ /* @__PURE__ */ jsxs5("div", { className: "space-y-2 px-2", children: [
516
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-9 w-full rounded-lg" }),
517
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-9 w-full rounded-lg" }),
518
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-9 w-full rounded-lg" }),
519
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-9 w-full rounded-lg" })
439
520
  ] }),
440
- /* @__PURE__ */ jsxs4("div", { className: "px-2", children: [
441
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-3 w-16 mb-3" }),
442
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-9 w-full rounded-lg" }),
443
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-9 w-full rounded-lg mt-2" })
521
+ /* @__PURE__ */ jsxs5("div", { className: "px-2", children: [
522
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-3 w-16 mb-3" }),
523
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-9 w-full rounded-lg" }),
524
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-9 w-full rounded-lg mt-2" })
444
525
  ] }),
445
- /* @__PURE__ */ jsx4("div", { className: "absolute bottom-4 left-4 right-4", children: /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-3 px-1", children: [
446
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-8 w-8 rounded-full" }),
447
- /* @__PURE__ */ jsxs4("div", { className: "flex-1 space-y-2", children: [
448
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-3 w-20" }),
449
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-2 w-32" })
526
+ /* @__PURE__ */ jsx5("div", { className: "absolute bottom-4 left-4 right-4", children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-3 px-1", children: [
527
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-8 w-8 rounded-full" }),
528
+ /* @__PURE__ */ jsxs5("div", { className: "flex-1 space-y-2", children: [
529
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-3 w-20" }),
530
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-2 w-32" })
450
531
  ] })
451
532
  ] }) })
452
533
  ] }),
453
- /* @__PURE__ */ jsxs4("div", { className: "flex-1 p-6 space-y-4", children: [
454
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center justify-between", children: [
455
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-8 w-48 rounded-lg" }),
456
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-9 w-24 rounded-lg" })
534
+ /* @__PURE__ */ jsxs5("div", { className: "flex-1 p-6 space-y-4", children: [
535
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between", children: [
536
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-8 w-48 rounded-lg" }),
537
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-9 w-24 rounded-lg" })
457
538
  ] }),
458
- /* @__PURE__ */ jsxs4("div", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-4", children: [
459
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-24 rounded-xl" }),
460
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-24 rounded-xl" }),
461
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-24 rounded-xl" }),
462
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-24 rounded-xl" })
539
+ /* @__PURE__ */ jsxs5("div", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-4", children: [
540
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-24 rounded-xl" }),
541
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-24 rounded-xl" }),
542
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-24 rounded-xl" }),
543
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-24 rounded-xl" })
463
544
  ] }),
464
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-64 rounded-xl" }),
465
- /* @__PURE__ */ jsxs4("div", { className: "space-y-2", children: [
466
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-10 w-full rounded-lg" }),
467
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-10 w-full rounded-lg" }),
468
- /* @__PURE__ */ jsx4(Skeleton, { className: "h-10 w-full rounded-lg" })
545
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-64 rounded-xl" }),
546
+ /* @__PURE__ */ jsxs5("div", { className: "space-y-2", children: [
547
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-10 w-full rounded-lg" }),
548
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-10 w-full rounded-lg" }),
549
+ /* @__PURE__ */ jsx5(Skeleton, { className: "h-10 w-full rounded-lg" })
469
550
  ] })
470
551
  ] })
471
552
  ] });
@@ -473,7 +554,7 @@ function DashboardLayoutSkeleton({ className }) {
473
554
 
474
555
  // src/layout/SharedPageHeader.tsx
475
556
  import { ChevronLeft } from "lucide-react";
476
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
557
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
477
558
  function SharedPageHeader({
478
559
  title,
479
560
  subtitle,
@@ -486,7 +567,7 @@ function SharedPageHeader({
486
567
  className,
487
568
  children
488
569
  }) {
489
- return /* @__PURE__ */ jsxs5(
570
+ return /* @__PURE__ */ jsxs6(
490
571
  "div",
491
572
  {
492
573
  className: cn(
@@ -496,10 +577,10 @@ function SharedPageHeader({
496
577
  className
497
578
  ),
498
579
  children: [
499
- breadcrumbs && /* @__PURE__ */ jsx5("div", { className: cn("mb-2", compact && "mb-1"), children: breadcrumbs }),
500
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between gap-4", children: [
501
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-3 min-w-0", children: [
502
- onBack && /* @__PURE__ */ jsx5(
580
+ breadcrumbs && /* @__PURE__ */ jsx6("div", { className: cn("mb-2", compact && "mb-1"), children: breadcrumbs }),
581
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between gap-4", children: [
582
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-3 min-w-0", children: [
583
+ onBack && /* @__PURE__ */ jsx6(
503
584
  "button",
504
585
  {
505
586
  onClick: onBack,
@@ -510,12 +591,12 @@ function SharedPageHeader({
510
591
  "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[#8C34E9]"
511
592
  ),
512
593
  "aria-label": "Go back",
513
- children: /* @__PURE__ */ jsx5(ChevronLeft, { className: compact ? "h-4 w-4" : "h-5 w-5" })
594
+ children: /* @__PURE__ */ jsx6(ChevronLeft, { className: compact ? "h-4 w-4" : "h-5 w-5" })
514
595
  }
515
596
  ),
516
- icon && /* @__PURE__ */ jsx5("div", { className: "shrink-0 text-[#8C34E9]", children: icon }),
517
- /* @__PURE__ */ jsxs5("div", { className: "min-w-0", children: [
518
- /* @__PURE__ */ jsx5(
597
+ icon && /* @__PURE__ */ jsx6("div", { className: "shrink-0 text-[#8C34E9]", children: icon }),
598
+ /* @__PURE__ */ jsxs6("div", { className: "min-w-0", children: [
599
+ /* @__PURE__ */ jsx6(
519
600
  "h1",
520
601
  {
521
602
  className: cn(
@@ -526,7 +607,7 @@ function SharedPageHeader({
526
607
  children: title
527
608
  }
528
609
  ),
529
- subtitle && /* @__PURE__ */ jsx5(
610
+ subtitle && /* @__PURE__ */ jsx6(
530
611
  "p",
531
612
  {
532
613
  className: cn(
@@ -539,16 +620,16 @@ function SharedPageHeader({
539
620
  )
540
621
  ] })
541
622
  ] }),
542
- actions && /* @__PURE__ */ jsx5("div", { className: "shrink-0 flex items-center gap-2", children: actions })
623
+ actions && /* @__PURE__ */ jsx6("div", { className: "shrink-0 flex items-center gap-2", children: actions })
543
624
  ] }),
544
- children && /* @__PURE__ */ jsx5("div", { className: cn("mt-3", compact && "mt-2"), children })
625
+ children && /* @__PURE__ */ jsx6("div", { className: cn("mt-3", compact && "mt-2"), children })
545
626
  ]
546
627
  }
547
628
  );
548
629
  }
549
630
 
550
631
  // src/layout/SharedFooter.tsx
551
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
632
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
552
633
  var FOOTER_SERVICES = [
553
634
  { name: "SQDCP", slug: "sqdcp", localRoute: "/services/sqdcp", externalUrl: "https://sqdcp.oplytics.digital" },
554
635
  { name: "OEE Manager", slug: "oee-manager", localRoute: "/services/oee-manager", externalUrl: "https://oee.oplytics.digital" },
@@ -570,7 +651,7 @@ function SharedFooter({
570
651
  year
571
652
  }) {
572
653
  const currentYear = year ?? (/* @__PURE__ */ new Date()).getFullYear();
573
- return /* @__PURE__ */ jsx6(
654
+ return /* @__PURE__ */ jsx7(
574
655
  "footer",
575
656
  {
576
657
  className: cn(
@@ -579,25 +660,25 @@ function SharedFooter({
579
660
  "font-[Space_Grotesk,sans-serif]",
580
661
  className
581
662
  ),
582
- children: /* @__PURE__ */ jsxs6("div", { className: "max-w-7xl mx-auto px-6 py-10", children: [
583
- /* @__PURE__ */ jsxs6("div", { className: "grid grid-cols-1 md:grid-cols-4 gap-8 mb-8", children: [
584
- /* @__PURE__ */ jsxs6("div", { className: "md:col-span-1", children: [
585
- /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 mb-3", children: [
586
- /* @__PURE__ */ jsx6(
663
+ children: /* @__PURE__ */ jsxs7("div", { className: "max-w-7xl mx-auto px-6 py-10", children: [
664
+ /* @__PURE__ */ jsxs7("div", { className: "grid grid-cols-1 md:grid-cols-4 gap-8 mb-8", children: [
665
+ /* @__PURE__ */ jsxs7("div", { className: "md:col-span-1", children: [
666
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2 mb-3", children: [
667
+ /* @__PURE__ */ jsx7(
587
668
  "div",
588
669
  {
589
670
  className: "w-7 h-7 rounded-full flex items-center justify-center",
590
671
  style: { background: "#8C34E9" },
591
- children: /* @__PURE__ */ jsx6("span", { className: "text-white font-bold text-xs", children: "O" })
672
+ children: /* @__PURE__ */ jsx7("span", { className: "text-white font-bold text-xs", children: "O" })
592
673
  }
593
674
  ),
594
- /* @__PURE__ */ jsx6("span", { className: "text-[#E2E8F0] font-semibold text-sm font-[Montserrat,sans-serif]", children: "Oplytics.digital" })
675
+ /* @__PURE__ */ jsx7("span", { className: "text-[#E2E8F0] font-semibold text-sm font-[Montserrat,sans-serif]", children: "Oplytics.digital" })
595
676
  ] }),
596
- /* @__PURE__ */ jsx6("p", { className: "text-xs text-[#596475] leading-relaxed", children: "Operational intelligence platform for manufacturing excellence." })
677
+ /* @__PURE__ */ jsx7("p", { className: "text-xs text-[#596475] leading-relaxed", children: "Operational intelligence platform for manufacturing excellence." })
597
678
  ] }),
598
- /* @__PURE__ */ jsxs6("div", { children: [
599
- /* @__PURE__ */ jsx6("h4", { className: "text-[#E2E8F0] font-medium text-xs uppercase tracking-wider mb-3 font-[Montserrat,sans-serif]", children: "Services" }),
600
- /* @__PURE__ */ jsx6("ul", { className: "space-y-2", children: services.map((service) => /* @__PURE__ */ jsx6("li", { children: /* @__PURE__ */ jsx6(
679
+ /* @__PURE__ */ jsxs7("div", { children: [
680
+ /* @__PURE__ */ jsx7("h4", { className: "text-[#E2E8F0] font-medium text-xs uppercase tracking-wider mb-3 font-[Montserrat,sans-serif]", children: "Services" }),
681
+ /* @__PURE__ */ jsx7("ul", { className: "space-y-2", children: services.map((service) => /* @__PURE__ */ jsx7("li", { children: /* @__PURE__ */ jsx7(
601
682
  "a",
602
683
  {
603
684
  href: useExternalUrls && service.externalUrl ? service.externalUrl : service.localRoute,
@@ -607,10 +688,10 @@ function SharedFooter({
607
688
  }
608
689
  ) }, service.slug)) })
609
690
  ] }),
610
- /* @__PURE__ */ jsxs6("div", { children: [
611
- /* @__PURE__ */ jsx6("h4", { className: "text-[#E2E8F0] font-medium text-xs uppercase tracking-wider mb-3 font-[Montserrat,sans-serif]", children: "Company" }),
612
- /* @__PURE__ */ jsxs6("ul", { className: "space-y-2", children: [
613
- showPricing && /* @__PURE__ */ jsx6("li", { children: /* @__PURE__ */ jsx6(
691
+ /* @__PURE__ */ jsxs7("div", { children: [
692
+ /* @__PURE__ */ jsx7("h4", { className: "text-[#E2E8F0] font-medium text-xs uppercase tracking-wider mb-3 font-[Montserrat,sans-serif]", children: "Company" }),
693
+ /* @__PURE__ */ jsxs7("ul", { className: "space-y-2", children: [
694
+ showPricing && /* @__PURE__ */ jsx7("li", { children: /* @__PURE__ */ jsx7(
614
695
  "a",
615
696
  {
616
697
  href: "/pricing",
@@ -619,7 +700,7 @@ function SharedFooter({
619
700
  children: "Pricing"
620
701
  }
621
702
  ) }),
622
- /* @__PURE__ */ jsx6("li", { children: /* @__PURE__ */ jsx6(
703
+ /* @__PURE__ */ jsx7("li", { children: /* @__PURE__ */ jsx7(
623
704
  "a",
624
705
  {
625
706
  href: "/about",
@@ -627,7 +708,7 @@ function SharedFooter({
627
708
  children: "About"
628
709
  }
629
710
  ) }),
630
- /* @__PURE__ */ jsx6("li", { children: /* @__PURE__ */ jsx6(
711
+ /* @__PURE__ */ jsx7("li", { children: /* @__PURE__ */ jsx7(
631
712
  "a",
632
713
  {
633
714
  href: "/contact",
@@ -637,10 +718,10 @@ function SharedFooter({
637
718
  ) })
638
719
  ] })
639
720
  ] }),
640
- /* @__PURE__ */ jsxs6("div", { children: [
641
- /* @__PURE__ */ jsx6("h4", { className: "text-[#E2E8F0] font-medium text-xs uppercase tracking-wider mb-3 font-[Montserrat,sans-serif]", children: "Legal" }),
642
- /* @__PURE__ */ jsxs6("ul", { className: "space-y-2", children: [
643
- /* @__PURE__ */ jsx6("li", { children: /* @__PURE__ */ jsx6(
721
+ /* @__PURE__ */ jsxs7("div", { children: [
722
+ /* @__PURE__ */ jsx7("h4", { className: "text-[#E2E8F0] font-medium text-xs uppercase tracking-wider mb-3 font-[Montserrat,sans-serif]", children: "Legal" }),
723
+ /* @__PURE__ */ jsxs7("ul", { className: "space-y-2", children: [
724
+ /* @__PURE__ */ jsx7("li", { children: /* @__PURE__ */ jsx7(
644
725
  "a",
645
726
  {
646
727
  href: "/privacy",
@@ -648,7 +729,7 @@ function SharedFooter({
648
729
  children: "Privacy Policy"
649
730
  }
650
731
  ) }),
651
- /* @__PURE__ */ jsx6("li", { children: /* @__PURE__ */ jsx6(
732
+ /* @__PURE__ */ jsx7("li", { children: /* @__PURE__ */ jsx7(
652
733
  "a",
653
734
  {
654
735
  href: "/terms",
@@ -657,7 +738,7 @@ function SharedFooter({
657
738
  }
658
739
  ) })
659
740
  ] }),
660
- showSignIn && /* @__PURE__ */ jsx6("div", { className: "mt-4", children: /* @__PURE__ */ jsx6(
741
+ showSignIn && /* @__PURE__ */ jsx7("div", { className: "mt-4", children: /* @__PURE__ */ jsx7(
661
742
  "a",
662
743
  {
663
744
  href: "/login",
@@ -669,14 +750,14 @@ function SharedFooter({
669
750
  ] })
670
751
  ] }),
671
752
  children,
672
- /* @__PURE__ */ jsxs6("div", { className: "pt-6 border-t border-[#1E2738] flex flex-col sm:flex-row items-center justify-between gap-3", children: [
673
- /* @__PURE__ */ jsxs6("p", { className: "text-xs text-[#596475]", children: [
753
+ /* @__PURE__ */ jsxs7("div", { className: "pt-6 border-t border-[#1E2738] flex flex-col sm:flex-row items-center justify-between gap-3", children: [
754
+ /* @__PURE__ */ jsxs7("p", { className: "text-xs text-[#596475]", children: [
674
755
  "\xA9 ",
675
756
  currentYear,
676
757
  " Oplytics.digital. All rights reserved."
677
758
  ] }),
678
- /* @__PURE__ */ jsx6("p", { className: "text-xs text-[#3E4A5C]", children: "Built for manufacturing excellence" }),
679
- typeof __APP_VERSION__ !== "undefined" && /* @__PURE__ */ jsxs6("p", { className: "text-xs text-[#3E4A5C]", children: [
759
+ /* @__PURE__ */ jsx7("p", { className: "text-xs text-[#3E4A5C]", children: "Built for manufacturing excellence" }),
760
+ typeof __APP_VERSION__ !== "undefined" && /* @__PURE__ */ jsxs7("p", { className: "text-xs text-[#3E4A5C]", children: [
680
761
  "Platform v",
681
762
  __APP_VERSION__
682
763
  ] })
@@ -687,7 +768,17 @@ function SharedFooter({
687
768
  }
688
769
 
689
770
  // src/layout/ServiceFooter.tsx
690
- import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
771
+ import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
772
+ function formatBuildDate2(iso) {
773
+ if (!iso) return void 0;
774
+ const d = new Date(iso);
775
+ if (Number.isNaN(d.getTime())) return void 0;
776
+ const day = d.getUTCDate();
777
+ const month = d.toLocaleString("en-GB", { month: "short", timeZone: "UTC" });
778
+ const hh = String(d.getUTCHours()).padStart(2, "0");
779
+ const mm = String(d.getUTCMinutes()).padStart(2, "0");
780
+ return `${day} ${month} ${hh}:${mm}Z`;
781
+ }
691
782
  var ENV_LABELS = {
692
783
  production: { label: "prod", color: "#10b981" },
693
784
  staging: { label: "stg", color: "#f59e0b" },
@@ -700,13 +791,20 @@ function ServiceFooter({
700
791
  userEmail,
701
792
  environment,
702
793
  buildVersion,
794
+ buildDate,
795
+ commitHash,
703
796
  showHealthMonitor = false,
704
797
  className
705
798
  }) {
706
799
  const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
707
800
  const env = environment ? ENV_LABELS[environment] : null;
708
801
  const version = buildVersion ?? (typeof __APP_VERSION__ !== "undefined" ? __APP_VERSION__ : void 0);
709
- return /* @__PURE__ */ jsxs7(
802
+ const commit = commitHash ?? (typeof __COMMIT_HASH__ !== "undefined" ? __COMMIT_HASH__ : void 0);
803
+ const builtAt = formatBuildDate2(
804
+ buildDate ?? (typeof __BUILD_DATE__ !== "undefined" ? __BUILD_DATE__ : void 0)
805
+ );
806
+ const buildStamp = [version && `v.${version}`, commit, builtAt].filter(Boolean).join(" \xB7 ");
807
+ return /* @__PURE__ */ jsxs8(
710
808
  "footer",
711
809
  {
712
810
  className: cn(
@@ -717,63 +815,57 @@ function ServiceFooter({
717
815
  className
718
816
  ),
719
817
  children: [
720
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2 min-w-0", children: [
721
- /* @__PURE__ */ jsx7(
818
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2 min-w-0", children: [
819
+ /* @__PURE__ */ jsx8(
722
820
  "div",
723
821
  {
724
822
  className: "w-5 h-5 rounded-full flex items-center justify-center shrink-0",
725
823
  style: { background: "#8C34E9" },
726
- children: /* @__PURE__ */ jsx7("span", { className: "text-white font-bold", style: { fontSize: 9 }, children: "O" })
824
+ children: /* @__PURE__ */ jsx8("span", { className: "text-white font-bold", style: { fontSize: 9 }, children: "O" })
727
825
  }
728
826
  ),
729
- /* @__PURE__ */ jsx7("span", { className: "text-[10px] text-[#596475] whitespace-nowrap hidden sm:inline", children: "Operational Excellence. One Digital Platform." })
827
+ /* @__PURE__ */ jsx8("span", { className: "text-[10px] text-[#596475] whitespace-nowrap hidden sm:inline", children: "Operational Excellence. One Digital Platform." })
730
828
  ] }),
731
- showHealthMonitor && /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1.5 text-[10px] text-[#3E4A5C] min-w-0 overflow-hidden", children: [
732
- enterpriseName && /* @__PURE__ */ jsxs7(Fragment3, { children: [
733
- /* @__PURE__ */ jsxs7("span", { className: "whitespace-nowrap", children: [
734
- /* @__PURE__ */ jsx7("span", { className: "text-[#596475]", children: enterpriseName }),
735
- enterpriseId != null && /* @__PURE__ */ jsxs7("span", { className: "text-[#3E4A5C]", children: [
829
+ showHealthMonitor && /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-1.5 text-[10px] text-[#3E4A5C] min-w-0 overflow-hidden", children: [
830
+ enterpriseName && /* @__PURE__ */ jsxs8(Fragment4, { children: [
831
+ /* @__PURE__ */ jsxs8("span", { className: "whitespace-nowrap", children: [
832
+ /* @__PURE__ */ jsx8("span", { className: "text-[#596475]", children: enterpriseName }),
833
+ enterpriseId != null && /* @__PURE__ */ jsxs8("span", { className: "text-[#3E4A5C]", children: [
736
834
  " (",
737
835
  enterpriseId,
738
836
  ")"
739
837
  ] })
740
838
  ] }),
741
- /* @__PURE__ */ jsx7(Separator, {})
839
+ /* @__PURE__ */ jsx8(Separator, {})
742
840
  ] }),
743
- userEmail && /* @__PURE__ */ jsxs7(Fragment3, { children: [
744
- /* @__PURE__ */ jsx7("span", { className: "whitespace-nowrap text-[#596475]", children: userEmail }),
745
- userRole && /* @__PURE__ */ jsxs7("span", { className: "text-[#3E4A5C]", children: [
841
+ userEmail && /* @__PURE__ */ jsxs8(Fragment4, { children: [
842
+ /* @__PURE__ */ jsx8("span", { className: "whitespace-nowrap text-[#596475]", children: userEmail }),
843
+ userRole && /* @__PURE__ */ jsxs8("span", { className: "text-[#3E4A5C]", children: [
746
844
  " (",
747
845
  userRole,
748
846
  ")"
749
847
  ] }),
750
- /* @__PURE__ */ jsx7(Separator, {})
848
+ /* @__PURE__ */ jsx8(Separator, {})
751
849
  ] }),
752
- env && /* @__PURE__ */ jsxs7(Fragment3, { children: [
753
- /* @__PURE__ */ jsxs7("span", { className: "whitespace-nowrap", children: [
850
+ env && /* @__PURE__ */ jsxs8(Fragment4, { children: [
851
+ /* @__PURE__ */ jsxs8("span", { className: "whitespace-nowrap", children: [
754
852
  "ENV:",
755
853
  " ",
756
- /* @__PURE__ */ jsx7("span", { style: { color: env.color }, className: "font-semibold", children: env.label })
854
+ /* @__PURE__ */ jsx8("span", { style: { color: env.color }, className: "font-semibold", children: env.label })
757
855
  ] }),
758
- /* @__PURE__ */ jsx7(Separator, {})
856
+ /* @__PURE__ */ jsx8(Separator, {})
759
857
  ] }),
760
- version && /* @__PURE__ */ jsxs7("span", { className: "whitespace-nowrap text-[#3E4A5C] font-mono", children: [
761
- "v.",
762
- version
763
- ] })
858
+ buildStamp && /* @__PURE__ */ jsx8("span", { className: "whitespace-nowrap text-[#3E4A5C] font-mono", title: "Deployed build", children: buildStamp })
764
859
  ] }),
765
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2 text-[10px] text-[#3E4A5C] whitespace-nowrap shrink-0", children: [
766
- /* @__PURE__ */ jsxs7("span", { children: [
860
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2 text-[10px] text-[#3E4A5C] whitespace-nowrap shrink-0", children: [
861
+ /* @__PURE__ */ jsxs8("span", { children: [
767
862
  "\xA9 ",
768
863
  currentYear,
769
864
  " Oplytics.digital"
770
865
  ] }),
771
- !showHealthMonitor && version && /* @__PURE__ */ jsxs7(Fragment3, { children: [
772
- /* @__PURE__ */ jsx7(Separator, {}),
773
- /* @__PURE__ */ jsxs7("span", { className: "font-mono", children: [
774
- "v.",
775
- version
776
- ] })
866
+ !showHealthMonitor && buildStamp && /* @__PURE__ */ jsxs8(Fragment4, { children: [
867
+ /* @__PURE__ */ jsx8(Separator, {}),
868
+ /* @__PURE__ */ jsx8("span", { className: "font-mono", title: "Deployed build", children: buildStamp })
777
869
  ] })
778
870
  ] })
779
871
  ]
@@ -781,7 +873,7 @@ function ServiceFooter({
781
873
  );
782
874
  }
783
875
  function Separator() {
784
- return /* @__PURE__ */ jsx7("span", { className: "text-[#1E2738] select-none", "aria-hidden": true, children: "|" });
876
+ return /* @__PURE__ */ jsx8("span", { className: "text-[#1E2738] select-none", "aria-hidden": true, children: "|" });
785
877
  }
786
878
 
787
879
  // src/layout/createServiceLayout.tsx
@@ -949,6 +1041,7 @@ export {
949
1041
  getInitials,
950
1042
  isMenuItemActive,
951
1043
  useSidebarResize,
1044
+ CrossServiceNav,
952
1045
  HealthFooter,
953
1046
  EnterpriseDebugLabel,
954
1047
  DashboardLayout,
@@ -965,4 +1058,4 @@ export {
965
1058
  policyDeploymentConfig,
966
1059
  SERVICE_CONFIGS
967
1060
  };
968
- //# sourceMappingURL=chunk-O4Y6TELY.js.map
1061
+ //# sourceMappingURL=chunk-POOTKX4M.js.map