@optifye/dashboard-core 6.12.27 → 6.12.29

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.
@@ -181,7 +181,7 @@ interface WorkspaceMetrics {
181
181
  factory_area_key?: string | null;
182
182
  factory_area_name?: string | null;
183
183
  factory_area_enabled?: boolean | null;
184
- leaderboard_metric_kind?: 'efficiency' | 'recent_flow_shift_average';
184
+ leaderboard_metric_kind?: 'efficiency' | 'cycle_time' | 'recent_flow_shift_average';
185
185
  leaderboard_value?: number | null;
186
186
  avg_recent_flow?: number | null;
187
187
  recent_flow_mode?: 'computed' | 'hold' | 'unavailable';
@@ -270,6 +270,9 @@ interface LineSignal {
270
270
  weight?: number | null;
271
271
  mode?: KpiSignalMode;
272
272
  reason?: string | null;
273
+ aggregate_eligible?: boolean | null;
274
+ aggregate_reason?: string | null;
275
+ aggregate_threshold_percent?: number | null;
273
276
  effective_end_at?: string | null;
274
277
  computed_at?: string | null;
275
278
  }
@@ -279,6 +282,9 @@ interface KpiSignal {
279
282
  weight?: number | null;
280
283
  mode?: KpiSignalMode;
281
284
  reason?: string | null;
285
+ aggregateEligible?: boolean | null;
286
+ aggregateReason?: string | null;
287
+ aggregateThresholdPercent?: number | null;
282
288
  effectiveEndAt?: string | null;
283
289
  computedAt?: string | null;
284
290
  }
@@ -181,7 +181,7 @@ interface WorkspaceMetrics {
181
181
  factory_area_key?: string | null;
182
182
  factory_area_name?: string | null;
183
183
  factory_area_enabled?: boolean | null;
184
- leaderboard_metric_kind?: 'efficiency' | 'recent_flow_shift_average';
184
+ leaderboard_metric_kind?: 'efficiency' | 'cycle_time' | 'recent_flow_shift_average';
185
185
  leaderboard_value?: number | null;
186
186
  avg_recent_flow?: number | null;
187
187
  recent_flow_mode?: 'computed' | 'hold' | 'unavailable';
@@ -270,6 +270,9 @@ interface LineSignal {
270
270
  weight?: number | null;
271
271
  mode?: KpiSignalMode;
272
272
  reason?: string | null;
273
+ aggregate_eligible?: boolean | null;
274
+ aggregate_reason?: string | null;
275
+ aggregate_threshold_percent?: number | null;
273
276
  effective_end_at?: string | null;
274
277
  computed_at?: string | null;
275
278
  }
@@ -279,6 +282,9 @@ interface KpiSignal {
279
282
  weight?: number | null;
280
283
  mode?: KpiSignalMode;
281
284
  reason?: string | null;
285
+ aggregateEligible?: boolean | null;
286
+ aggregateReason?: string | null;
287
+ aggregateThresholdPercent?: number | null;
282
288
  effectiveEndAt?: string | null;
283
289
  computedAt?: string | null;
284
290
  }
@@ -1,2 +1,2 @@
1
- export { z as RecentFlowSnapshotGrid, R as RecentFlowSnapshotGridProps, W as WorkspaceMetrics, e as WorkspaceVideoStream } from './automation-pIVo1XWk.mjs';
1
+ export { z as RecentFlowSnapshotGrid, R as RecentFlowSnapshotGridProps, W as WorkspaceMetrics, e as WorkspaceVideoStream } from './automation-DYa3jNEf.mjs';
2
2
  import 'react';
@@ -1,2 +1,2 @@
1
- export { z as RecentFlowSnapshotGrid, R as RecentFlowSnapshotGridProps, W as WorkspaceMetrics, e as WorkspaceVideoStream } from './automation-pIVo1XWk.js';
1
+ export { z as RecentFlowSnapshotGrid, R as RecentFlowSnapshotGridProps, W as WorkspaceMetrics, e as WorkspaceVideoStream } from './automation-DYa3jNEf.js';
2
2
  import 'react';
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { L as LineSignal, V as VideoGridMetricMode, W as WorkspaceMetrics, a as LineInfo, b as WorkspaceDetailedMetrics, S as SkuBreakdownItem, c as SkuSegmentItem, d as LineSkuBreakdownItem, E as EfficiencyLegendUpdate, D as DashboardKPIs, P as PoorPerformingWorkspace, e as WorkspaceVideoStream, K as KpiTrend, M as MonthlyTrendSummary, f as Workspace, g as WorkspaceCameraIpInfo, h as WorkspaceActionUpdate, A as ActionThreshold, i as ShiftConfiguration, j as KpiSignal, k as LineIssueResolutionSummary } from './automation-pIVo1XWk.mjs';
2
- export { r as CountDelta, C as CurrentWorkspaceSKU, s as DurationDelta, o as KpiSignalMode, n as KpiSignalSource, l as LineDetailedMetrics, m as LineSignalSource, u as LineThreshold, q as PercentageDelta, z as RecentFlowSnapshotGrid, R as RecentFlowSnapshotGridProps, v as ShiftConfigurationRecord, p as ValueDelta, t as WorkspaceCropRect, x as isRecentFlowVideoGridMetricMode, y as isWipGatedVideoGridMetricMode, w as normalizeVideoGridMetricMode } from './automation-pIVo1XWk.mjs';
1
+ import { L as LineSignal, V as VideoGridMetricMode, W as WorkspaceMetrics, a as LineInfo, b as WorkspaceDetailedMetrics, S as SkuBreakdownItem, c as SkuSegmentItem, d as LineSkuBreakdownItem, E as EfficiencyLegendUpdate, D as DashboardKPIs, P as PoorPerformingWorkspace, e as WorkspaceVideoStream, K as KpiTrend, M as MonthlyTrendSummary, f as Workspace, g as WorkspaceCameraIpInfo, h as WorkspaceActionUpdate, A as ActionThreshold, i as ShiftConfiguration, j as KpiSignal, k as LineIssueResolutionSummary } from './automation-DYa3jNEf.mjs';
2
+ export { r as CountDelta, C as CurrentWorkspaceSKU, s as DurationDelta, o as KpiSignalMode, n as KpiSignalSource, l as LineDetailedMetrics, m as LineSignalSource, u as LineThreshold, q as PercentageDelta, z as RecentFlowSnapshotGrid, R as RecentFlowSnapshotGridProps, v as ShiftConfigurationRecord, p as ValueDelta, t as WorkspaceCropRect, x as isRecentFlowVideoGridMetricMode, y as isWipGatedVideoGridMetricMode, w as normalizeVideoGridMetricMode } from './automation-DYa3jNEf.mjs';
3
3
  import * as _supabase_supabase_js from '@supabase/supabase-js';
4
4
  import { SupabaseClient as SupabaseClient$1, Session, User, AuthError } from '@supabase/supabase-js';
5
5
  import { LucideProps, Share2, Download } from 'lucide-react';
@@ -2704,7 +2704,7 @@ interface LeaderboardEntry {
2704
2704
  efficiency: number;
2705
2705
  avg_recent_flow?: number | null;
2706
2706
  leaderboard_value?: number | null;
2707
- leaderboard_metric_kind?: 'efficiency' | 'recent_flow_shift_average';
2707
+ leaderboard_metric_kind?: 'efficiency' | 'cycle_time' | 'recent_flow_shift_average';
2708
2708
  total_output?: number;
2709
2709
  total_day_output?: number;
2710
2710
  avg_pph?: number;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { L as LineSignal, V as VideoGridMetricMode, W as WorkspaceMetrics, a as LineInfo, b as WorkspaceDetailedMetrics, S as SkuBreakdownItem, c as SkuSegmentItem, d as LineSkuBreakdownItem, E as EfficiencyLegendUpdate, D as DashboardKPIs, P as PoorPerformingWorkspace, e as WorkspaceVideoStream, K as KpiTrend, M as MonthlyTrendSummary, f as Workspace, g as WorkspaceCameraIpInfo, h as WorkspaceActionUpdate, A as ActionThreshold, i as ShiftConfiguration, j as KpiSignal, k as LineIssueResolutionSummary } from './automation-pIVo1XWk.js';
2
- export { r as CountDelta, C as CurrentWorkspaceSKU, s as DurationDelta, o as KpiSignalMode, n as KpiSignalSource, l as LineDetailedMetrics, m as LineSignalSource, u as LineThreshold, q as PercentageDelta, z as RecentFlowSnapshotGrid, R as RecentFlowSnapshotGridProps, v as ShiftConfigurationRecord, p as ValueDelta, t as WorkspaceCropRect, x as isRecentFlowVideoGridMetricMode, y as isWipGatedVideoGridMetricMode, w as normalizeVideoGridMetricMode } from './automation-pIVo1XWk.js';
1
+ import { L as LineSignal, V as VideoGridMetricMode, W as WorkspaceMetrics, a as LineInfo, b as WorkspaceDetailedMetrics, S as SkuBreakdownItem, c as SkuSegmentItem, d as LineSkuBreakdownItem, E as EfficiencyLegendUpdate, D as DashboardKPIs, P as PoorPerformingWorkspace, e as WorkspaceVideoStream, K as KpiTrend, M as MonthlyTrendSummary, f as Workspace, g as WorkspaceCameraIpInfo, h as WorkspaceActionUpdate, A as ActionThreshold, i as ShiftConfiguration, j as KpiSignal, k as LineIssueResolutionSummary } from './automation-DYa3jNEf.js';
2
+ export { r as CountDelta, C as CurrentWorkspaceSKU, s as DurationDelta, o as KpiSignalMode, n as KpiSignalSource, l as LineDetailedMetrics, m as LineSignalSource, u as LineThreshold, q as PercentageDelta, z as RecentFlowSnapshotGrid, R as RecentFlowSnapshotGridProps, v as ShiftConfigurationRecord, p as ValueDelta, t as WorkspaceCropRect, x as isRecentFlowVideoGridMetricMode, y as isWipGatedVideoGridMetricMode, w as normalizeVideoGridMetricMode } from './automation-DYa3jNEf.js';
3
3
  import * as _supabase_supabase_js from '@supabase/supabase-js';
4
4
  import { SupabaseClient as SupabaseClient$1, Session, User, AuthError } from '@supabase/supabase-js';
5
5
  import { LucideProps, Share2, Download } from 'lucide-react';
@@ -2704,7 +2704,7 @@ interface LeaderboardEntry {
2704
2704
  efficiency: number;
2705
2705
  avg_recent_flow?: number | null;
2706
2706
  leaderboard_value?: number | null;
2707
- leaderboard_metric_kind?: 'efficiency' | 'recent_flow_shift_average';
2707
+ leaderboard_metric_kind?: 'efficiency' | 'cycle_time' | 'recent_flow_shift_average';
2708
2708
  total_output?: number;
2709
2709
  total_day_output?: number;
2710
2710
  avg_pph?: number;
package/dist/index.js CHANGED
@@ -14320,9 +14320,11 @@ var useLeaderboardMetrics = (date, shiftId, limit = 10, filter2 = "all") => {
14320
14320
  `/api/dashboard/leaderboard?${params.toString()}`
14321
14321
  );
14322
14322
  let entries = (data.entries || []).slice();
14323
- entries.sort(
14324
- (a, b) => (b.leaderboard_value ?? b.efficiency ?? 0) - (a.leaderboard_value ?? a.efficiency ?? 0)
14325
- );
14323
+ entries.sort((a, b) => {
14324
+ const valueA = a.leaderboard_metric_kind === "cycle_time" ? a.leaderboard_value : a.efficiency;
14325
+ const valueB = b.leaderboard_metric_kind === "cycle_time" ? b.leaderboard_value : b.efficiency;
14326
+ return (valueB ?? -1) - (valueA ?? -1);
14327
+ });
14326
14328
  if (filter2 === "top") {
14327
14329
  entries = entries.slice(0, limit);
14328
14330
  } else if (filter2 === "bottom") {
@@ -22094,7 +22096,7 @@ var normalizeLineSignalSource = (source) => source === "recent_flow" ? "recent_f
22094
22096
  var normalizeLineSignal = (lineSignal, fallbackEfficiency, fallbackWeight) => {
22095
22097
  if (lineSignal && typeof lineSignal === "object") {
22096
22098
  const raw = lineSignal;
22097
- return {
22099
+ const normalized = {
22098
22100
  source: normalizeLineSignalSource(raw.source),
22099
22101
  percent: toOptionalNumber(raw.percent),
22100
22102
  weight: toOptionalNumber(raw.weight),
@@ -22103,6 +22105,21 @@ var normalizeLineSignal = (lineSignal, fallbackEfficiency, fallbackWeight) => {
22103
22105
  effectiveEndAt: raw.effective_end_at ?? raw.effectiveEndAt ?? null,
22104
22106
  computedAt: raw.computed_at ?? raw.computedAt ?? null
22105
22107
  };
22108
+ const aggregateEligible = typeof raw.aggregate_eligible === "boolean" ? raw.aggregate_eligible : typeof raw.aggregateEligible === "boolean" ? raw.aggregateEligible : null;
22109
+ if (aggregateEligible !== null) {
22110
+ normalized.aggregateEligible = aggregateEligible;
22111
+ }
22112
+ const aggregateReason = typeof raw.aggregate_reason === "string" ? raw.aggregate_reason : typeof raw.aggregateReason === "string" ? raw.aggregateReason : null;
22113
+ if (aggregateReason !== null) {
22114
+ normalized.aggregateReason = aggregateReason;
22115
+ }
22116
+ const aggregateThresholdPercent = toOptionalNumber(
22117
+ raw.aggregate_threshold_percent ?? raw.aggregateThresholdPercent
22118
+ );
22119
+ if (aggregateThresholdPercent !== null) {
22120
+ normalized.aggregateThresholdPercent = aggregateThresholdPercent;
22121
+ }
22122
+ return normalized;
22106
22123
  }
22107
22124
  const percent2 = toOptionalNumber(fallbackEfficiency);
22108
22125
  if (percent2 === null) return null;
@@ -22130,7 +22147,7 @@ var getKpiSignalLabel = (signal, legend = DEFAULT_EFFICIENCY_LEGEND) => {
22130
22147
  };
22131
22148
  var aggregateLineSignals = (signals) => {
22132
22149
  const numericSignals = signals.filter(
22133
- (signal) => signal !== null && signal !== void 0 && toOptionalNumber(signal.percent) !== null
22150
+ (signal) => signal !== null && signal !== void 0 && signal.aggregateEligible !== false && toOptionalNumber(signal.percent) !== null
22134
22151
  );
22135
22152
  if (numericSignals.length === 0) return null;
22136
22153
  const percent2 = numericSignals.reduce(
@@ -57701,7 +57718,7 @@ var SideNavBar = React144.memo(({
57701
57718
  const role = user?.role_level;
57702
57719
  const roleNavPaths = React144.useMemo(() => getRoleNavPaths(role), [role]);
57703
57720
  const showLiveMonitorLink = roleNavPaths.includes("/live-monitor");
57704
- const rootDashboardSurface = React144.useMemo(() => "monitor", []);
57721
+ const rootDashboardSurface = React144.useMemo(() => role === "owner" || role === "plant_head" || role === "optifye" ? "operations_overview" : "monitor", [role]);
57705
57722
  const getBasePath = React144.useCallback((path) => {
57706
57723
  const firstSegment = path.split("?")[0].split("/").filter(Boolean)[0];
57707
57724
  return firstSegment ? `/${firstSegment}` : "/";
@@ -57752,6 +57769,12 @@ var SideNavBar = React144.memo(({
57752
57769
  dashboard_surface: dashboardSurface
57753
57770
  }
57754
57771
  }), []);
57772
+ const handleHomeClick = React144.useCallback(() => {
57773
+ navigate("/", {
57774
+ trackingEvent: buildDashboardSurfaceTrackingEvent("side_nav", "/", rootDashboardSurface)
57775
+ });
57776
+ onMobileMenuClose?.();
57777
+ }, [navigate, onMobileMenuClose, buildDashboardSurfaceTrackingEvent, rootDashboardSurface]);
57755
57778
  const handleLeaderboardClick = React144.useCallback(() => {
57756
57779
  navigate(`/leaderboard`, {
57757
57780
  trackingEvent: {
@@ -58057,6 +58080,7 @@ var SideNavBar = React144.memo(({
58057
58080
  });
58058
58081
  onMobileMenuClose?.();
58059
58082
  }, [navigate, onMobileMenuClose, buildDashboardSurfaceTrackingEvent, rootDashboardSurface]);
58083
+ const homeButtonClasses = React144.useMemo(() => getButtonClasses("/"), [getButtonClasses]);
58060
58084
  const liveButtonClasses = React144.useMemo(() => getButtonClasses("/live-monitor"), [getButtonClasses]);
58061
58085
  const leaderboardButtonClasses = React144.useMemo(() => getButtonClasses("/leaderboard"), [getButtonClasses]);
58062
58086
  const kpisButtonClasses = React144.useMemo(() => getButtonClasses("/kpis"), [getButtonClasses]);
@@ -58088,6 +58112,21 @@ var SideNavBar = React144.memo(({
58088
58112
  }
58089
58113
  ) }),
58090
58114
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 w-full py-6 px-4 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
58115
+ canAccessPath("/") && /* @__PURE__ */ jsxRuntime.jsxs(
58116
+ "button",
58117
+ {
58118
+ onClick: handleHomeClick,
58119
+ className: homeButtonClasses,
58120
+ "aria-label": "Home",
58121
+ tabIndex: 0,
58122
+ role: "tab",
58123
+ "aria-selected": isPathActive("/"),
58124
+ children: [
58125
+ /* @__PURE__ */ jsxRuntime.jsx(outline.HomeIcon, { className: "w-5 h-5 mb-1" }),
58126
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Home" })
58127
+ ]
58128
+ }
58129
+ ),
58091
58130
  showLiveMonitorLink && canAccessPath("/live-monitor") && /* @__PURE__ */ jsxRuntime.jsxs(
58092
58131
  "button",
58093
58132
  {
@@ -58216,6 +58255,18 @@ var SideNavBar = React144.memo(({
58216
58255
  };
58217
58256
  };
58218
58257
  return /* @__PURE__ */ jsxRuntime.jsxs("nav", { className: "px-5 py-6", children: [
58258
+ canAccessPath("/") && /* @__PURE__ */ jsxRuntime.jsxs(
58259
+ "button",
58260
+ {
58261
+ onClick: handleMobileNavClick(handleHomeClick),
58262
+ className: getMobileButtonClass("/"),
58263
+ "aria-label": "Home",
58264
+ children: [
58265
+ /* @__PURE__ */ jsxRuntime.jsx(outline.HomeIcon, { className: getIconClass("/") }),
58266
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-medium", children: "Home" })
58267
+ ]
58268
+ }
58269
+ ),
58219
58270
  showLiveMonitorLink && canAccessPath("/live-monitor") && /* @__PURE__ */ jsxRuntime.jsxs(
58220
58271
  "button",
58221
58272
  {
@@ -64801,7 +64852,6 @@ var EMPTY_LINE_IDS = [];
64801
64852
  var EMPTY_WORKSPACES = [];
64802
64853
  var ALL_GREEN_CELEBRATION_DURATION_MS = 6e3;
64803
64854
  var ALL_GREEN_MILESTONE_DURATION_MS = 6e3;
64804
- var ALL_GREEN_STREAK_LOCAL_SECOND_CAP = 59;
64805
64855
  var formatAllGreenCelebrationTimer = (elapsedSeconds) => {
64806
64856
  const safeElapsedSeconds = Math.max(1, Math.floor(elapsedSeconds));
64807
64857
  const minutes = Math.floor(safeElapsedSeconds / 60);
@@ -64809,10 +64859,7 @@ var formatAllGreenCelebrationTimer = (elapsedSeconds) => {
64809
64859
  return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}s`;
64810
64860
  };
64811
64861
  var getAllGreenBackendVisibleSeconds = (confirmedSeconds, tickOriginAtMs, nowMs2) => {
64812
- const localSecondOffset = Math.min(
64813
- ALL_GREEN_STREAK_LOCAL_SECOND_CAP,
64814
- Math.max(0, Math.floor((nowMs2 - tickOriginAtMs) / 1e3))
64815
- );
64862
+ const localSecondOffset = Math.max(0, Math.floor((nowMs2 - tickOriginAtMs) / 1e3));
64816
64863
  return confirmedSeconds + localSecondOffset;
64817
64864
  };
64818
64865
  var LoadingPageCmp = LoadingPage_default;
@@ -65272,38 +65319,25 @@ function HomeView({
65272
65319
  allGreenStreakDisplay.tickOriginAtMs,
65273
65320
  currentAllGreenStreakNowMs
65274
65321
  );
65275
- const backendMaxVisibleSeconds = confirmedSeconds + ALL_GREEN_STREAK_LOCAL_SECOND_CAP;
65276
65322
  const currentBaseline = allGreenStreakTimerBaselineRef.current;
65277
65323
  if (!currentBaseline || currentBaseline.identity !== allGreenMilestoneIdentity) {
65278
65324
  allGreenStreakTimerBaselineRef.current = {
65279
65325
  identity: allGreenMilestoneIdentity,
65280
65326
  baseSeconds: backendVisibleSeconds,
65281
- baseReceivedAtMs: currentAllGreenStreakNowMs,
65282
- maxVisibleSeconds: backendMaxVisibleSeconds
65327
+ baseReceivedAtMs: currentAllGreenStreakNowMs
65283
65328
  };
65284
65329
  } else {
65285
- currentBaseline.maxVisibleSeconds = Math.max(
65286
- currentBaseline.maxVisibleSeconds,
65287
- backendMaxVisibleSeconds
65288
- );
65289
- const visibleSeconds = Math.min(
65290
- currentBaseline.maxVisibleSeconds,
65291
- currentBaseline.baseSeconds + Math.max(0, Math.floor((currentAllGreenStreakNowMs - currentBaseline.baseReceivedAtMs) / 1e3))
65292
- );
65330
+ const visibleSeconds = currentBaseline.baseSeconds + Math.max(0, Math.floor((currentAllGreenStreakNowMs - currentBaseline.baseReceivedAtMs) / 1e3));
65293
65331
  if (backendVisibleSeconds > visibleSeconds) {
65294
65332
  allGreenStreakTimerBaselineRef.current = {
65295
65333
  identity: allGreenMilestoneIdentity,
65296
65334
  baseSeconds: backendVisibleSeconds,
65297
- baseReceivedAtMs: currentAllGreenStreakNowMs,
65298
- maxVisibleSeconds: currentBaseline.maxVisibleSeconds
65335
+ baseReceivedAtMs: currentAllGreenStreakNowMs
65299
65336
  };
65300
65337
  }
65301
65338
  }
65302
65339
  const baseline = allGreenStreakTimerBaselineRef.current;
65303
- const elapsedSeconds = baseline ? Math.min(
65304
- baseline.maxVisibleSeconds,
65305
- baseline.baseSeconds + Math.max(0, Math.floor((currentAllGreenStreakNowMs - baseline.baseReceivedAtMs) / 1e3))
65306
- ) : backendVisibleSeconds;
65340
+ const elapsedSeconds = baseline ? baseline.baseSeconds + Math.max(0, Math.floor((currentAllGreenStreakNowMs - baseline.baseReceivedAtMs) / 1e3)) : backendVisibleSeconds;
65307
65341
  return {
65308
65342
  ...allGreenStreakDisplay,
65309
65343
  elapsedSeconds,
@@ -70517,12 +70551,16 @@ var KPIsOverviewView = ({
70517
70551
  () => new Set(resolvedAssignedLineIds),
70518
70552
  [resolvedAssignedLineIds]
70519
70553
  );
70554
+ const loadedLineIds = React144__namespace.default.useMemo(
70555
+ () => lines.map((line) => line.id).filter(Boolean),
70556
+ [lines]
70557
+ );
70520
70558
  const metricsLineIds = React144__namespace.default.useMemo(() => {
70521
70559
  if (isSuperAdmin) {
70522
- return lineIds ?? [];
70560
+ return loadedLineIds.length > 0 ? loadedLineIds : lineIds ?? [];
70523
70561
  }
70524
70562
  return resolvedAssignedLineIds;
70525
- }, [isSuperAdmin, lineIds, resolvedAssignedLineIds]);
70563
+ }, [isSuperAdmin, loadedLineIds, lineIds, resolvedAssignedLineIds]);
70526
70564
  const assignedLineIdsForLeaderboard = isSuperAdmin ? void 0 : resolvedAssignedLineIds;
70527
70565
  const leaderboardLinesForView = React144__namespace.default.useMemo(() => {
70528
70566
  const targetMode = viewType === "machine" ? "uptime" : "output";
@@ -71576,16 +71614,16 @@ var AnimatedEfficiency = React144.memo(({ value }) => {
71576
71614
  });
71577
71615
  AnimatedEfficiency.displayName = "AnimatedEfficiency";
71578
71616
  var getWorkspaceLeaderboardMetricValue = (workspace) => {
71579
- if (workspace.leaderboard_metric_kind === "recent_flow_shift_average") {
71617
+ if (workspace.leaderboard_metric_kind === "cycle_time") {
71580
71618
  const cycleRatio = getCycleRatio(workspace);
71581
- return cycleRatio === null ? null : cycleRatio * 100;
71619
+ return toFiniteNumber(workspace.leaderboard_value) ?? (cycleRatio === null ? null : cycleRatio * 100);
71582
71620
  }
71583
- return toFiniteNumber(workspace.leaderboard_value) ?? toFiniteNumber(workspace.efficiency);
71621
+ return toFiniteNumber(workspace.efficiency);
71584
71622
  };
71585
71623
  var getWorkspaceDisplayedMetricValue = (workspace) => getWorkspaceLeaderboardMetricValue(workspace);
71586
- var getWorkspaceLeaderboardMetricLabel = (workspace, defaultLabel) => workspace.leaderboard_metric_kind === "recent_flow_shift_average" ? "Actual CT / Standard CT" : defaultLabel;
71624
+ var getWorkspaceLeaderboardMetricLabel = (workspace, defaultLabel) => workspace.leaderboard_metric_kind === "cycle_time" ? "Actual CT / Standard CT" : defaultLabel;
71587
71625
  var renderWorkspaceLeaderboardMetric = (workspace) => {
71588
- if (workspace.leaderboard_metric_kind === "recent_flow_shift_average") {
71626
+ if (workspace.leaderboard_metric_kind === "cycle_time") {
71589
71627
  const actualCT = formatCycleTimeValue(workspace.avg_cycle_time);
71590
71628
  const standardCT = formatCycleTimeValue(workspace.ideal_cycle_time);
71591
71629
  return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "tabular-nums", children: [
@@ -72554,13 +72592,13 @@ var LeaderboardDetailView = React144.memo(({
72554
72592
  error.message
72555
72593
  ] }) });
72556
72594
  }
72557
- const hasRecentFlowLeaderboardRows = sortedWorkspaces.some(
72558
- (workspace) => workspace.leaderboard_metric_kind === "recent_flow_shift_average"
72595
+ const hasCycleTimeLeaderboardRows = sortedWorkspaces.some(
72596
+ (workspace) => workspace.leaderboard_metric_kind === "cycle_time"
72559
72597
  );
72560
72598
  const hasEfficiencyLeaderboardRows = sortedWorkspaces.some(
72561
- (workspace) => workspace.leaderboard_metric_kind !== "recent_flow_shift_average"
72599
+ (workspace) => workspace.leaderboard_metric_kind !== "cycle_time"
72562
72600
  );
72563
- const metricLabel = viewType === "machine" ? "Utilization" : hasRecentFlowLeaderboardRows && !hasEfficiencyLeaderboardRows ? "Actual CT / Standard CT" : hasRecentFlowLeaderboardRows && hasEfficiencyLeaderboardRows ? "Performance" : "Efficiency";
72601
+ const metricLabel = viewType === "machine" ? "Utilization" : hasCycleTimeLeaderboardRows && !hasEfficiencyLeaderboardRows ? "Actual CT / Standard CT" : hasCycleTimeLeaderboardRows && hasEfficiencyLeaderboardRows ? "Performance" : "Efficiency";
72564
72602
  const descendingSortLabel = "Highest to Lowest";
72565
72603
  const ascendingSortLabel = "Lowest to Highest";
72566
72604
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `min-h-screen bg-slate-50 flex flex-col ${className}`, style: { willChange: "contents" }, children: [
package/dist/index.mjs CHANGED
@@ -16,7 +16,7 @@ import { BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, ReferenceLine, Too
16
16
  import { Slot } from '@radix-ui/react-slot';
17
17
  import * as SelectPrimitive from '@radix-ui/react-select';
18
18
  import { DayPicker, useNavigation as useNavigation$1 } from 'react-day-picker';
19
- import { AdjustmentsHorizontalIcon, ClockIcon, UsersIcon, UserCircleIcon, TicketIcon, CurrencyDollarIcon, QuestionMarkCircleIcon, XMarkIcon, ArrowRightIcon, Bars3Icon, VideoCameraIcon, TrophyIcon, ChartBarIcon, LightBulbIcon, CubeIcon, HeartIcon, Cog6ToothIcon, ChevronRightIcon, ArrowRightStartOnRectangleIcon, ExclamationCircleIcon, ExclamationTriangleIcon, CalendarIcon, ChevronDownIcon, ChevronLeftIcon, EnvelopeIcon, DocumentTextIcon, ChevronUpIcon, ArrowDownTrayIcon, CheckCircleIcon, ChatBubbleLeftRightIcon, XCircleIcon, FunnelIcon, EyeIcon, InformationCircleIcon, ArrowLeftIcon, PlayCircleIcon } from '@heroicons/react/24/outline';
19
+ import { AdjustmentsHorizontalIcon, ClockIcon, UsersIcon, UserCircleIcon, TicketIcon, CurrencyDollarIcon, QuestionMarkCircleIcon, XMarkIcon, ArrowRightIcon, Bars3Icon, HomeIcon, VideoCameraIcon, TrophyIcon, ChartBarIcon, LightBulbIcon, CubeIcon, HeartIcon, Cog6ToothIcon, ChevronRightIcon, ArrowRightStartOnRectangleIcon, ExclamationCircleIcon, ExclamationTriangleIcon, CalendarIcon, ChevronDownIcon, ChevronLeftIcon, EnvelopeIcon, DocumentTextIcon, ChevronUpIcon, ArrowDownTrayIcon, CheckCircleIcon, ChatBubbleLeftRightIcon, XCircleIcon, FunnelIcon, EyeIcon, InformationCircleIcon, ArrowLeftIcon, PlayCircleIcon } from '@heroicons/react/24/outline';
20
20
  import { CheckIcon } from '@heroicons/react/24/solid';
21
21
  import html2canvas from 'html2canvas';
22
22
  import jsPDF, { jsPDF as jsPDF$1 } from 'jspdf';
@@ -14291,9 +14291,11 @@ var useLeaderboardMetrics = (date, shiftId, limit = 10, filter2 = "all") => {
14291
14291
  `/api/dashboard/leaderboard?${params.toString()}`
14292
14292
  );
14293
14293
  let entries = (data.entries || []).slice();
14294
- entries.sort(
14295
- (a, b) => (b.leaderboard_value ?? b.efficiency ?? 0) - (a.leaderboard_value ?? a.efficiency ?? 0)
14296
- );
14294
+ entries.sort((a, b) => {
14295
+ const valueA = a.leaderboard_metric_kind === "cycle_time" ? a.leaderboard_value : a.efficiency;
14296
+ const valueB = b.leaderboard_metric_kind === "cycle_time" ? b.leaderboard_value : b.efficiency;
14297
+ return (valueB ?? -1) - (valueA ?? -1);
14298
+ });
14297
14299
  if (filter2 === "top") {
14298
14300
  entries = entries.slice(0, limit);
14299
14301
  } else if (filter2 === "bottom") {
@@ -22065,7 +22067,7 @@ var normalizeLineSignalSource = (source) => source === "recent_flow" ? "recent_f
22065
22067
  var normalizeLineSignal = (lineSignal, fallbackEfficiency, fallbackWeight) => {
22066
22068
  if (lineSignal && typeof lineSignal === "object") {
22067
22069
  const raw = lineSignal;
22068
- return {
22070
+ const normalized = {
22069
22071
  source: normalizeLineSignalSource(raw.source),
22070
22072
  percent: toOptionalNumber(raw.percent),
22071
22073
  weight: toOptionalNumber(raw.weight),
@@ -22074,6 +22076,21 @@ var normalizeLineSignal = (lineSignal, fallbackEfficiency, fallbackWeight) => {
22074
22076
  effectiveEndAt: raw.effective_end_at ?? raw.effectiveEndAt ?? null,
22075
22077
  computedAt: raw.computed_at ?? raw.computedAt ?? null
22076
22078
  };
22079
+ const aggregateEligible = typeof raw.aggregate_eligible === "boolean" ? raw.aggregate_eligible : typeof raw.aggregateEligible === "boolean" ? raw.aggregateEligible : null;
22080
+ if (aggregateEligible !== null) {
22081
+ normalized.aggregateEligible = aggregateEligible;
22082
+ }
22083
+ const aggregateReason = typeof raw.aggregate_reason === "string" ? raw.aggregate_reason : typeof raw.aggregateReason === "string" ? raw.aggregateReason : null;
22084
+ if (aggregateReason !== null) {
22085
+ normalized.aggregateReason = aggregateReason;
22086
+ }
22087
+ const aggregateThresholdPercent = toOptionalNumber(
22088
+ raw.aggregate_threshold_percent ?? raw.aggregateThresholdPercent
22089
+ );
22090
+ if (aggregateThresholdPercent !== null) {
22091
+ normalized.aggregateThresholdPercent = aggregateThresholdPercent;
22092
+ }
22093
+ return normalized;
22077
22094
  }
22078
22095
  const percent2 = toOptionalNumber(fallbackEfficiency);
22079
22096
  if (percent2 === null) return null;
@@ -22101,7 +22118,7 @@ var getKpiSignalLabel = (signal, legend = DEFAULT_EFFICIENCY_LEGEND) => {
22101
22118
  };
22102
22119
  var aggregateLineSignals = (signals) => {
22103
22120
  const numericSignals = signals.filter(
22104
- (signal) => signal !== null && signal !== void 0 && toOptionalNumber(signal.percent) !== null
22121
+ (signal) => signal !== null && signal !== void 0 && signal.aggregateEligible !== false && toOptionalNumber(signal.percent) !== null
22105
22122
  );
22106
22123
  if (numericSignals.length === 0) return null;
22107
22124
  const percent2 = numericSignals.reduce(
@@ -57672,7 +57689,7 @@ var SideNavBar = memo$1(({
57672
57689
  const role = user?.role_level;
57673
57690
  const roleNavPaths = useMemo(() => getRoleNavPaths(role), [role]);
57674
57691
  const showLiveMonitorLink = roleNavPaths.includes("/live-monitor");
57675
- const rootDashboardSurface = useMemo(() => "monitor", []);
57692
+ const rootDashboardSurface = useMemo(() => role === "owner" || role === "plant_head" || role === "optifye" ? "operations_overview" : "monitor", [role]);
57676
57693
  const getBasePath = useCallback((path) => {
57677
57694
  const firstSegment = path.split("?")[0].split("/").filter(Boolean)[0];
57678
57695
  return firstSegment ? `/${firstSegment}` : "/";
@@ -57723,6 +57740,12 @@ var SideNavBar = memo$1(({
57723
57740
  dashboard_surface: dashboardSurface
57724
57741
  }
57725
57742
  }), []);
57743
+ const handleHomeClick = useCallback(() => {
57744
+ navigate("/", {
57745
+ trackingEvent: buildDashboardSurfaceTrackingEvent("side_nav", "/", rootDashboardSurface)
57746
+ });
57747
+ onMobileMenuClose?.();
57748
+ }, [navigate, onMobileMenuClose, buildDashboardSurfaceTrackingEvent, rootDashboardSurface]);
57726
57749
  const handleLeaderboardClick = useCallback(() => {
57727
57750
  navigate(`/leaderboard`, {
57728
57751
  trackingEvent: {
@@ -58028,6 +58051,7 @@ var SideNavBar = memo$1(({
58028
58051
  });
58029
58052
  onMobileMenuClose?.();
58030
58053
  }, [navigate, onMobileMenuClose, buildDashboardSurfaceTrackingEvent, rootDashboardSurface]);
58054
+ const homeButtonClasses = useMemo(() => getButtonClasses("/"), [getButtonClasses]);
58031
58055
  const liveButtonClasses = useMemo(() => getButtonClasses("/live-monitor"), [getButtonClasses]);
58032
58056
  const leaderboardButtonClasses = useMemo(() => getButtonClasses("/leaderboard"), [getButtonClasses]);
58033
58057
  const kpisButtonClasses = useMemo(() => getButtonClasses("/kpis"), [getButtonClasses]);
@@ -58059,6 +58083,21 @@ var SideNavBar = memo$1(({
58059
58083
  }
58060
58084
  ) }),
58061
58085
  /* @__PURE__ */ jsx("div", { className: "flex-1 w-full py-6 px-4 overflow-y-auto", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
58086
+ canAccessPath("/") && /* @__PURE__ */ jsxs(
58087
+ "button",
58088
+ {
58089
+ onClick: handleHomeClick,
58090
+ className: homeButtonClasses,
58091
+ "aria-label": "Home",
58092
+ tabIndex: 0,
58093
+ role: "tab",
58094
+ "aria-selected": isPathActive("/"),
58095
+ children: [
58096
+ /* @__PURE__ */ jsx(HomeIcon, { className: "w-5 h-5 mb-1" }),
58097
+ /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Home" })
58098
+ ]
58099
+ }
58100
+ ),
58062
58101
  showLiveMonitorLink && canAccessPath("/live-monitor") && /* @__PURE__ */ jsxs(
58063
58102
  "button",
58064
58103
  {
@@ -58187,6 +58226,18 @@ var SideNavBar = memo$1(({
58187
58226
  };
58188
58227
  };
58189
58228
  return /* @__PURE__ */ jsxs("nav", { className: "px-5 py-6", children: [
58229
+ canAccessPath("/") && /* @__PURE__ */ jsxs(
58230
+ "button",
58231
+ {
58232
+ onClick: handleMobileNavClick(handleHomeClick),
58233
+ className: getMobileButtonClass("/"),
58234
+ "aria-label": "Home",
58235
+ children: [
58236
+ /* @__PURE__ */ jsx(HomeIcon, { className: getIconClass("/") }),
58237
+ /* @__PURE__ */ jsx("span", { className: "text-base font-medium", children: "Home" })
58238
+ ]
58239
+ }
58240
+ ),
58190
58241
  showLiveMonitorLink && canAccessPath("/live-monitor") && /* @__PURE__ */ jsxs(
58191
58242
  "button",
58192
58243
  {
@@ -64772,7 +64823,6 @@ var EMPTY_LINE_IDS = [];
64772
64823
  var EMPTY_WORKSPACES = [];
64773
64824
  var ALL_GREEN_CELEBRATION_DURATION_MS = 6e3;
64774
64825
  var ALL_GREEN_MILESTONE_DURATION_MS = 6e3;
64775
- var ALL_GREEN_STREAK_LOCAL_SECOND_CAP = 59;
64776
64826
  var formatAllGreenCelebrationTimer = (elapsedSeconds) => {
64777
64827
  const safeElapsedSeconds = Math.max(1, Math.floor(elapsedSeconds));
64778
64828
  const minutes = Math.floor(safeElapsedSeconds / 60);
@@ -64780,10 +64830,7 @@ var formatAllGreenCelebrationTimer = (elapsedSeconds) => {
64780
64830
  return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}s`;
64781
64831
  };
64782
64832
  var getAllGreenBackendVisibleSeconds = (confirmedSeconds, tickOriginAtMs, nowMs2) => {
64783
- const localSecondOffset = Math.min(
64784
- ALL_GREEN_STREAK_LOCAL_SECOND_CAP,
64785
- Math.max(0, Math.floor((nowMs2 - tickOriginAtMs) / 1e3))
64786
- );
64833
+ const localSecondOffset = Math.max(0, Math.floor((nowMs2 - tickOriginAtMs) / 1e3));
64787
64834
  return confirmedSeconds + localSecondOffset;
64788
64835
  };
64789
64836
  var LoadingPageCmp = LoadingPage_default;
@@ -65243,38 +65290,25 @@ function HomeView({
65243
65290
  allGreenStreakDisplay.tickOriginAtMs,
65244
65291
  currentAllGreenStreakNowMs
65245
65292
  );
65246
- const backendMaxVisibleSeconds = confirmedSeconds + ALL_GREEN_STREAK_LOCAL_SECOND_CAP;
65247
65293
  const currentBaseline = allGreenStreakTimerBaselineRef.current;
65248
65294
  if (!currentBaseline || currentBaseline.identity !== allGreenMilestoneIdentity) {
65249
65295
  allGreenStreakTimerBaselineRef.current = {
65250
65296
  identity: allGreenMilestoneIdentity,
65251
65297
  baseSeconds: backendVisibleSeconds,
65252
- baseReceivedAtMs: currentAllGreenStreakNowMs,
65253
- maxVisibleSeconds: backendMaxVisibleSeconds
65298
+ baseReceivedAtMs: currentAllGreenStreakNowMs
65254
65299
  };
65255
65300
  } else {
65256
- currentBaseline.maxVisibleSeconds = Math.max(
65257
- currentBaseline.maxVisibleSeconds,
65258
- backendMaxVisibleSeconds
65259
- );
65260
- const visibleSeconds = Math.min(
65261
- currentBaseline.maxVisibleSeconds,
65262
- currentBaseline.baseSeconds + Math.max(0, Math.floor((currentAllGreenStreakNowMs - currentBaseline.baseReceivedAtMs) / 1e3))
65263
- );
65301
+ const visibleSeconds = currentBaseline.baseSeconds + Math.max(0, Math.floor((currentAllGreenStreakNowMs - currentBaseline.baseReceivedAtMs) / 1e3));
65264
65302
  if (backendVisibleSeconds > visibleSeconds) {
65265
65303
  allGreenStreakTimerBaselineRef.current = {
65266
65304
  identity: allGreenMilestoneIdentity,
65267
65305
  baseSeconds: backendVisibleSeconds,
65268
- baseReceivedAtMs: currentAllGreenStreakNowMs,
65269
- maxVisibleSeconds: currentBaseline.maxVisibleSeconds
65306
+ baseReceivedAtMs: currentAllGreenStreakNowMs
65270
65307
  };
65271
65308
  }
65272
65309
  }
65273
65310
  const baseline = allGreenStreakTimerBaselineRef.current;
65274
- const elapsedSeconds = baseline ? Math.min(
65275
- baseline.maxVisibleSeconds,
65276
- baseline.baseSeconds + Math.max(0, Math.floor((currentAllGreenStreakNowMs - baseline.baseReceivedAtMs) / 1e3))
65277
- ) : backendVisibleSeconds;
65311
+ const elapsedSeconds = baseline ? baseline.baseSeconds + Math.max(0, Math.floor((currentAllGreenStreakNowMs - baseline.baseReceivedAtMs) / 1e3)) : backendVisibleSeconds;
65278
65312
  return {
65279
65313
  ...allGreenStreakDisplay,
65280
65314
  elapsedSeconds,
@@ -70488,12 +70522,16 @@ var KPIsOverviewView = ({
70488
70522
  () => new Set(resolvedAssignedLineIds),
70489
70523
  [resolvedAssignedLineIds]
70490
70524
  );
70525
+ const loadedLineIds = React144__default.useMemo(
70526
+ () => lines.map((line) => line.id).filter(Boolean),
70527
+ [lines]
70528
+ );
70491
70529
  const metricsLineIds = React144__default.useMemo(() => {
70492
70530
  if (isSuperAdmin) {
70493
- return lineIds ?? [];
70531
+ return loadedLineIds.length > 0 ? loadedLineIds : lineIds ?? [];
70494
70532
  }
70495
70533
  return resolvedAssignedLineIds;
70496
- }, [isSuperAdmin, lineIds, resolvedAssignedLineIds]);
70534
+ }, [isSuperAdmin, loadedLineIds, lineIds, resolvedAssignedLineIds]);
70497
70535
  const assignedLineIdsForLeaderboard = isSuperAdmin ? void 0 : resolvedAssignedLineIds;
70498
70536
  const leaderboardLinesForView = React144__default.useMemo(() => {
70499
70537
  const targetMode = viewType === "machine" ? "uptime" : "output";
@@ -71547,16 +71585,16 @@ var AnimatedEfficiency = memo$1(({ value }) => {
71547
71585
  });
71548
71586
  AnimatedEfficiency.displayName = "AnimatedEfficiency";
71549
71587
  var getWorkspaceLeaderboardMetricValue = (workspace) => {
71550
- if (workspace.leaderboard_metric_kind === "recent_flow_shift_average") {
71588
+ if (workspace.leaderboard_metric_kind === "cycle_time") {
71551
71589
  const cycleRatio = getCycleRatio(workspace);
71552
- return cycleRatio === null ? null : cycleRatio * 100;
71590
+ return toFiniteNumber(workspace.leaderboard_value) ?? (cycleRatio === null ? null : cycleRatio * 100);
71553
71591
  }
71554
- return toFiniteNumber(workspace.leaderboard_value) ?? toFiniteNumber(workspace.efficiency);
71592
+ return toFiniteNumber(workspace.efficiency);
71555
71593
  };
71556
71594
  var getWorkspaceDisplayedMetricValue = (workspace) => getWorkspaceLeaderboardMetricValue(workspace);
71557
- var getWorkspaceLeaderboardMetricLabel = (workspace, defaultLabel) => workspace.leaderboard_metric_kind === "recent_flow_shift_average" ? "Actual CT / Standard CT" : defaultLabel;
71595
+ var getWorkspaceLeaderboardMetricLabel = (workspace, defaultLabel) => workspace.leaderboard_metric_kind === "cycle_time" ? "Actual CT / Standard CT" : defaultLabel;
71558
71596
  var renderWorkspaceLeaderboardMetric = (workspace) => {
71559
- if (workspace.leaderboard_metric_kind === "recent_flow_shift_average") {
71597
+ if (workspace.leaderboard_metric_kind === "cycle_time") {
71560
71598
  const actualCT = formatCycleTimeValue(workspace.avg_cycle_time);
71561
71599
  const standardCT = formatCycleTimeValue(workspace.ideal_cycle_time);
71562
71600
  return /* @__PURE__ */ jsxs("span", { className: "tabular-nums", children: [
@@ -72525,13 +72563,13 @@ var LeaderboardDetailView = memo$1(({
72525
72563
  error.message
72526
72564
  ] }) });
72527
72565
  }
72528
- const hasRecentFlowLeaderboardRows = sortedWorkspaces.some(
72529
- (workspace) => workspace.leaderboard_metric_kind === "recent_flow_shift_average"
72566
+ const hasCycleTimeLeaderboardRows = sortedWorkspaces.some(
72567
+ (workspace) => workspace.leaderboard_metric_kind === "cycle_time"
72530
72568
  );
72531
72569
  const hasEfficiencyLeaderboardRows = sortedWorkspaces.some(
72532
- (workspace) => workspace.leaderboard_metric_kind !== "recent_flow_shift_average"
72570
+ (workspace) => workspace.leaderboard_metric_kind !== "cycle_time"
72533
72571
  );
72534
- const metricLabel = viewType === "machine" ? "Utilization" : hasRecentFlowLeaderboardRows && !hasEfficiencyLeaderboardRows ? "Actual CT / Standard CT" : hasRecentFlowLeaderboardRows && hasEfficiencyLeaderboardRows ? "Performance" : "Efficiency";
72572
+ const metricLabel = viewType === "machine" ? "Utilization" : hasCycleTimeLeaderboardRows && !hasEfficiencyLeaderboardRows ? "Actual CT / Standard CT" : hasCycleTimeLeaderboardRows && hasEfficiencyLeaderboardRows ? "Performance" : "Efficiency";
72535
72573
  const descendingSortLabel = "Highest to Lowest";
72536
72574
  const ascendingSortLabel = "Lowest to Highest";
72537
72575
  return /* @__PURE__ */ jsxs("div", { className: `min-h-screen bg-slate-50 flex flex-col ${className}`, style: { willChange: "contents" }, children: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optifye/dashboard-core",
3
- "version": "6.12.27",
3
+ "version": "6.12.29",
4
4
  "description": "Reusable UI & logic for Optifye dashboard",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",