@optifye/dashboard-core 6.12.29 → 6.12.30
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/dist/{automation-DYa3jNEf.d.mts → automation-Jf6Isg6G.d.mts} +18 -1
- package/dist/{automation-DYa3jNEf.d.ts → automation-Jf6Isg6G.d.ts} +18 -1
- package/dist/automation.d.mts +1 -1
- package/dist/automation.d.ts +1 -1
- package/dist/automation.js +165 -1
- package/dist/automation.mjs +167 -3
- package/dist/index.css +35 -0
- package/dist/index.d.mts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +79 -2
- package/dist/index.mjs +81 -4
- package/package.json +1 -1
|
@@ -5,6 +5,9 @@ declare const normalizeVideoGridMetricMode: (value: unknown, assemblyEnabled?: b
|
|
|
5
5
|
declare const isRecentFlowVideoGridMetricMode: (value: unknown, assemblyEnabled?: boolean) => boolean;
|
|
6
6
|
declare const isWipGatedVideoGridMetricMode: (value: unknown, assemblyEnabled?: boolean) => boolean;
|
|
7
7
|
|
|
8
|
+
type IdleReasonPaletteToken = 'red' | 'amber' | 'blue' | 'violet' | 'emerald' | 'cyan' | 'slate';
|
|
9
|
+
type IdleReasonIconToken = 'alert-triangle' | 'refresh-cw' | 'package' | 'clock' | 'user-x' | 'wrench' | 'activity' | 'clipboard-x' | 'help-circle';
|
|
10
|
+
|
|
8
11
|
/** One row of per-SKU workspace metrics. Backend computes; frontend renders. */
|
|
9
12
|
interface SkuBreakdownItem {
|
|
10
13
|
/** UUID — `skus.id`. Stable identifier for selectors and threshold writes. */
|
|
@@ -149,6 +152,18 @@ interface PoorPerformingWorkspace {
|
|
|
149
152
|
action_count: number;
|
|
150
153
|
action_threshold: number;
|
|
151
154
|
}
|
|
155
|
+
interface VideoGridStatusBadge {
|
|
156
|
+
kind: 'idle_reason' | 'no_plan';
|
|
157
|
+
label: string | null;
|
|
158
|
+
display_name: string;
|
|
159
|
+
palette_token: IdleReasonPaletteToken;
|
|
160
|
+
icon_token: IdleReasonIconToken;
|
|
161
|
+
is_known?: boolean;
|
|
162
|
+
title?: string;
|
|
163
|
+
anchor_minute?: number;
|
|
164
|
+
reason_minute?: number;
|
|
165
|
+
shift_elapsed_fraction?: number;
|
|
166
|
+
}
|
|
152
167
|
interface WorkspaceMetrics {
|
|
153
168
|
company_id: string;
|
|
154
169
|
line_id: string;
|
|
@@ -170,6 +185,7 @@ interface WorkspaceMetrics {
|
|
|
170
185
|
monitoring_mode?: 'output' | 'uptime';
|
|
171
186
|
idle_time?: number;
|
|
172
187
|
idle_time_hourly?: Record<string, any> | null;
|
|
188
|
+
idle_reason_hourly?: Record<string, any> | null;
|
|
173
189
|
shift_start?: string;
|
|
174
190
|
shift_end?: string;
|
|
175
191
|
assembly_enabled?: boolean;
|
|
@@ -200,6 +216,7 @@ interface WorkspaceMetrics {
|
|
|
200
216
|
incoming_wip_current?: number | null;
|
|
201
217
|
incoming_wip_effective_at?: string | null;
|
|
202
218
|
incoming_wip_buffer_name?: string | null;
|
|
219
|
+
video_grid_badges?: VideoGridStatusBadge[];
|
|
203
220
|
/**
|
|
204
221
|
* When present, controls whether the UI should show the exclamation indicator for this workstation.
|
|
205
222
|
* - Flow-configured lines: true only when a WIP alert is active for a buffer that outputs to this workstation.
|
|
@@ -477,4 +494,4 @@ interface RecentFlowSnapshotGridProps {
|
|
|
477
494
|
}
|
|
478
495
|
declare const RecentFlowSnapshotGrid: React__default.FC<RecentFlowSnapshotGridProps>;
|
|
479
496
|
|
|
480
|
-
export { type ActionThreshold as A, type CurrentWorkspaceSKU as C, type DashboardKPIs as D, type EfficiencyLegendUpdate as E, type KpiTrend as K, type LineSignal as L, type MonthlyTrendSummary as M, type PoorPerformingWorkspace as P, type RecentFlowSnapshotGridProps as R, type SkuBreakdownItem as S, type VideoGridMetricMode as V, type WorkspaceMetrics as W, type LineInfo as a, type WorkspaceDetailedMetrics as b, type SkuSegmentItem as c, type LineSkuBreakdownItem as d, type WorkspaceVideoStream as e, type Workspace as f, type WorkspaceCameraIpInfo as g, type WorkspaceActionUpdate as h, type ShiftConfiguration as i, type KpiSignal as j, type LineIssueResolutionSummary as k, type LineDetailedMetrics as l, type
|
|
497
|
+
export { type ActionThreshold as A, RecentFlowSnapshotGrid as B, type CurrentWorkspaceSKU as C, type DashboardKPIs as D, type EfficiencyLegendUpdate as E, type KpiTrend as K, type LineSignal as L, type MonthlyTrendSummary as M, type PoorPerformingWorkspace as P, type RecentFlowSnapshotGridProps as R, type SkuBreakdownItem as S, type VideoGridMetricMode as V, type WorkspaceMetrics as W, type LineInfo as a, type WorkspaceDetailedMetrics as b, type SkuSegmentItem as c, type LineSkuBreakdownItem as d, type WorkspaceVideoStream as e, type Workspace as f, type WorkspaceCameraIpInfo as g, type WorkspaceActionUpdate as h, type ShiftConfiguration as i, type KpiSignal as j, type LineIssueResolutionSummary as k, type LineDetailedMetrics as l, type VideoGridStatusBadge as m, type LineSignalSource as n, type KpiSignalSource as o, type KpiSignalMode as p, type ValueDelta as q, type PercentageDelta as r, type CountDelta as s, type DurationDelta as t, type WorkspaceCropRect as u, type LineThreshold as v, type ShiftConfigurationRecord as w, normalizeVideoGridMetricMode as x, isRecentFlowVideoGridMetricMode as y, isWipGatedVideoGridMetricMode as z };
|
|
@@ -5,6 +5,9 @@ declare const normalizeVideoGridMetricMode: (value: unknown, assemblyEnabled?: b
|
|
|
5
5
|
declare const isRecentFlowVideoGridMetricMode: (value: unknown, assemblyEnabled?: boolean) => boolean;
|
|
6
6
|
declare const isWipGatedVideoGridMetricMode: (value: unknown, assemblyEnabled?: boolean) => boolean;
|
|
7
7
|
|
|
8
|
+
type IdleReasonPaletteToken = 'red' | 'amber' | 'blue' | 'violet' | 'emerald' | 'cyan' | 'slate';
|
|
9
|
+
type IdleReasonIconToken = 'alert-triangle' | 'refresh-cw' | 'package' | 'clock' | 'user-x' | 'wrench' | 'activity' | 'clipboard-x' | 'help-circle';
|
|
10
|
+
|
|
8
11
|
/** One row of per-SKU workspace metrics. Backend computes; frontend renders. */
|
|
9
12
|
interface SkuBreakdownItem {
|
|
10
13
|
/** UUID — `skus.id`. Stable identifier for selectors and threshold writes. */
|
|
@@ -149,6 +152,18 @@ interface PoorPerformingWorkspace {
|
|
|
149
152
|
action_count: number;
|
|
150
153
|
action_threshold: number;
|
|
151
154
|
}
|
|
155
|
+
interface VideoGridStatusBadge {
|
|
156
|
+
kind: 'idle_reason' | 'no_plan';
|
|
157
|
+
label: string | null;
|
|
158
|
+
display_name: string;
|
|
159
|
+
palette_token: IdleReasonPaletteToken;
|
|
160
|
+
icon_token: IdleReasonIconToken;
|
|
161
|
+
is_known?: boolean;
|
|
162
|
+
title?: string;
|
|
163
|
+
anchor_minute?: number;
|
|
164
|
+
reason_minute?: number;
|
|
165
|
+
shift_elapsed_fraction?: number;
|
|
166
|
+
}
|
|
152
167
|
interface WorkspaceMetrics {
|
|
153
168
|
company_id: string;
|
|
154
169
|
line_id: string;
|
|
@@ -170,6 +185,7 @@ interface WorkspaceMetrics {
|
|
|
170
185
|
monitoring_mode?: 'output' | 'uptime';
|
|
171
186
|
idle_time?: number;
|
|
172
187
|
idle_time_hourly?: Record<string, any> | null;
|
|
188
|
+
idle_reason_hourly?: Record<string, any> | null;
|
|
173
189
|
shift_start?: string;
|
|
174
190
|
shift_end?: string;
|
|
175
191
|
assembly_enabled?: boolean;
|
|
@@ -200,6 +216,7 @@ interface WorkspaceMetrics {
|
|
|
200
216
|
incoming_wip_current?: number | null;
|
|
201
217
|
incoming_wip_effective_at?: string | null;
|
|
202
218
|
incoming_wip_buffer_name?: string | null;
|
|
219
|
+
video_grid_badges?: VideoGridStatusBadge[];
|
|
203
220
|
/**
|
|
204
221
|
* When present, controls whether the UI should show the exclamation indicator for this workstation.
|
|
205
222
|
* - Flow-configured lines: true only when a WIP alert is active for a buffer that outputs to this workstation.
|
|
@@ -477,4 +494,4 @@ interface RecentFlowSnapshotGridProps {
|
|
|
477
494
|
}
|
|
478
495
|
declare const RecentFlowSnapshotGrid: React__default.FC<RecentFlowSnapshotGridProps>;
|
|
479
496
|
|
|
480
|
-
export { type ActionThreshold as A, type CurrentWorkspaceSKU as C, type DashboardKPIs as D, type EfficiencyLegendUpdate as E, type KpiTrend as K, type LineSignal as L, type MonthlyTrendSummary as M, type PoorPerformingWorkspace as P, type RecentFlowSnapshotGridProps as R, type SkuBreakdownItem as S, type VideoGridMetricMode as V, type WorkspaceMetrics as W, type LineInfo as a, type WorkspaceDetailedMetrics as b, type SkuSegmentItem as c, type LineSkuBreakdownItem as d, type WorkspaceVideoStream as e, type Workspace as f, type WorkspaceCameraIpInfo as g, type WorkspaceActionUpdate as h, type ShiftConfiguration as i, type KpiSignal as j, type LineIssueResolutionSummary as k, type LineDetailedMetrics as l, type
|
|
497
|
+
export { type ActionThreshold as A, RecentFlowSnapshotGrid as B, type CurrentWorkspaceSKU as C, type DashboardKPIs as D, type EfficiencyLegendUpdate as E, type KpiTrend as K, type LineSignal as L, type MonthlyTrendSummary as M, type PoorPerformingWorkspace as P, type RecentFlowSnapshotGridProps as R, type SkuBreakdownItem as S, type VideoGridMetricMode as V, type WorkspaceMetrics as W, type LineInfo as a, type WorkspaceDetailedMetrics as b, type SkuSegmentItem as c, type LineSkuBreakdownItem as d, type WorkspaceVideoStream as e, type Workspace as f, type WorkspaceCameraIpInfo as g, type WorkspaceActionUpdate as h, type ShiftConfiguration as i, type KpiSignal as j, type LineIssueResolutionSummary as k, type LineDetailedMetrics as l, type VideoGridStatusBadge as m, type LineSignalSource as n, type KpiSignalSource as o, type KpiSignalMode as p, type ValueDelta as q, type PercentageDelta as r, type CountDelta as s, type DurationDelta as t, type WorkspaceCropRect as u, type LineThreshold as v, type ShiftConfigurationRecord as w, normalizeVideoGridMetricMode as x, isRecentFlowVideoGridMetricMode as y, isWipGatedVideoGridMetricMode as z };
|
package/dist/automation.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { B as RecentFlowSnapshotGrid, R as RecentFlowSnapshotGridProps, W as WorkspaceMetrics, e as WorkspaceVideoStream } from './automation-Jf6Isg6G.mjs';
|
|
2
2
|
import 'react';
|
package/dist/automation.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { B as RecentFlowSnapshotGrid, R as RecentFlowSnapshotGridProps, W as WorkspaceMetrics, e as WorkspaceVideoStream } from './automation-Jf6Isg6G.js';
|
|
2
2
|
import 'react';
|
package/dist/automation.js
CHANGED
|
@@ -1734,6 +1734,99 @@ var trackCoreEvent = (eventName, properties) => {
|
|
|
1734
1734
|
return;
|
|
1735
1735
|
}
|
|
1736
1736
|
};
|
|
1737
|
+
var DEFAULT_PALETTE_TOKEN = "slate";
|
|
1738
|
+
var DEFAULT_ICON_TOKEN = "help-circle";
|
|
1739
|
+
var PALETTE_CONFIG = {
|
|
1740
|
+
red: {
|
|
1741
|
+
hex: "#dc2626",
|
|
1742
|
+
textClass: "text-red-600",
|
|
1743
|
+
bgClass: "bg-red-50",
|
|
1744
|
+
borderClass: "border-red-200"
|
|
1745
|
+
},
|
|
1746
|
+
amber: {
|
|
1747
|
+
hex: "#f59e0b",
|
|
1748
|
+
textClass: "text-amber-600",
|
|
1749
|
+
bgClass: "bg-amber-50",
|
|
1750
|
+
borderClass: "border-amber-200"
|
|
1751
|
+
},
|
|
1752
|
+
blue: {
|
|
1753
|
+
hex: "#3b82f6",
|
|
1754
|
+
textClass: "text-blue-600",
|
|
1755
|
+
bgClass: "bg-blue-50",
|
|
1756
|
+
borderClass: "border-blue-200"
|
|
1757
|
+
},
|
|
1758
|
+
violet: {
|
|
1759
|
+
hex: "#8b5cf6",
|
|
1760
|
+
textClass: "text-violet-600",
|
|
1761
|
+
bgClass: "bg-violet-50",
|
|
1762
|
+
borderClass: "border-violet-200"
|
|
1763
|
+
},
|
|
1764
|
+
emerald: {
|
|
1765
|
+
hex: "#10b981",
|
|
1766
|
+
textClass: "text-emerald-600",
|
|
1767
|
+
bgClass: "bg-emerald-50",
|
|
1768
|
+
borderClass: "border-emerald-200"
|
|
1769
|
+
},
|
|
1770
|
+
cyan: {
|
|
1771
|
+
hex: "#0891b2",
|
|
1772
|
+
textClass: "text-cyan-600",
|
|
1773
|
+
bgClass: "bg-cyan-50",
|
|
1774
|
+
borderClass: "border-cyan-200"
|
|
1775
|
+
},
|
|
1776
|
+
slate: {
|
|
1777
|
+
hex: "#64748b",
|
|
1778
|
+
textClass: "text-slate-600",
|
|
1779
|
+
bgClass: "bg-slate-50",
|
|
1780
|
+
borderClass: "border-slate-200"
|
|
1781
|
+
}
|
|
1782
|
+
};
|
|
1783
|
+
var ICON_CONFIG = {
|
|
1784
|
+
"alert-triangle": lucideReact.AlertTriangle,
|
|
1785
|
+
"refresh-cw": lucideReact.RefreshCw,
|
|
1786
|
+
package: lucideReact.Package,
|
|
1787
|
+
clock: lucideReact.Clock,
|
|
1788
|
+
"user-x": lucideReact.UserX,
|
|
1789
|
+
wrench: lucideReact.Wrench,
|
|
1790
|
+
activity: lucideReact.Activity,
|
|
1791
|
+
"clipboard-x": lucideReact.ClipboardX,
|
|
1792
|
+
"help-circle": lucideReact.HelpCircle
|
|
1793
|
+
};
|
|
1794
|
+
var humanizeIdleReasonLabel = (value) => {
|
|
1795
|
+
const text = String(value || "").trim();
|
|
1796
|
+
if (!text) {
|
|
1797
|
+
return "Unknown";
|
|
1798
|
+
}
|
|
1799
|
+
return text.replace(/_/g, " ").split(/\s+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
|
|
1800
|
+
};
|
|
1801
|
+
var normalizePaletteToken = (value) => {
|
|
1802
|
+
const token = String(value || "").trim().toLowerCase();
|
|
1803
|
+
if (token in PALETTE_CONFIG) {
|
|
1804
|
+
return token;
|
|
1805
|
+
}
|
|
1806
|
+
return DEFAULT_PALETTE_TOKEN;
|
|
1807
|
+
};
|
|
1808
|
+
var normalizeIconToken = (value) => {
|
|
1809
|
+
const token = String(value || "").trim().toLowerCase();
|
|
1810
|
+
if (token in ICON_CONFIG) {
|
|
1811
|
+
return token;
|
|
1812
|
+
}
|
|
1813
|
+
return DEFAULT_ICON_TOKEN;
|
|
1814
|
+
};
|
|
1815
|
+
var getIdleReasonPresentation = (metadata) => {
|
|
1816
|
+
const label = typeof metadata?.label === "string" && metadata.label.trim() ? metadata.label.trim() : null;
|
|
1817
|
+
const displayName = typeof metadata?.displayName === "string" && metadata.displayName.trim() ? metadata.displayName.trim() : humanizeIdleReasonLabel(label);
|
|
1818
|
+
const paletteToken = normalizePaletteToken(metadata?.paletteToken);
|
|
1819
|
+
const iconToken = normalizeIconToken(metadata?.iconToken);
|
|
1820
|
+
return {
|
|
1821
|
+
label,
|
|
1822
|
+
displayName,
|
|
1823
|
+
paletteToken,
|
|
1824
|
+
iconToken,
|
|
1825
|
+
isKnown: Boolean(metadata?.isKnown),
|
|
1826
|
+
Icon: ICON_CONFIG[iconToken],
|
|
1827
|
+
...PALETTE_CONFIG[paletteToken]
|
|
1828
|
+
};
|
|
1829
|
+
};
|
|
1737
1830
|
|
|
1738
1831
|
// src/lib/constants/videoGridMetricMode.ts
|
|
1739
1832
|
var VALID_VIDEO_GRID_METRIC_MODES = /* @__PURE__ */ new Set([
|
|
@@ -1875,6 +1968,20 @@ var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND, blu
|
|
|
1875
1968
|
}
|
|
1876
1969
|
return baseColor;
|
|
1877
1970
|
};
|
|
1971
|
+
var getStatusBadgeSignature = (workspace) => {
|
|
1972
|
+
const badges = workspace.video_grid_badges || [];
|
|
1973
|
+
return badges.map((badge) => [
|
|
1974
|
+
badge.kind,
|
|
1975
|
+
badge.label,
|
|
1976
|
+
badge.display_name,
|
|
1977
|
+
badge.palette_token,
|
|
1978
|
+
badge.icon_token,
|
|
1979
|
+
badge.anchor_minute,
|
|
1980
|
+
badge.reason_minute,
|
|
1981
|
+
badge.shift_elapsed_fraction,
|
|
1982
|
+
badge.title
|
|
1983
|
+
].join(":")).join("|");
|
|
1984
|
+
};
|
|
1878
1985
|
function getTrendArrowAndColor(trend) {
|
|
1879
1986
|
if (trend > 0) {
|
|
1880
1987
|
return { arrow: "\u2191", color: "text-green-400" };
|
|
@@ -1906,6 +2013,7 @@ var VideoCard = React__default.default.memo(({
|
|
|
1906
2013
|
}) => {
|
|
1907
2014
|
const videoRef = React.useRef(null);
|
|
1908
2015
|
const canvasRef = React.useRef(null);
|
|
2016
|
+
const statusBadgeIdPrefix = React.useId();
|
|
1909
2017
|
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
1910
2018
|
const { isStale: isStreamStale } = useHlsStreamWithCropping(videoRef, canvasRef, {
|
|
1911
2019
|
src: hlsUrl,
|
|
@@ -1932,6 +2040,7 @@ var VideoCard = React__default.default.memo(({
|
|
|
1932
2040
|
const shouldRenderMetricBadge = hasDisplayMetric;
|
|
1933
2041
|
const badgeTitle = isHighEfficiencyOverride ? `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%` : hasVideoGridRecentFlow(workspace) ? `Flow ${Math.round(videoGridDisplayValue ?? 0)}%` : isRecentFlowCard ? "Flow unavailable" : `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%`;
|
|
1934
2042
|
const badgeLabel = `${Math.round(videoGridDisplayValue ?? 0)}%`;
|
|
2043
|
+
const statusBadges = workspace.video_grid_badges || [];
|
|
1935
2044
|
const efficiencyOverlayClass = videoGridColorState === "green" ? "bg-[#00D654]/25" : videoGridColorState === "blue" ? "bg-[#0EA5E9]/30" : videoGridColorState === "yellow" ? "bg-[#FFD700]/30" : videoGridColorState === "red" ? "bg-[#FF2D0A]/30" : "bg-transparent";
|
|
1936
2045
|
const efficiencyBarClass = videoGridColorState === "green" ? "bg-[#00AB45]" : videoGridColorState === "blue" ? "bg-[#0EA5E9]" : videoGridColorState === "yellow" ? "bg-[#FFB020]" : videoGridColorState === "red" ? "bg-[#E34329]" : "bg-gray-500/70";
|
|
1937
2046
|
const efficiencyStatus = videoGridColorState === "green" ? "High" : videoGridColorState === "blue" ? "Best" : videoGridColorState === "yellow" ? "Medium" : videoGridColorState === "red" ? "Low" : "Neutral";
|
|
@@ -2010,6 +2119,61 @@ var VideoCard = React__default.default.memo(({
|
|
|
2010
2119
|
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: `${compact ? "text-[10px]" : "text-xs"} font-semibold`, children: badgeLabel })
|
|
2011
2120
|
}
|
|
2012
2121
|
) }),
|
|
2122
|
+
statusBadges.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2123
|
+
"div",
|
|
2124
|
+
{
|
|
2125
|
+
"data-testid": "video-card-status-badges",
|
|
2126
|
+
className: `absolute ${compact ? "top-1.5 left-1.5 gap-1" : "top-2 left-2 gap-1.5"} z-30 flex items-center`,
|
|
2127
|
+
children: statusBadges.map((badge, index) => {
|
|
2128
|
+
const presentation = getIdleReasonPresentation({
|
|
2129
|
+
label: badge.label,
|
|
2130
|
+
displayName: badge.display_name,
|
|
2131
|
+
paletteToken: badge.palette_token,
|
|
2132
|
+
iconToken: badge.icon_token,
|
|
2133
|
+
isKnown: badge.is_known
|
|
2134
|
+
});
|
|
2135
|
+
const Icon = presentation.Icon;
|
|
2136
|
+
const tooltipText = presentation.displayName;
|
|
2137
|
+
const tooltipId = `video-card-status-tooltip-${statusBadgeIdPrefix}-${badge.kind}-${index}`;
|
|
2138
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2139
|
+
"div",
|
|
2140
|
+
{
|
|
2141
|
+
"data-testid": `video-card-status-badge-${badge.kind}`,
|
|
2142
|
+
"aria-label": tooltipText,
|
|
2143
|
+
"aria-describedby": tooltipId,
|
|
2144
|
+
className: `group relative inline-flex shrink-0 items-center justify-center rounded-full bg-slate-950/70 border-2 shadow-[0_3px_10px_rgba(0,0,0,0.34),inset_0_0_0_1px_rgba(255,255,255,0.18)] ${compact ? "h-10 w-10" : "h-11 w-11"}`,
|
|
2145
|
+
style: {
|
|
2146
|
+
borderColor: presentation.hex
|
|
2147
|
+
},
|
|
2148
|
+
children: [
|
|
2149
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2150
|
+
Icon,
|
|
2151
|
+
{
|
|
2152
|
+
"aria-hidden": "true",
|
|
2153
|
+
className: `${compact ? "h-5 w-5" : "h-6 w-6"} text-white`,
|
|
2154
|
+
strokeWidth: 2.4
|
|
2155
|
+
}
|
|
2156
|
+
),
|
|
2157
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2158
|
+
"span",
|
|
2159
|
+
{
|
|
2160
|
+
id: tooltipId,
|
|
2161
|
+
role: "tooltip",
|
|
2162
|
+
"data-testid": `video-card-status-tooltip-${badge.kind}`,
|
|
2163
|
+
className: "pointer-events-none absolute left-0 top-full mt-2 whitespace-nowrap rounded-md border border-white/10 bg-slate-950/95 px-2 py-1 text-[11px] font-semibold leading-none text-white opacity-0 shadow-[0_6px_18px_rgba(0,0,0,0.34)] transition-opacity duration-150 group-hover:opacity-100",
|
|
2164
|
+
children: [
|
|
2165
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-1 left-3 h-2 w-2 rotate-45 border-l border-t border-white/10 bg-slate-950/95" }),
|
|
2166
|
+
tooltipText
|
|
2167
|
+
]
|
|
2168
|
+
}
|
|
2169
|
+
)
|
|
2170
|
+
]
|
|
2171
|
+
},
|
|
2172
|
+
`${badge.kind}-${badge.label || index}-${badge.reason_minute ?? index}`
|
|
2173
|
+
);
|
|
2174
|
+
})
|
|
2175
|
+
}
|
|
2176
|
+
),
|
|
2013
2177
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `absolute bottom-0 left-0 right-0 ${compact ? "h-0.5" : "h-1"} bg-black/50 z-30`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2014
2178
|
"div",
|
|
2015
2179
|
{
|
|
@@ -2046,7 +2210,7 @@ var VideoCard = React__default.default.memo(({
|
|
|
2046
2210
|
}
|
|
2047
2211
|
);
|
|
2048
2212
|
}, (prevProps, nextProps) => {
|
|
2049
|
-
if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.recent_flow_percent !== nextProps.workspace.recent_flow_percent || prevProps.workspace.recent_flow_effective_end_at !== nextProps.workspace.recent_flow_effective_end_at || prevProps.workspace.recent_flow_forced_zero_after_shift !== nextProps.workspace.recent_flow_forced_zero_after_shift || prevProps.workspace.scheduled_break_active !== nextProps.workspace.scheduled_break_active || prevProps.workspace.incoming_wip_current !== nextProps.workspace.incoming_wip_current || prevProps.workspace.incoming_wip_buffer_name !== nextProps.workspace.incoming_wip_buffer_name || prevProps.workspace.trend !== nextProps.workspace.trend || prevProps.workspace.performance_score !== nextProps.workspace.performance_score || prevProps.workspace.pph !== nextProps.workspace.pph) {
|
|
2213
|
+
if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.recent_flow_percent !== nextProps.workspace.recent_flow_percent || prevProps.workspace.recent_flow_effective_end_at !== nextProps.workspace.recent_flow_effective_end_at || prevProps.workspace.recent_flow_forced_zero_after_shift !== nextProps.workspace.recent_flow_forced_zero_after_shift || prevProps.workspace.scheduled_break_active !== nextProps.workspace.scheduled_break_active || prevProps.workspace.incoming_wip_current !== nextProps.workspace.incoming_wip_current || prevProps.workspace.incoming_wip_buffer_name !== nextProps.workspace.incoming_wip_buffer_name || getStatusBadgeSignature(prevProps.workspace) !== getStatusBadgeSignature(nextProps.workspace) || prevProps.workspace.trend !== nextProps.workspace.trend || prevProps.workspace.performance_score !== nextProps.workspace.performance_score || prevProps.workspace.pph !== nextProps.workspace.pph) {
|
|
2050
2214
|
return false;
|
|
2051
2215
|
}
|
|
2052
2216
|
if (prevProps.workspace.workspace_uuid !== nextProps.workspace.workspace_uuid || prevProps.workspace.workspace_name !== nextProps.workspace.workspace_name || prevProps.workspace.line_id !== nextProps.workspace.line_id) {
|
package/dist/automation.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React, { useRef, useCallback, useEffect, useState, useMemo } from 'react';
|
|
2
|
-
import { Camera, AlertTriangle } from 'lucide-react';
|
|
1
|
+
import React, { useRef, useId, useCallback, useEffect, useState, useMemo } from 'react';
|
|
2
|
+
import { Camera, AlertTriangle, HelpCircle, ClipboardX, Activity, Wrench, UserX, Clock, Package, RefreshCw } from 'lucide-react';
|
|
3
3
|
import Hls from 'hls.js';
|
|
4
4
|
import 'mixpanel-browser';
|
|
5
5
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
@@ -1727,6 +1727,99 @@ var trackCoreEvent = (eventName, properties) => {
|
|
|
1727
1727
|
return;
|
|
1728
1728
|
}
|
|
1729
1729
|
};
|
|
1730
|
+
var DEFAULT_PALETTE_TOKEN = "slate";
|
|
1731
|
+
var DEFAULT_ICON_TOKEN = "help-circle";
|
|
1732
|
+
var PALETTE_CONFIG = {
|
|
1733
|
+
red: {
|
|
1734
|
+
hex: "#dc2626",
|
|
1735
|
+
textClass: "text-red-600",
|
|
1736
|
+
bgClass: "bg-red-50",
|
|
1737
|
+
borderClass: "border-red-200"
|
|
1738
|
+
},
|
|
1739
|
+
amber: {
|
|
1740
|
+
hex: "#f59e0b",
|
|
1741
|
+
textClass: "text-amber-600",
|
|
1742
|
+
bgClass: "bg-amber-50",
|
|
1743
|
+
borderClass: "border-amber-200"
|
|
1744
|
+
},
|
|
1745
|
+
blue: {
|
|
1746
|
+
hex: "#3b82f6",
|
|
1747
|
+
textClass: "text-blue-600",
|
|
1748
|
+
bgClass: "bg-blue-50",
|
|
1749
|
+
borderClass: "border-blue-200"
|
|
1750
|
+
},
|
|
1751
|
+
violet: {
|
|
1752
|
+
hex: "#8b5cf6",
|
|
1753
|
+
textClass: "text-violet-600",
|
|
1754
|
+
bgClass: "bg-violet-50",
|
|
1755
|
+
borderClass: "border-violet-200"
|
|
1756
|
+
},
|
|
1757
|
+
emerald: {
|
|
1758
|
+
hex: "#10b981",
|
|
1759
|
+
textClass: "text-emerald-600",
|
|
1760
|
+
bgClass: "bg-emerald-50",
|
|
1761
|
+
borderClass: "border-emerald-200"
|
|
1762
|
+
},
|
|
1763
|
+
cyan: {
|
|
1764
|
+
hex: "#0891b2",
|
|
1765
|
+
textClass: "text-cyan-600",
|
|
1766
|
+
bgClass: "bg-cyan-50",
|
|
1767
|
+
borderClass: "border-cyan-200"
|
|
1768
|
+
},
|
|
1769
|
+
slate: {
|
|
1770
|
+
hex: "#64748b",
|
|
1771
|
+
textClass: "text-slate-600",
|
|
1772
|
+
bgClass: "bg-slate-50",
|
|
1773
|
+
borderClass: "border-slate-200"
|
|
1774
|
+
}
|
|
1775
|
+
};
|
|
1776
|
+
var ICON_CONFIG = {
|
|
1777
|
+
"alert-triangle": AlertTriangle,
|
|
1778
|
+
"refresh-cw": RefreshCw,
|
|
1779
|
+
package: Package,
|
|
1780
|
+
clock: Clock,
|
|
1781
|
+
"user-x": UserX,
|
|
1782
|
+
wrench: Wrench,
|
|
1783
|
+
activity: Activity,
|
|
1784
|
+
"clipboard-x": ClipboardX,
|
|
1785
|
+
"help-circle": HelpCircle
|
|
1786
|
+
};
|
|
1787
|
+
var humanizeIdleReasonLabel = (value) => {
|
|
1788
|
+
const text = String(value || "").trim();
|
|
1789
|
+
if (!text) {
|
|
1790
|
+
return "Unknown";
|
|
1791
|
+
}
|
|
1792
|
+
return text.replace(/_/g, " ").split(/\s+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
|
|
1793
|
+
};
|
|
1794
|
+
var normalizePaletteToken = (value) => {
|
|
1795
|
+
const token = String(value || "").trim().toLowerCase();
|
|
1796
|
+
if (token in PALETTE_CONFIG) {
|
|
1797
|
+
return token;
|
|
1798
|
+
}
|
|
1799
|
+
return DEFAULT_PALETTE_TOKEN;
|
|
1800
|
+
};
|
|
1801
|
+
var normalizeIconToken = (value) => {
|
|
1802
|
+
const token = String(value || "").trim().toLowerCase();
|
|
1803
|
+
if (token in ICON_CONFIG) {
|
|
1804
|
+
return token;
|
|
1805
|
+
}
|
|
1806
|
+
return DEFAULT_ICON_TOKEN;
|
|
1807
|
+
};
|
|
1808
|
+
var getIdleReasonPresentation = (metadata) => {
|
|
1809
|
+
const label = typeof metadata?.label === "string" && metadata.label.trim() ? metadata.label.trim() : null;
|
|
1810
|
+
const displayName = typeof metadata?.displayName === "string" && metadata.displayName.trim() ? metadata.displayName.trim() : humanizeIdleReasonLabel(label);
|
|
1811
|
+
const paletteToken = normalizePaletteToken(metadata?.paletteToken);
|
|
1812
|
+
const iconToken = normalizeIconToken(metadata?.iconToken);
|
|
1813
|
+
return {
|
|
1814
|
+
label,
|
|
1815
|
+
displayName,
|
|
1816
|
+
paletteToken,
|
|
1817
|
+
iconToken,
|
|
1818
|
+
isKnown: Boolean(metadata?.isKnown),
|
|
1819
|
+
Icon: ICON_CONFIG[iconToken],
|
|
1820
|
+
...PALETTE_CONFIG[paletteToken]
|
|
1821
|
+
};
|
|
1822
|
+
};
|
|
1730
1823
|
|
|
1731
1824
|
// src/lib/constants/videoGridMetricMode.ts
|
|
1732
1825
|
var VALID_VIDEO_GRID_METRIC_MODES = /* @__PURE__ */ new Set([
|
|
@@ -1868,6 +1961,20 @@ var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND, blu
|
|
|
1868
1961
|
}
|
|
1869
1962
|
return baseColor;
|
|
1870
1963
|
};
|
|
1964
|
+
var getStatusBadgeSignature = (workspace) => {
|
|
1965
|
+
const badges = workspace.video_grid_badges || [];
|
|
1966
|
+
return badges.map((badge) => [
|
|
1967
|
+
badge.kind,
|
|
1968
|
+
badge.label,
|
|
1969
|
+
badge.display_name,
|
|
1970
|
+
badge.palette_token,
|
|
1971
|
+
badge.icon_token,
|
|
1972
|
+
badge.anchor_minute,
|
|
1973
|
+
badge.reason_minute,
|
|
1974
|
+
badge.shift_elapsed_fraction,
|
|
1975
|
+
badge.title
|
|
1976
|
+
].join(":")).join("|");
|
|
1977
|
+
};
|
|
1871
1978
|
function getTrendArrowAndColor(trend) {
|
|
1872
1979
|
if (trend > 0) {
|
|
1873
1980
|
return { arrow: "\u2191", color: "text-green-400" };
|
|
@@ -1899,6 +2006,7 @@ var VideoCard = React.memo(({
|
|
|
1899
2006
|
}) => {
|
|
1900
2007
|
const videoRef = useRef(null);
|
|
1901
2008
|
const canvasRef = useRef(null);
|
|
2009
|
+
const statusBadgeIdPrefix = useId();
|
|
1902
2010
|
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
1903
2011
|
const { isStale: isStreamStale } = useHlsStreamWithCropping(videoRef, canvasRef, {
|
|
1904
2012
|
src: hlsUrl,
|
|
@@ -1925,6 +2033,7 @@ var VideoCard = React.memo(({
|
|
|
1925
2033
|
const shouldRenderMetricBadge = hasDisplayMetric;
|
|
1926
2034
|
const badgeTitle = isHighEfficiencyOverride ? `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%` : hasVideoGridRecentFlow(workspace) ? `Flow ${Math.round(videoGridDisplayValue ?? 0)}%` : isRecentFlowCard ? "Flow unavailable" : `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%`;
|
|
1927
2035
|
const badgeLabel = `${Math.round(videoGridDisplayValue ?? 0)}%`;
|
|
2036
|
+
const statusBadges = workspace.video_grid_badges || [];
|
|
1928
2037
|
const efficiencyOverlayClass = videoGridColorState === "green" ? "bg-[#00D654]/25" : videoGridColorState === "blue" ? "bg-[#0EA5E9]/30" : videoGridColorState === "yellow" ? "bg-[#FFD700]/30" : videoGridColorState === "red" ? "bg-[#FF2D0A]/30" : "bg-transparent";
|
|
1929
2038
|
const efficiencyBarClass = videoGridColorState === "green" ? "bg-[#00AB45]" : videoGridColorState === "blue" ? "bg-[#0EA5E9]" : videoGridColorState === "yellow" ? "bg-[#FFB020]" : videoGridColorState === "red" ? "bg-[#E34329]" : "bg-gray-500/70";
|
|
1930
2039
|
const efficiencyStatus = videoGridColorState === "green" ? "High" : videoGridColorState === "blue" ? "Best" : videoGridColorState === "yellow" ? "Medium" : videoGridColorState === "red" ? "Low" : "Neutral";
|
|
@@ -2003,6 +2112,61 @@ var VideoCard = React.memo(({
|
|
|
2003
2112
|
children: /* @__PURE__ */ jsx("span", { className: `${compact ? "text-[10px]" : "text-xs"} font-semibold`, children: badgeLabel })
|
|
2004
2113
|
}
|
|
2005
2114
|
) }),
|
|
2115
|
+
statusBadges.length > 0 && /* @__PURE__ */ jsx(
|
|
2116
|
+
"div",
|
|
2117
|
+
{
|
|
2118
|
+
"data-testid": "video-card-status-badges",
|
|
2119
|
+
className: `absolute ${compact ? "top-1.5 left-1.5 gap-1" : "top-2 left-2 gap-1.5"} z-30 flex items-center`,
|
|
2120
|
+
children: statusBadges.map((badge, index) => {
|
|
2121
|
+
const presentation = getIdleReasonPresentation({
|
|
2122
|
+
label: badge.label,
|
|
2123
|
+
displayName: badge.display_name,
|
|
2124
|
+
paletteToken: badge.palette_token,
|
|
2125
|
+
iconToken: badge.icon_token,
|
|
2126
|
+
isKnown: badge.is_known
|
|
2127
|
+
});
|
|
2128
|
+
const Icon = presentation.Icon;
|
|
2129
|
+
const tooltipText = presentation.displayName;
|
|
2130
|
+
const tooltipId = `video-card-status-tooltip-${statusBadgeIdPrefix}-${badge.kind}-${index}`;
|
|
2131
|
+
return /* @__PURE__ */ jsxs(
|
|
2132
|
+
"div",
|
|
2133
|
+
{
|
|
2134
|
+
"data-testid": `video-card-status-badge-${badge.kind}`,
|
|
2135
|
+
"aria-label": tooltipText,
|
|
2136
|
+
"aria-describedby": tooltipId,
|
|
2137
|
+
className: `group relative inline-flex shrink-0 items-center justify-center rounded-full bg-slate-950/70 border-2 shadow-[0_3px_10px_rgba(0,0,0,0.34),inset_0_0_0_1px_rgba(255,255,255,0.18)] ${compact ? "h-10 w-10" : "h-11 w-11"}`,
|
|
2138
|
+
style: {
|
|
2139
|
+
borderColor: presentation.hex
|
|
2140
|
+
},
|
|
2141
|
+
children: [
|
|
2142
|
+
/* @__PURE__ */ jsx(
|
|
2143
|
+
Icon,
|
|
2144
|
+
{
|
|
2145
|
+
"aria-hidden": "true",
|
|
2146
|
+
className: `${compact ? "h-5 w-5" : "h-6 w-6"} text-white`,
|
|
2147
|
+
strokeWidth: 2.4
|
|
2148
|
+
}
|
|
2149
|
+
),
|
|
2150
|
+
/* @__PURE__ */ jsxs(
|
|
2151
|
+
"span",
|
|
2152
|
+
{
|
|
2153
|
+
id: tooltipId,
|
|
2154
|
+
role: "tooltip",
|
|
2155
|
+
"data-testid": `video-card-status-tooltip-${badge.kind}`,
|
|
2156
|
+
className: "pointer-events-none absolute left-0 top-full mt-2 whitespace-nowrap rounded-md border border-white/10 bg-slate-950/95 px-2 py-1 text-[11px] font-semibold leading-none text-white opacity-0 shadow-[0_6px_18px_rgba(0,0,0,0.34)] transition-opacity duration-150 group-hover:opacity-100",
|
|
2157
|
+
children: [
|
|
2158
|
+
/* @__PURE__ */ jsx("span", { className: "absolute -top-1 left-3 h-2 w-2 rotate-45 border-l border-t border-white/10 bg-slate-950/95" }),
|
|
2159
|
+
tooltipText
|
|
2160
|
+
]
|
|
2161
|
+
}
|
|
2162
|
+
)
|
|
2163
|
+
]
|
|
2164
|
+
},
|
|
2165
|
+
`${badge.kind}-${badge.label || index}-${badge.reason_minute ?? index}`
|
|
2166
|
+
);
|
|
2167
|
+
})
|
|
2168
|
+
}
|
|
2169
|
+
),
|
|
2006
2170
|
/* @__PURE__ */ jsx("div", { className: `absolute bottom-0 left-0 right-0 ${compact ? "h-0.5" : "h-1"} bg-black/50 z-30`, children: /* @__PURE__ */ jsx(
|
|
2007
2171
|
"div",
|
|
2008
2172
|
{
|
|
@@ -2039,7 +2203,7 @@ var VideoCard = React.memo(({
|
|
|
2039
2203
|
}
|
|
2040
2204
|
);
|
|
2041
2205
|
}, (prevProps, nextProps) => {
|
|
2042
|
-
if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.recent_flow_percent !== nextProps.workspace.recent_flow_percent || prevProps.workspace.recent_flow_effective_end_at !== nextProps.workspace.recent_flow_effective_end_at || prevProps.workspace.recent_flow_forced_zero_after_shift !== nextProps.workspace.recent_flow_forced_zero_after_shift || prevProps.workspace.scheduled_break_active !== nextProps.workspace.scheduled_break_active || prevProps.workspace.incoming_wip_current !== nextProps.workspace.incoming_wip_current || prevProps.workspace.incoming_wip_buffer_name !== nextProps.workspace.incoming_wip_buffer_name || prevProps.workspace.trend !== nextProps.workspace.trend || prevProps.workspace.performance_score !== nextProps.workspace.performance_score || prevProps.workspace.pph !== nextProps.workspace.pph) {
|
|
2206
|
+
if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.recent_flow_percent !== nextProps.workspace.recent_flow_percent || prevProps.workspace.recent_flow_effective_end_at !== nextProps.workspace.recent_flow_effective_end_at || prevProps.workspace.recent_flow_forced_zero_after_shift !== nextProps.workspace.recent_flow_forced_zero_after_shift || prevProps.workspace.scheduled_break_active !== nextProps.workspace.scheduled_break_active || prevProps.workspace.incoming_wip_current !== nextProps.workspace.incoming_wip_current || prevProps.workspace.incoming_wip_buffer_name !== nextProps.workspace.incoming_wip_buffer_name || getStatusBadgeSignature(prevProps.workspace) !== getStatusBadgeSignature(nextProps.workspace) || prevProps.workspace.trend !== nextProps.workspace.trend || prevProps.workspace.performance_score !== nextProps.workspace.performance_score || prevProps.workspace.pph !== nextProps.workspace.pph) {
|
|
2043
2207
|
return false;
|
|
2044
2208
|
}
|
|
2045
2209
|
if (prevProps.workspace.workspace_uuid !== nextProps.workspace.workspace_uuid || prevProps.workspace.workspace_name !== nextProps.workspace.workspace_name || prevProps.workspace.line_id !== nextProps.workspace.line_id) {
|
package/dist/index.css
CHANGED
|
@@ -538,6 +538,9 @@ body {
|
|
|
538
538
|
.left-1 {
|
|
539
539
|
left: 0.25rem;
|
|
540
540
|
}
|
|
541
|
+
.left-1\.5 {
|
|
542
|
+
left: 0.375rem;
|
|
543
|
+
}
|
|
541
544
|
.left-1\/2 {
|
|
542
545
|
left: 50%;
|
|
543
546
|
}
|
|
@@ -595,6 +598,9 @@ body {
|
|
|
595
598
|
.top-1 {
|
|
596
599
|
top: 0.25rem;
|
|
597
600
|
}
|
|
601
|
+
.top-1\.5 {
|
|
602
|
+
top: 0.375rem;
|
|
603
|
+
}
|
|
598
604
|
.top-1\/2 {
|
|
599
605
|
top: 50%;
|
|
600
606
|
}
|
|
@@ -1740,6 +1746,10 @@ body {
|
|
|
1740
1746
|
--tw-rotate: 180deg;
|
|
1741
1747
|
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
1742
1748
|
}
|
|
1749
|
+
.rotate-45 {
|
|
1750
|
+
--tw-rotate: 45deg;
|
|
1751
|
+
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
1752
|
+
}
|
|
1743
1753
|
.scale-0 {
|
|
1744
1754
|
--tw-scale-x: 0;
|
|
1745
1755
|
--tw-scale-y: 0;
|
|
@@ -2261,6 +2271,9 @@ body {
|
|
|
2261
2271
|
.border-b-\[6px\] {
|
|
2262
2272
|
border-bottom-width: 6px;
|
|
2263
2273
|
}
|
|
2274
|
+
.border-l {
|
|
2275
|
+
border-left-width: 1px;
|
|
2276
|
+
}
|
|
2264
2277
|
.border-l-2 {
|
|
2265
2278
|
border-left-width: 2px;
|
|
2266
2279
|
}
|
|
@@ -3091,6 +3104,12 @@ body {
|
|
|
3091
3104
|
.bg-slate-900\/60 {
|
|
3092
3105
|
background-color: rgb(15 23 42 / 0.6);
|
|
3093
3106
|
}
|
|
3107
|
+
.bg-slate-950\/70 {
|
|
3108
|
+
background-color: rgb(2 6 23 / 0.7);
|
|
3109
|
+
}
|
|
3110
|
+
.bg-slate-950\/95 {
|
|
3111
|
+
background-color: rgb(2 6 23 / 0.95);
|
|
3112
|
+
}
|
|
3094
3113
|
.bg-teal-100 {
|
|
3095
3114
|
--tw-bg-opacity: 1;
|
|
3096
3115
|
background-color: rgb(204 251 241 / var(--tw-bg-opacity, 1));
|
|
@@ -4974,6 +4993,22 @@ body {
|
|
|
4974
4993
|
var(--tw-ring-shadow, 0 0 #0000),
|
|
4975
4994
|
var(--tw-shadow);
|
|
4976
4995
|
}
|
|
4996
|
+
.shadow-\[0_3px_10px_rgba\(0\,0\,0\,0\.34\)\,inset_0_0_0_1px_rgba\(255\,255\,255\,0\.18\)\] {
|
|
4997
|
+
--tw-shadow: 0 3px 10px rgba(0,0,0,0.34),inset 0 0 0 1px rgba(255,255,255,0.18);
|
|
4998
|
+
--tw-shadow-colored: 0 3px 10px var(--tw-shadow-color), inset 0 0 0 1px var(--tw-shadow-color);
|
|
4999
|
+
box-shadow:
|
|
5000
|
+
var(--tw-ring-offset-shadow, 0 0 #0000),
|
|
5001
|
+
var(--tw-ring-shadow, 0 0 #0000),
|
|
5002
|
+
var(--tw-shadow);
|
|
5003
|
+
}
|
|
5004
|
+
.shadow-\[0_6px_18px_rgba\(0\,0\,0\,0\.34\)\] {
|
|
5005
|
+
--tw-shadow: 0 6px 18px rgba(0,0,0,0.34);
|
|
5006
|
+
--tw-shadow-colored: 0 6px 18px var(--tw-shadow-color);
|
|
5007
|
+
box-shadow:
|
|
5008
|
+
var(--tw-ring-offset-shadow, 0 0 #0000),
|
|
5009
|
+
var(--tw-ring-shadow, 0 0 #0000),
|
|
5010
|
+
var(--tw-shadow);
|
|
5011
|
+
}
|
|
4977
5012
|
.shadow-inner {
|
|
4978
5013
|
--tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.05);
|
|
4979
5014
|
--tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color);
|
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-
|
|
2
|
-
export {
|
|
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-Jf6Isg6G.mjs';
|
|
2
|
+
export { s as CountDelta, C as CurrentWorkspaceSKU, t as DurationDelta, p as KpiSignalMode, o as KpiSignalSource, l as LineDetailedMetrics, n as LineSignalSource, v as LineThreshold, r as PercentageDelta, B as RecentFlowSnapshotGrid, R as RecentFlowSnapshotGridProps, w as ShiftConfigurationRecord, q as ValueDelta, m as VideoGridStatusBadge, u as WorkspaceCropRect, y as isRecentFlowVideoGridMetricMode, z as isWipGatedVideoGridMetricMode, x as normalizeVideoGridMetricMode } from './automation-Jf6Isg6G.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';
|
|
@@ -5262,9 +5262,11 @@ declare const pickPreferredLineMetricsRow: (supabase: {
|
|
|
5262
5262
|
* - Aggregates `current_output` and `ideal_output` sum across
|
|
5263
5263
|
* **real-SKU rows only**. Dummy rows contribute 0 — they are skipped
|
|
5264
5264
|
* from that summation set.
|
|
5265
|
-
* - Weighted-average fields (avg_efficiency, avg_cycle_time
|
|
5266
|
-
*
|
|
5267
|
-
*
|
|
5265
|
+
* - Weighted-average fields (avg_efficiency, avg_cycle_time) use per-row
|
|
5266
|
+
* active-minutes as weight; falls back to plain mean when no row has
|
|
5267
|
+
* positive weight.
|
|
5268
|
+
* - `threshold_pph` sums across real rows so it matches the Targets
|
|
5269
|
+
* page/API additive output-family PPH rule.
|
|
5268
5270
|
* - `underperforming_workspaces` is averaged across ACTIVE real rows only
|
|
5269
5271
|
* (real row with `current_output > 0 || ideal_output > 0`), rounded
|
|
5270
5272
|
* half-up to the nearest whole number. Names / UUIDs are deduped unions
|
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-
|
|
2
|
-
export {
|
|
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-Jf6Isg6G.js';
|
|
2
|
+
export { s as CountDelta, C as CurrentWorkspaceSKU, t as DurationDelta, p as KpiSignalMode, o as KpiSignalSource, l as LineDetailedMetrics, n as LineSignalSource, v as LineThreshold, r as PercentageDelta, B as RecentFlowSnapshotGrid, R as RecentFlowSnapshotGridProps, w as ShiftConfigurationRecord, q as ValueDelta, m as VideoGridStatusBadge, u as WorkspaceCropRect, y as isRecentFlowVideoGridMetricMode, z as isWipGatedVideoGridMetricMode, x as normalizeVideoGridMetricMode } from './automation-Jf6Isg6G.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';
|
|
@@ -5262,9 +5262,11 @@ declare const pickPreferredLineMetricsRow: (supabase: {
|
|
|
5262
5262
|
* - Aggregates `current_output` and `ideal_output` sum across
|
|
5263
5263
|
* **real-SKU rows only**. Dummy rows contribute 0 — they are skipped
|
|
5264
5264
|
* from that summation set.
|
|
5265
|
-
* - Weighted-average fields (avg_efficiency, avg_cycle_time
|
|
5266
|
-
*
|
|
5267
|
-
*
|
|
5265
|
+
* - Weighted-average fields (avg_efficiency, avg_cycle_time) use per-row
|
|
5266
|
+
* active-minutes as weight; falls back to plain mean when no row has
|
|
5267
|
+
* positive weight.
|
|
5268
|
+
* - `threshold_pph` sums across real rows so it matches the Targets
|
|
5269
|
+
* page/API additive output-family PPH rule.
|
|
5268
5270
|
* - `underperforming_workspaces` is averaged across ACTIVE real rows only
|
|
5269
5271
|
* (real row with `current_output > 0 || ideal_output > 0`), rounded
|
|
5270
5272
|
* half-up to the nearest whole number. Names / UUIDs are deduped unions
|
package/dist/index.js
CHANGED
|
@@ -4665,7 +4665,10 @@ var combineLineMetricsRows = (rows, dummySkuId) => {
|
|
|
4665
4665
|
};
|
|
4666
4666
|
const avgEfficiency = weighted("avg_efficiency");
|
|
4667
4667
|
const avgCycleTime = weighted("avg_cycle_time");
|
|
4668
|
-
const thresholdPph =
|
|
4668
|
+
const thresholdPph = rowsForAggregation.reduce(
|
|
4669
|
+
(acc, row) => acc + (coerceOptionalNumber(row.threshold_pph) ?? 0),
|
|
4670
|
+
0
|
|
4671
|
+
);
|
|
4669
4672
|
const underperformingWorkspaces = activeRealRows.length > 0 ? roundHalfUpInt(
|
|
4670
4673
|
activeRealRows.reduce(
|
|
4671
4674
|
(acc, row) => acc + safeInt(row.underperforming_workspaces),
|
|
@@ -14716,6 +14719,7 @@ var transformMonitorWorkspaceMetrics = ({
|
|
|
14716
14719
|
monitoring_mode: item.monitoring_mode ?? void 0,
|
|
14717
14720
|
idle_time: idleTimeSeconds,
|
|
14718
14721
|
idle_time_hourly: item.idle_time_hourly ?? null,
|
|
14722
|
+
idle_reason_hourly: item.idle_reason_hourly ?? null,
|
|
14719
14723
|
shift_start: item.shift_start ?? void 0,
|
|
14720
14724
|
shift_end: item.shift_end ?? void 0,
|
|
14721
14725
|
assembly_enabled: item.assembly_enabled ?? false,
|
|
@@ -14751,6 +14755,7 @@ var transformMonitorWorkspaceMetrics = ({
|
|
|
14751
14755
|
incoming_wip_current: item.incoming_wip_current ?? null,
|
|
14752
14756
|
incoming_wip_effective_at: item.incoming_wip_effective_at ?? null,
|
|
14753
14757
|
incoming_wip_buffer_name: item.incoming_wip_buffer_name ?? null,
|
|
14758
|
+
video_grid_badges: Array.isArray(item.video_grid_badges) ? item.video_grid_badges : [],
|
|
14754
14759
|
show_exclamation: item.show_exclamation ?? void 0
|
|
14755
14760
|
};
|
|
14756
14761
|
workspaceMetricsStore.setOverview(metric);
|
|
@@ -21269,6 +21274,7 @@ var ICON_CONFIG = {
|
|
|
21269
21274
|
"user-x": lucideReact.UserX,
|
|
21270
21275
|
wrench: lucideReact.Wrench,
|
|
21271
21276
|
activity: lucideReact.Activity,
|
|
21277
|
+
"clipboard-x": lucideReact.ClipboardX,
|
|
21272
21278
|
"help-circle": lucideReact.HelpCircle
|
|
21273
21279
|
};
|
|
21274
21280
|
var humanizeIdleReasonLabel = (value) => {
|
|
@@ -38055,6 +38061,20 @@ var getVideoGridLegendLabel = (workspaces) => {
|
|
|
38055
38061
|
}
|
|
38056
38062
|
return visibleWorkspaces.some(isVideoGridRecentFlowEnabled) ? VIDEO_GRID_LEGEND_LABEL : MAP_GRID_LEGEND_LABEL;
|
|
38057
38063
|
};
|
|
38064
|
+
var getStatusBadgeSignature = (workspace) => {
|
|
38065
|
+
const badges = workspace.video_grid_badges || [];
|
|
38066
|
+
return badges.map((badge) => [
|
|
38067
|
+
badge.kind,
|
|
38068
|
+
badge.label,
|
|
38069
|
+
badge.display_name,
|
|
38070
|
+
badge.palette_token,
|
|
38071
|
+
badge.icon_token,
|
|
38072
|
+
badge.anchor_minute,
|
|
38073
|
+
badge.reason_minute,
|
|
38074
|
+
badge.shift_elapsed_fraction,
|
|
38075
|
+
badge.title
|
|
38076
|
+
].join(":")).join("|");
|
|
38077
|
+
};
|
|
38058
38078
|
function getTrendArrowAndColor(trend) {
|
|
38059
38079
|
if (trend > 0) {
|
|
38060
38080
|
return { arrow: "\u2191", color: "text-green-400" };
|
|
@@ -38086,6 +38106,7 @@ var VideoCard = React144__namespace.default.memo(({
|
|
|
38086
38106
|
}) => {
|
|
38087
38107
|
const videoRef = React144.useRef(null);
|
|
38088
38108
|
const canvasRef = React144.useRef(null);
|
|
38109
|
+
const statusBadgeIdPrefix = React144.useId();
|
|
38089
38110
|
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
38090
38111
|
const { isStale: isStreamStale } = useHlsStreamWithCropping(videoRef, canvasRef, {
|
|
38091
38112
|
src: hlsUrl,
|
|
@@ -38112,6 +38133,7 @@ var VideoCard = React144__namespace.default.memo(({
|
|
|
38112
38133
|
const shouldRenderMetricBadge = hasDisplayMetric;
|
|
38113
38134
|
const badgeTitle = isHighEfficiencyOverride ? `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%` : hasVideoGridRecentFlow(workspace) ? `Flow ${Math.round(videoGridDisplayValue ?? 0)}%` : isRecentFlowCard ? "Flow unavailable" : `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%`;
|
|
38114
38135
|
const badgeLabel = `${Math.round(videoGridDisplayValue ?? 0)}%`;
|
|
38136
|
+
const statusBadges = workspace.video_grid_badges || [];
|
|
38115
38137
|
const efficiencyOverlayClass = videoGridColorState === "green" ? "bg-[#00D654]/25" : videoGridColorState === "blue" ? "bg-[#0EA5E9]/30" : videoGridColorState === "yellow" ? "bg-[#FFD700]/30" : videoGridColorState === "red" ? "bg-[#FF2D0A]/30" : "bg-transparent";
|
|
38116
38138
|
const efficiencyBarClass = videoGridColorState === "green" ? "bg-[#00AB45]" : videoGridColorState === "blue" ? "bg-[#0EA5E9]" : videoGridColorState === "yellow" ? "bg-[#FFB020]" : videoGridColorState === "red" ? "bg-[#E34329]" : "bg-gray-500/70";
|
|
38117
38139
|
const efficiencyStatus = videoGridColorState === "green" ? "High" : videoGridColorState === "blue" ? "Best" : videoGridColorState === "yellow" ? "Medium" : videoGridColorState === "red" ? "Low" : "Neutral";
|
|
@@ -38190,6 +38212,61 @@ var VideoCard = React144__namespace.default.memo(({
|
|
|
38190
38212
|
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: `${compact ? "text-[10px]" : "text-xs"} font-semibold`, children: badgeLabel })
|
|
38191
38213
|
}
|
|
38192
38214
|
) }),
|
|
38215
|
+
statusBadges.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
38216
|
+
"div",
|
|
38217
|
+
{
|
|
38218
|
+
"data-testid": "video-card-status-badges",
|
|
38219
|
+
className: `absolute ${compact ? "top-1.5 left-1.5 gap-1" : "top-2 left-2 gap-1.5"} z-30 flex items-center`,
|
|
38220
|
+
children: statusBadges.map((badge, index) => {
|
|
38221
|
+
const presentation = getIdleReasonPresentation({
|
|
38222
|
+
label: badge.label,
|
|
38223
|
+
displayName: badge.display_name,
|
|
38224
|
+
paletteToken: badge.palette_token,
|
|
38225
|
+
iconToken: badge.icon_token,
|
|
38226
|
+
isKnown: badge.is_known
|
|
38227
|
+
});
|
|
38228
|
+
const Icon2 = presentation.Icon;
|
|
38229
|
+
const tooltipText = presentation.displayName;
|
|
38230
|
+
const tooltipId = `video-card-status-tooltip-${statusBadgeIdPrefix}-${badge.kind}-${index}`;
|
|
38231
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
38232
|
+
"div",
|
|
38233
|
+
{
|
|
38234
|
+
"data-testid": `video-card-status-badge-${badge.kind}`,
|
|
38235
|
+
"aria-label": tooltipText,
|
|
38236
|
+
"aria-describedby": tooltipId,
|
|
38237
|
+
className: `group relative inline-flex shrink-0 items-center justify-center rounded-full bg-slate-950/70 border-2 shadow-[0_3px_10px_rgba(0,0,0,0.34),inset_0_0_0_1px_rgba(255,255,255,0.18)] ${compact ? "h-10 w-10" : "h-11 w-11"}`,
|
|
38238
|
+
style: {
|
|
38239
|
+
borderColor: presentation.hex
|
|
38240
|
+
},
|
|
38241
|
+
children: [
|
|
38242
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
38243
|
+
Icon2,
|
|
38244
|
+
{
|
|
38245
|
+
"aria-hidden": "true",
|
|
38246
|
+
className: `${compact ? "h-5 w-5" : "h-6 w-6"} text-white`,
|
|
38247
|
+
strokeWidth: 2.4
|
|
38248
|
+
}
|
|
38249
|
+
),
|
|
38250
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
38251
|
+
"span",
|
|
38252
|
+
{
|
|
38253
|
+
id: tooltipId,
|
|
38254
|
+
role: "tooltip",
|
|
38255
|
+
"data-testid": `video-card-status-tooltip-${badge.kind}`,
|
|
38256
|
+
className: "pointer-events-none absolute left-0 top-full mt-2 whitespace-nowrap rounded-md border border-white/10 bg-slate-950/95 px-2 py-1 text-[11px] font-semibold leading-none text-white opacity-0 shadow-[0_6px_18px_rgba(0,0,0,0.34)] transition-opacity duration-150 group-hover:opacity-100",
|
|
38257
|
+
children: [
|
|
38258
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-1 left-3 h-2 w-2 rotate-45 border-l border-t border-white/10 bg-slate-950/95" }),
|
|
38259
|
+
tooltipText
|
|
38260
|
+
]
|
|
38261
|
+
}
|
|
38262
|
+
)
|
|
38263
|
+
]
|
|
38264
|
+
},
|
|
38265
|
+
`${badge.kind}-${badge.label || index}-${badge.reason_minute ?? index}`
|
|
38266
|
+
);
|
|
38267
|
+
})
|
|
38268
|
+
}
|
|
38269
|
+
),
|
|
38193
38270
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `absolute bottom-0 left-0 right-0 ${compact ? "h-0.5" : "h-1"} bg-black/50 z-30`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
38194
38271
|
"div",
|
|
38195
38272
|
{
|
|
@@ -38226,7 +38303,7 @@ var VideoCard = React144__namespace.default.memo(({
|
|
|
38226
38303
|
}
|
|
38227
38304
|
);
|
|
38228
38305
|
}, (prevProps, nextProps) => {
|
|
38229
|
-
if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.recent_flow_percent !== nextProps.workspace.recent_flow_percent || prevProps.workspace.recent_flow_effective_end_at !== nextProps.workspace.recent_flow_effective_end_at || prevProps.workspace.recent_flow_forced_zero_after_shift !== nextProps.workspace.recent_flow_forced_zero_after_shift || prevProps.workspace.scheduled_break_active !== nextProps.workspace.scheduled_break_active || prevProps.workspace.incoming_wip_current !== nextProps.workspace.incoming_wip_current || prevProps.workspace.incoming_wip_buffer_name !== nextProps.workspace.incoming_wip_buffer_name || prevProps.workspace.trend !== nextProps.workspace.trend || prevProps.workspace.performance_score !== nextProps.workspace.performance_score || prevProps.workspace.pph !== nextProps.workspace.pph) {
|
|
38306
|
+
if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.recent_flow_percent !== nextProps.workspace.recent_flow_percent || prevProps.workspace.recent_flow_effective_end_at !== nextProps.workspace.recent_flow_effective_end_at || prevProps.workspace.recent_flow_forced_zero_after_shift !== nextProps.workspace.recent_flow_forced_zero_after_shift || prevProps.workspace.scheduled_break_active !== nextProps.workspace.scheduled_break_active || prevProps.workspace.incoming_wip_current !== nextProps.workspace.incoming_wip_current || prevProps.workspace.incoming_wip_buffer_name !== nextProps.workspace.incoming_wip_buffer_name || getStatusBadgeSignature(prevProps.workspace) !== getStatusBadgeSignature(nextProps.workspace) || prevProps.workspace.trend !== nextProps.workspace.trend || prevProps.workspace.performance_score !== nextProps.workspace.performance_score || prevProps.workspace.pph !== nextProps.workspace.pph) {
|
|
38230
38307
|
return false;
|
|
38231
38308
|
}
|
|
38232
38309
|
if (prevProps.workspace.workspace_uuid !== nextProps.workspace.workspace_uuid || prevProps.workspace.workspace_name !== nextProps.workspace.workspace_name || prevProps.workspace.line_id !== nextProps.workspace.line_id) {
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { format, addDays, subMonths, endOfMonth, startOfMonth, endOfDay, eachDayOfInterval, getDay, isSameDay, isWithinInterval, startOfDay, parseISO, subDays, differenceInMinutes, addMinutes, addMonths, isValid, formatDistanceToNow, isToday, isFuture, isBefore } from 'date-fns';
|
|
2
2
|
import { formatInTimeZone, fromZonedTime, toZonedTime } from 'date-fns-tz';
|
|
3
3
|
import * as React144 from 'react';
|
|
4
|
-
import React144__default, { createContext, useRef, useCallback, useState, useMemo, useEffect, forwardRef, useImperativeHandle, useLayoutEffect, memo as memo$1, useContext, useSyncExternalStore,
|
|
4
|
+
import React144__default, { createContext, useRef, useId, useCallback, useState, useMemo, useEffect, forwardRef, useImperativeHandle, useLayoutEffect, memo as memo$1, useContext, useSyncExternalStore, Children, isValidElement, useInsertionEffect, startTransition, Fragment as Fragment$1, createElement, Component } from 'react';
|
|
5
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
import { useRouter } from 'next/router';
|
|
7
7
|
import { toast } from 'sonner';
|
|
@@ -10,7 +10,7 @@ import { EventEmitter } from 'events';
|
|
|
10
10
|
import { createClient, REALTIME_SUBSCRIBE_STATES } from '@supabase/supabase-js';
|
|
11
11
|
import Hls, { Events, ErrorTypes } from 'hls.js';
|
|
12
12
|
import useSWR from 'swr';
|
|
13
|
-
import { Camera, AlertTriangle, ChevronDown, ChevronUp, Check, ShieldCheck, Star, Award, Filter, X, Coffee, Plus, ArrowUp, ArrowDown, ArrowRight,
|
|
13
|
+
import { Camera, AlertTriangle, ChevronDown, ChevronUp, Check, ShieldCheck, Star, Award, Filter, X, Coffee, Plus, ArrowUp, ArrowDown, ArrowRight, HelpCircle, ClipboardX, Activity, Wrench, UserX, Clock, Package, RefreshCw, CheckCircle2, ArrowLeft, Calendar, Save, AlertCircle, Loader2, Minus, ChevronLeft, ChevronRight, TrendingUp, Sparkles, Pause, Play, XCircle, Palette, TrendingDown, FolderOpen, Folder, ArrowDownWideNarrow, Tag, Sliders, Layers, Search, Edit2, CheckCircle, User, Users, Shield, Building2, Mail, Lock, Info, Share2, Trophy, Target, Download, Video, Copy, Sun, Moon, MousePointer, UserPlus, UserCog, Trash2, Eye, MoreVertical, BarChart3, Pencil, UserCheck, LogOut, Film, MessageSquare, Menu, Send, Settings, LifeBuoy, EyeOff, Zap, Flame, Crown, Medal } from 'lucide-react';
|
|
14
14
|
import { memo, noop, warning, invariant, progress, secondsToMilliseconds, millisecondsToSeconds } from 'motion-utils';
|
|
15
15
|
import { BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, ReferenceLine, Tooltip, Legend, Bar, LabelList, ResponsiveContainer, LineChart as LineChart$1, Line, Customized, Cell, PieChart, Pie, ComposedChart, Area, ScatterChart, Scatter } from 'recharts';
|
|
16
16
|
import { Slot } from '@radix-ui/react-slot';
|
|
@@ -4636,7 +4636,10 @@ var combineLineMetricsRows = (rows, dummySkuId) => {
|
|
|
4636
4636
|
};
|
|
4637
4637
|
const avgEfficiency = weighted("avg_efficiency");
|
|
4638
4638
|
const avgCycleTime = weighted("avg_cycle_time");
|
|
4639
|
-
const thresholdPph =
|
|
4639
|
+
const thresholdPph = rowsForAggregation.reduce(
|
|
4640
|
+
(acc, row) => acc + (coerceOptionalNumber(row.threshold_pph) ?? 0),
|
|
4641
|
+
0
|
|
4642
|
+
);
|
|
4640
4643
|
const underperformingWorkspaces = activeRealRows.length > 0 ? roundHalfUpInt(
|
|
4641
4644
|
activeRealRows.reduce(
|
|
4642
4645
|
(acc, row) => acc + safeInt(row.underperforming_workspaces),
|
|
@@ -14687,6 +14690,7 @@ var transformMonitorWorkspaceMetrics = ({
|
|
|
14687
14690
|
monitoring_mode: item.monitoring_mode ?? void 0,
|
|
14688
14691
|
idle_time: idleTimeSeconds,
|
|
14689
14692
|
idle_time_hourly: item.idle_time_hourly ?? null,
|
|
14693
|
+
idle_reason_hourly: item.idle_reason_hourly ?? null,
|
|
14690
14694
|
shift_start: item.shift_start ?? void 0,
|
|
14691
14695
|
shift_end: item.shift_end ?? void 0,
|
|
14692
14696
|
assembly_enabled: item.assembly_enabled ?? false,
|
|
@@ -14722,6 +14726,7 @@ var transformMonitorWorkspaceMetrics = ({
|
|
|
14722
14726
|
incoming_wip_current: item.incoming_wip_current ?? null,
|
|
14723
14727
|
incoming_wip_effective_at: item.incoming_wip_effective_at ?? null,
|
|
14724
14728
|
incoming_wip_buffer_name: item.incoming_wip_buffer_name ?? null,
|
|
14729
|
+
video_grid_badges: Array.isArray(item.video_grid_badges) ? item.video_grid_badges : [],
|
|
14725
14730
|
show_exclamation: item.show_exclamation ?? void 0
|
|
14726
14731
|
};
|
|
14727
14732
|
workspaceMetricsStore.setOverview(metric);
|
|
@@ -21240,6 +21245,7 @@ var ICON_CONFIG = {
|
|
|
21240
21245
|
"user-x": UserX,
|
|
21241
21246
|
wrench: Wrench,
|
|
21242
21247
|
activity: Activity,
|
|
21248
|
+
"clipboard-x": ClipboardX,
|
|
21243
21249
|
"help-circle": HelpCircle
|
|
21244
21250
|
};
|
|
21245
21251
|
var humanizeIdleReasonLabel = (value) => {
|
|
@@ -38026,6 +38032,20 @@ var getVideoGridLegendLabel = (workspaces) => {
|
|
|
38026
38032
|
}
|
|
38027
38033
|
return visibleWorkspaces.some(isVideoGridRecentFlowEnabled) ? VIDEO_GRID_LEGEND_LABEL : MAP_GRID_LEGEND_LABEL;
|
|
38028
38034
|
};
|
|
38035
|
+
var getStatusBadgeSignature = (workspace) => {
|
|
38036
|
+
const badges = workspace.video_grid_badges || [];
|
|
38037
|
+
return badges.map((badge) => [
|
|
38038
|
+
badge.kind,
|
|
38039
|
+
badge.label,
|
|
38040
|
+
badge.display_name,
|
|
38041
|
+
badge.palette_token,
|
|
38042
|
+
badge.icon_token,
|
|
38043
|
+
badge.anchor_minute,
|
|
38044
|
+
badge.reason_minute,
|
|
38045
|
+
badge.shift_elapsed_fraction,
|
|
38046
|
+
badge.title
|
|
38047
|
+
].join(":")).join("|");
|
|
38048
|
+
};
|
|
38029
38049
|
function getTrendArrowAndColor(trend) {
|
|
38030
38050
|
if (trend > 0) {
|
|
38031
38051
|
return { arrow: "\u2191", color: "text-green-400" };
|
|
@@ -38057,6 +38077,7 @@ var VideoCard = React144__default.memo(({
|
|
|
38057
38077
|
}) => {
|
|
38058
38078
|
const videoRef = useRef(null);
|
|
38059
38079
|
const canvasRef = useRef(null);
|
|
38080
|
+
const statusBadgeIdPrefix = useId();
|
|
38060
38081
|
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
38061
38082
|
const { isStale: isStreamStale } = useHlsStreamWithCropping(videoRef, canvasRef, {
|
|
38062
38083
|
src: hlsUrl,
|
|
@@ -38083,6 +38104,7 @@ var VideoCard = React144__default.memo(({
|
|
|
38083
38104
|
const shouldRenderMetricBadge = hasDisplayMetric;
|
|
38084
38105
|
const badgeTitle = isHighEfficiencyOverride ? `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%` : hasVideoGridRecentFlow(workspace) ? `Flow ${Math.round(videoGridDisplayValue ?? 0)}%` : isRecentFlowCard ? "Flow unavailable" : `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%`;
|
|
38085
38106
|
const badgeLabel = `${Math.round(videoGridDisplayValue ?? 0)}%`;
|
|
38107
|
+
const statusBadges = workspace.video_grid_badges || [];
|
|
38086
38108
|
const efficiencyOverlayClass = videoGridColorState === "green" ? "bg-[#00D654]/25" : videoGridColorState === "blue" ? "bg-[#0EA5E9]/30" : videoGridColorState === "yellow" ? "bg-[#FFD700]/30" : videoGridColorState === "red" ? "bg-[#FF2D0A]/30" : "bg-transparent";
|
|
38087
38109
|
const efficiencyBarClass = videoGridColorState === "green" ? "bg-[#00AB45]" : videoGridColorState === "blue" ? "bg-[#0EA5E9]" : videoGridColorState === "yellow" ? "bg-[#FFB020]" : videoGridColorState === "red" ? "bg-[#E34329]" : "bg-gray-500/70";
|
|
38088
38110
|
const efficiencyStatus = videoGridColorState === "green" ? "High" : videoGridColorState === "blue" ? "Best" : videoGridColorState === "yellow" ? "Medium" : videoGridColorState === "red" ? "Low" : "Neutral";
|
|
@@ -38161,6 +38183,61 @@ var VideoCard = React144__default.memo(({
|
|
|
38161
38183
|
children: /* @__PURE__ */ jsx("span", { className: `${compact ? "text-[10px]" : "text-xs"} font-semibold`, children: badgeLabel })
|
|
38162
38184
|
}
|
|
38163
38185
|
) }),
|
|
38186
|
+
statusBadges.length > 0 && /* @__PURE__ */ jsx(
|
|
38187
|
+
"div",
|
|
38188
|
+
{
|
|
38189
|
+
"data-testid": "video-card-status-badges",
|
|
38190
|
+
className: `absolute ${compact ? "top-1.5 left-1.5 gap-1" : "top-2 left-2 gap-1.5"} z-30 flex items-center`,
|
|
38191
|
+
children: statusBadges.map((badge, index) => {
|
|
38192
|
+
const presentation = getIdleReasonPresentation({
|
|
38193
|
+
label: badge.label,
|
|
38194
|
+
displayName: badge.display_name,
|
|
38195
|
+
paletteToken: badge.palette_token,
|
|
38196
|
+
iconToken: badge.icon_token,
|
|
38197
|
+
isKnown: badge.is_known
|
|
38198
|
+
});
|
|
38199
|
+
const Icon2 = presentation.Icon;
|
|
38200
|
+
const tooltipText = presentation.displayName;
|
|
38201
|
+
const tooltipId = `video-card-status-tooltip-${statusBadgeIdPrefix}-${badge.kind}-${index}`;
|
|
38202
|
+
return /* @__PURE__ */ jsxs(
|
|
38203
|
+
"div",
|
|
38204
|
+
{
|
|
38205
|
+
"data-testid": `video-card-status-badge-${badge.kind}`,
|
|
38206
|
+
"aria-label": tooltipText,
|
|
38207
|
+
"aria-describedby": tooltipId,
|
|
38208
|
+
className: `group relative inline-flex shrink-0 items-center justify-center rounded-full bg-slate-950/70 border-2 shadow-[0_3px_10px_rgba(0,0,0,0.34),inset_0_0_0_1px_rgba(255,255,255,0.18)] ${compact ? "h-10 w-10" : "h-11 w-11"}`,
|
|
38209
|
+
style: {
|
|
38210
|
+
borderColor: presentation.hex
|
|
38211
|
+
},
|
|
38212
|
+
children: [
|
|
38213
|
+
/* @__PURE__ */ jsx(
|
|
38214
|
+
Icon2,
|
|
38215
|
+
{
|
|
38216
|
+
"aria-hidden": "true",
|
|
38217
|
+
className: `${compact ? "h-5 w-5" : "h-6 w-6"} text-white`,
|
|
38218
|
+
strokeWidth: 2.4
|
|
38219
|
+
}
|
|
38220
|
+
),
|
|
38221
|
+
/* @__PURE__ */ jsxs(
|
|
38222
|
+
"span",
|
|
38223
|
+
{
|
|
38224
|
+
id: tooltipId,
|
|
38225
|
+
role: "tooltip",
|
|
38226
|
+
"data-testid": `video-card-status-tooltip-${badge.kind}`,
|
|
38227
|
+
className: "pointer-events-none absolute left-0 top-full mt-2 whitespace-nowrap rounded-md border border-white/10 bg-slate-950/95 px-2 py-1 text-[11px] font-semibold leading-none text-white opacity-0 shadow-[0_6px_18px_rgba(0,0,0,0.34)] transition-opacity duration-150 group-hover:opacity-100",
|
|
38228
|
+
children: [
|
|
38229
|
+
/* @__PURE__ */ jsx("span", { className: "absolute -top-1 left-3 h-2 w-2 rotate-45 border-l border-t border-white/10 bg-slate-950/95" }),
|
|
38230
|
+
tooltipText
|
|
38231
|
+
]
|
|
38232
|
+
}
|
|
38233
|
+
)
|
|
38234
|
+
]
|
|
38235
|
+
},
|
|
38236
|
+
`${badge.kind}-${badge.label || index}-${badge.reason_minute ?? index}`
|
|
38237
|
+
);
|
|
38238
|
+
})
|
|
38239
|
+
}
|
|
38240
|
+
),
|
|
38164
38241
|
/* @__PURE__ */ jsx("div", { className: `absolute bottom-0 left-0 right-0 ${compact ? "h-0.5" : "h-1"} bg-black/50 z-30`, children: /* @__PURE__ */ jsx(
|
|
38165
38242
|
"div",
|
|
38166
38243
|
{
|
|
@@ -38197,7 +38274,7 @@ var VideoCard = React144__default.memo(({
|
|
|
38197
38274
|
}
|
|
38198
38275
|
);
|
|
38199
38276
|
}, (prevProps, nextProps) => {
|
|
38200
|
-
if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.recent_flow_percent !== nextProps.workspace.recent_flow_percent || prevProps.workspace.recent_flow_effective_end_at !== nextProps.workspace.recent_flow_effective_end_at || prevProps.workspace.recent_flow_forced_zero_after_shift !== nextProps.workspace.recent_flow_forced_zero_after_shift || prevProps.workspace.scheduled_break_active !== nextProps.workspace.scheduled_break_active || prevProps.workspace.incoming_wip_current !== nextProps.workspace.incoming_wip_current || prevProps.workspace.incoming_wip_buffer_name !== nextProps.workspace.incoming_wip_buffer_name || prevProps.workspace.trend !== nextProps.workspace.trend || prevProps.workspace.performance_score !== nextProps.workspace.performance_score || prevProps.workspace.pph !== nextProps.workspace.pph) {
|
|
38277
|
+
if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.recent_flow_percent !== nextProps.workspace.recent_flow_percent || prevProps.workspace.recent_flow_effective_end_at !== nextProps.workspace.recent_flow_effective_end_at || prevProps.workspace.recent_flow_forced_zero_after_shift !== nextProps.workspace.recent_flow_forced_zero_after_shift || prevProps.workspace.scheduled_break_active !== nextProps.workspace.scheduled_break_active || prevProps.workspace.incoming_wip_current !== nextProps.workspace.incoming_wip_current || prevProps.workspace.incoming_wip_buffer_name !== nextProps.workspace.incoming_wip_buffer_name || getStatusBadgeSignature(prevProps.workspace) !== getStatusBadgeSignature(nextProps.workspace) || prevProps.workspace.trend !== nextProps.workspace.trend || prevProps.workspace.performance_score !== nextProps.workspace.performance_score || prevProps.workspace.pph !== nextProps.workspace.pph) {
|
|
38201
38278
|
return false;
|
|
38202
38279
|
}
|
|
38203
38280
|
if (prevProps.workspace.workspace_uuid !== nextProps.workspace.workspace_uuid || prevProps.workspace.workspace_name !== nextProps.workspace.workspace_name || prevProps.workspace.line_id !== nextProps.workspace.line_id) {
|