@optifye/dashboard-core 6.12.16 → 6.12.18

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.
@@ -1896,6 +1896,7 @@ var VideoCard = React__default.default.memo(({
1896
1896
  displayMinuteBucket,
1897
1897
  displayName,
1898
1898
  lastSeenLabel,
1899
+ hasRecentHealthSignal = false,
1899
1900
  onMouseEnter,
1900
1901
  onMouseLeave
1901
1902
  }) => {
@@ -1910,7 +1911,7 @@ var VideoCard = React__default.default.memo(({
1910
1911
  useRAF,
1911
1912
  onFatalError: onFatalError ?? (() => throttledReloadDashboard())
1912
1913
  });
1913
- const showOffline = Boolean(isStreamStale);
1914
+ const showOffline = Boolean(isStreamStale && !hasRecentHealthSignal);
1914
1915
  const lastSeenText = lastSeenLabel || "Unknown";
1915
1916
  const workspaceDisplayName = displayName || workspace.displayName || workspace.workspace_name;
1916
1917
  const videoGridMetricValue = getVideoGridMetricValue(workspace, effectiveLegend);
@@ -2050,6 +2051,9 @@ var VideoCard = React__default.default.memo(({
2050
2051
  if (prevProps.lastSeenLabel !== nextProps.lastSeenLabel) {
2051
2052
  return false;
2052
2053
  }
2054
+ if (prevProps.hasRecentHealthSignal !== nextProps.hasRecentHealthSignal) {
2055
+ return false;
2056
+ }
2053
2057
  if (prevProps.legend !== nextProps.legend) {
2054
2058
  return false;
2055
2059
  }
@@ -1889,6 +1889,7 @@ var VideoCard = React.memo(({
1889
1889
  displayMinuteBucket,
1890
1890
  displayName,
1891
1891
  lastSeenLabel,
1892
+ hasRecentHealthSignal = false,
1892
1893
  onMouseEnter,
1893
1894
  onMouseLeave
1894
1895
  }) => {
@@ -1903,7 +1904,7 @@ var VideoCard = React.memo(({
1903
1904
  useRAF,
1904
1905
  onFatalError: onFatalError ?? (() => throttledReloadDashboard())
1905
1906
  });
1906
- const showOffline = Boolean(isStreamStale);
1907
+ const showOffline = Boolean(isStreamStale && !hasRecentHealthSignal);
1907
1908
  const lastSeenText = lastSeenLabel || "Unknown";
1908
1909
  const workspaceDisplayName = displayName || workspace.displayName || workspace.workspace_name;
1909
1910
  const videoGridMetricValue = getVideoGridMetricValue(workspace, effectiveLegend);
@@ -2043,6 +2044,9 @@ var VideoCard = React.memo(({
2043
2044
  if (prevProps.lastSeenLabel !== nextProps.lastSeenLabel) {
2044
2045
  return false;
2045
2046
  }
2047
+ if (prevProps.hasRecentHealthSignal !== nextProps.hasRecentHealthSignal) {
2048
+ return false;
2049
+ }
2046
2050
  if (prevProps.legend !== nextProps.legend) {
2047
2051
  return false;
2048
2052
  }
package/dist/index.d.mts CHANGED
@@ -8576,6 +8576,7 @@ interface VideoCardProps {
8576
8576
  displayMinuteBucket?: number;
8577
8577
  displayName?: string;
8578
8578
  lastSeenLabel?: string;
8579
+ hasRecentHealthSignal?: boolean;
8579
8580
  onMouseEnter?: () => void;
8580
8581
  onMouseLeave?: () => void;
8581
8582
  }
package/dist/index.d.ts CHANGED
@@ -8576,6 +8576,7 @@ interface VideoCardProps {
8576
8576
  displayMinuteBucket?: number;
8577
8577
  displayName?: string;
8578
8578
  lastSeenLabel?: string;
8579
+ hasRecentHealthSignal?: boolean;
8579
8580
  onMouseEnter?: () => void;
8580
8581
  onMouseLeave?: () => void;
8581
8582
  }
package/dist/index.js CHANGED
@@ -37604,6 +37604,7 @@ var VideoCard = React144__namespace.default.memo(({
37604
37604
  displayMinuteBucket,
37605
37605
  displayName,
37606
37606
  lastSeenLabel,
37607
+ hasRecentHealthSignal: hasRecentHealthSignal2 = false,
37607
37608
  onMouseEnter,
37608
37609
  onMouseLeave
37609
37610
  }) => {
@@ -37618,7 +37619,7 @@ var VideoCard = React144__namespace.default.memo(({
37618
37619
  useRAF,
37619
37620
  onFatalError: onFatalError ?? (() => throttledReloadDashboard())
37620
37621
  });
37621
- const showOffline = Boolean(isStreamStale);
37622
+ const showOffline = Boolean(isStreamStale && !hasRecentHealthSignal2);
37622
37623
  const lastSeenText = lastSeenLabel || "Unknown";
37623
37624
  const workspaceDisplayName = displayName || workspace.displayName || workspace.workspace_name;
37624
37625
  const videoGridMetricValue = getVideoGridMetricValue(workspace, effectiveLegend);
@@ -37758,6 +37759,9 @@ var VideoCard = React144__namespace.default.memo(({
37758
37759
  if (prevProps.lastSeenLabel !== nextProps.lastSeenLabel) {
37759
37760
  return false;
37760
37761
  }
37762
+ if (prevProps.hasRecentHealthSignal !== nextProps.hasRecentHealthSignal) {
37763
+ return false;
37764
+ }
37761
37765
  if (prevProps.legend !== nextProps.legend) {
37762
37766
  return false;
37763
37767
  }
@@ -37780,10 +37784,17 @@ var DEFAULT_HLS_URL = "https://192.168.5.9:8443/cam1.m3u8";
37780
37784
  var DEBUG_DASHBOARD_LOGS2 = process.env.NEXT_PUBLIC_DEBUG_DASHBOARD === "true";
37781
37785
  var MOBILE_SCROLL_THRESHOLD = 15;
37782
37786
  var MOBILE_BREAKPOINT_PX = 640;
37787
+ var RECENT_HEALTH_SIGNAL_MS = 3 * 60 * 1e3;
37783
37788
  var logDebug2 = (...args) => {
37784
37789
  if (!DEBUG_DASHBOARD_LOGS2) return;
37785
37790
  console.log(...args);
37786
37791
  };
37792
+ var hasRecentHealthSignal = (lastHeartbeat) => {
37793
+ if (!lastHeartbeat) return false;
37794
+ const heartbeatMs = new Date(lastHeartbeat).getTime();
37795
+ if (!Number.isFinite(heartbeatMs)) return false;
37796
+ return Date.now() - heartbeatMs <= RECENT_HEALTH_SIGNAL_MS;
37797
+ };
37787
37798
  var VideoGridView = React144__namespace.default.memo(({
37788
37799
  workspaces,
37789
37800
  selectedLine,
@@ -37811,10 +37822,16 @@ var VideoGridView = React144__namespace.default.memo(({
37811
37822
  const ids = workspaces.map((ws) => ws.workspace_uuid || ws.workspace_name);
37812
37823
  return ids.sort().join(",");
37813
37824
  }, [workspaces]);
37825
+ const [resolvedStreamWorkspaceKey, setResolvedStreamWorkspaceKey] = React144.useState(() => videoStreamsLoading ? null : workspaceIdsKey);
37814
37826
  React144.useEffect(() => {
37815
37827
  setFailedStreams(/* @__PURE__ */ new Set());
37816
37828
  setR2FallbackWorkspaces(/* @__PURE__ */ new Set());
37817
37829
  }, [workspaceIdsKey]);
37830
+ React144.useEffect(() => {
37831
+ if (!videoStreamsLoading) {
37832
+ setResolvedStreamWorkspaceKey(workspaceIdsKey);
37833
+ }
37834
+ }, [videoStreamsLoading, workspaceIdsKey]);
37818
37835
  const videoConfig = useVideoConfig();
37819
37836
  const dashboardConfig = useDashboardConfig();
37820
37837
  const timezone = useAppTimezone();
@@ -37908,7 +37925,7 @@ var VideoGridView = React144__namespace.default.memo(({
37908
37925
  return a.workspace_name.localeCompare(b.workspace_name);
37909
37926
  });
37910
37927
  }, [filteredWorkspaces]);
37911
- const streamsReady = !videoStreamsLoading;
37928
+ const streamsResolvedForWorkspaceSet = resolvedStreamWorkspaceKey === workspaceIdsKey;
37912
37929
  const resolveWorkspaceDisplayName = React144.useCallback((workspace) => {
37913
37930
  return workspace.displayName || displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || workspace.workspace_name;
37914
37931
  }, [displayNames]);
@@ -38095,11 +38112,12 @@ var VideoGridView = React144__namespace.default.memo(({
38095
38112
  const isVisible = visibleWorkspaces.has(workspaceId);
38096
38113
  const workspaceCropping = getWorkspaceCropping(workspaceId, workspace.workspace_name);
38097
38114
  const workspaceStream = videoStreamsByWorkspaceId?.[workspaceId];
38098
- const lastSeenLabel = workspace.workspace_uuid ? lastSeenByWorkspaceId[workspace.workspace_uuid]?.timeSinceLastUpdate : void 0;
38115
+ const workspaceHealth = workspace.workspace_uuid ? lastSeenByWorkspaceId[workspace.workspace_uuid] : void 0;
38116
+ const lastSeenLabel = workspaceHealth?.timeSinceLastUpdate;
38099
38117
  const r2Url = workspaceStream?.hls_url;
38100
38118
  const fallbackUrl = getWorkspaceHlsUrl(workspace.workspace_name, workspace.line_id);
38101
38119
  const hasR2Stream = Boolean(r2Url);
38102
- const useFallback = r2FallbackWorkspaces.has(workspaceId) || streamsReady && !hasR2Stream;
38120
+ const useFallback = r2FallbackWorkspaces.has(workspaceId) || streamsResolvedForWorkspaceSet && !hasR2Stream;
38103
38121
  const hlsUrl = useFallback ? fallbackUrl : r2Url ?? "";
38104
38122
  const isR2Stream = !useFallback && hasR2Stream;
38105
38123
  const canAttemptR2 = hasR2Stream && !r2FallbackWorkspaces.has(workspaceId);
@@ -38114,7 +38132,8 @@ var VideoGridView = React144__namespace.default.memo(({
38114
38132
  hlsUrl,
38115
38133
  isR2Stream,
38116
38134
  shouldPlay,
38117
- lastSeenLabel
38135
+ lastSeenLabel,
38136
+ hasRecentHealthSignal: hasRecentHealthSignal(workspaceHealth?.lastHeartbeat)
38118
38137
  };
38119
38138
  });
38120
38139
  }, [
@@ -38125,7 +38144,7 @@ var VideoGridView = React144__namespace.default.memo(({
38125
38144
  lastSeenByWorkspaceId,
38126
38145
  getWorkspaceHlsUrl,
38127
38146
  r2FallbackWorkspaces,
38128
- streamsReady,
38147
+ streamsResolvedForWorkspaceSet,
38129
38148
  failedStreams
38130
38149
  ]);
38131
38150
  const croppedActiveCount = React144.useMemo(() => {
@@ -38161,6 +38180,7 @@ var VideoGridView = React144__namespace.default.memo(({
38161
38180
  canvasFps: effectiveCanvasFps,
38162
38181
  displayName: resolveWorkspaceDisplayName(card.workspace),
38163
38182
  lastSeenLabel: card.lastSeenLabel,
38183
+ hasRecentHealthSignal: card.hasRecentHealthSignal,
38164
38184
  useRAF: effectiveUseRAF,
38165
38185
  displayMinuteBucket,
38166
38186
  compact: !selectedLine,
package/dist/index.mjs CHANGED
@@ -37575,6 +37575,7 @@ var VideoCard = React144__default.memo(({
37575
37575
  displayMinuteBucket,
37576
37576
  displayName,
37577
37577
  lastSeenLabel,
37578
+ hasRecentHealthSignal: hasRecentHealthSignal2 = false,
37578
37579
  onMouseEnter,
37579
37580
  onMouseLeave
37580
37581
  }) => {
@@ -37589,7 +37590,7 @@ var VideoCard = React144__default.memo(({
37589
37590
  useRAF,
37590
37591
  onFatalError: onFatalError ?? (() => throttledReloadDashboard())
37591
37592
  });
37592
- const showOffline = Boolean(isStreamStale);
37593
+ const showOffline = Boolean(isStreamStale && !hasRecentHealthSignal2);
37593
37594
  const lastSeenText = lastSeenLabel || "Unknown";
37594
37595
  const workspaceDisplayName = displayName || workspace.displayName || workspace.workspace_name;
37595
37596
  const videoGridMetricValue = getVideoGridMetricValue(workspace, effectiveLegend);
@@ -37729,6 +37730,9 @@ var VideoCard = React144__default.memo(({
37729
37730
  if (prevProps.lastSeenLabel !== nextProps.lastSeenLabel) {
37730
37731
  return false;
37731
37732
  }
37733
+ if (prevProps.hasRecentHealthSignal !== nextProps.hasRecentHealthSignal) {
37734
+ return false;
37735
+ }
37732
37736
  if (prevProps.legend !== nextProps.legend) {
37733
37737
  return false;
37734
37738
  }
@@ -37751,10 +37755,17 @@ var DEFAULT_HLS_URL = "https://192.168.5.9:8443/cam1.m3u8";
37751
37755
  var DEBUG_DASHBOARD_LOGS2 = process.env.NEXT_PUBLIC_DEBUG_DASHBOARD === "true";
37752
37756
  var MOBILE_SCROLL_THRESHOLD = 15;
37753
37757
  var MOBILE_BREAKPOINT_PX = 640;
37758
+ var RECENT_HEALTH_SIGNAL_MS = 3 * 60 * 1e3;
37754
37759
  var logDebug2 = (...args) => {
37755
37760
  if (!DEBUG_DASHBOARD_LOGS2) return;
37756
37761
  console.log(...args);
37757
37762
  };
37763
+ var hasRecentHealthSignal = (lastHeartbeat) => {
37764
+ if (!lastHeartbeat) return false;
37765
+ const heartbeatMs = new Date(lastHeartbeat).getTime();
37766
+ if (!Number.isFinite(heartbeatMs)) return false;
37767
+ return Date.now() - heartbeatMs <= RECENT_HEALTH_SIGNAL_MS;
37768
+ };
37758
37769
  var VideoGridView = React144__default.memo(({
37759
37770
  workspaces,
37760
37771
  selectedLine,
@@ -37782,10 +37793,16 @@ var VideoGridView = React144__default.memo(({
37782
37793
  const ids = workspaces.map((ws) => ws.workspace_uuid || ws.workspace_name);
37783
37794
  return ids.sort().join(",");
37784
37795
  }, [workspaces]);
37796
+ const [resolvedStreamWorkspaceKey, setResolvedStreamWorkspaceKey] = useState(() => videoStreamsLoading ? null : workspaceIdsKey);
37785
37797
  useEffect(() => {
37786
37798
  setFailedStreams(/* @__PURE__ */ new Set());
37787
37799
  setR2FallbackWorkspaces(/* @__PURE__ */ new Set());
37788
37800
  }, [workspaceIdsKey]);
37801
+ useEffect(() => {
37802
+ if (!videoStreamsLoading) {
37803
+ setResolvedStreamWorkspaceKey(workspaceIdsKey);
37804
+ }
37805
+ }, [videoStreamsLoading, workspaceIdsKey]);
37789
37806
  const videoConfig = useVideoConfig();
37790
37807
  const dashboardConfig = useDashboardConfig();
37791
37808
  const timezone = useAppTimezone();
@@ -37879,7 +37896,7 @@ var VideoGridView = React144__default.memo(({
37879
37896
  return a.workspace_name.localeCompare(b.workspace_name);
37880
37897
  });
37881
37898
  }, [filteredWorkspaces]);
37882
- const streamsReady = !videoStreamsLoading;
37899
+ const streamsResolvedForWorkspaceSet = resolvedStreamWorkspaceKey === workspaceIdsKey;
37883
37900
  const resolveWorkspaceDisplayName = useCallback((workspace) => {
37884
37901
  return workspace.displayName || displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || workspace.workspace_name;
37885
37902
  }, [displayNames]);
@@ -38066,11 +38083,12 @@ var VideoGridView = React144__default.memo(({
38066
38083
  const isVisible = visibleWorkspaces.has(workspaceId);
38067
38084
  const workspaceCropping = getWorkspaceCropping(workspaceId, workspace.workspace_name);
38068
38085
  const workspaceStream = videoStreamsByWorkspaceId?.[workspaceId];
38069
- const lastSeenLabel = workspace.workspace_uuid ? lastSeenByWorkspaceId[workspace.workspace_uuid]?.timeSinceLastUpdate : void 0;
38086
+ const workspaceHealth = workspace.workspace_uuid ? lastSeenByWorkspaceId[workspace.workspace_uuid] : void 0;
38087
+ const lastSeenLabel = workspaceHealth?.timeSinceLastUpdate;
38070
38088
  const r2Url = workspaceStream?.hls_url;
38071
38089
  const fallbackUrl = getWorkspaceHlsUrl(workspace.workspace_name, workspace.line_id);
38072
38090
  const hasR2Stream = Boolean(r2Url);
38073
- const useFallback = r2FallbackWorkspaces.has(workspaceId) || streamsReady && !hasR2Stream;
38091
+ const useFallback = r2FallbackWorkspaces.has(workspaceId) || streamsResolvedForWorkspaceSet && !hasR2Stream;
38074
38092
  const hlsUrl = useFallback ? fallbackUrl : r2Url ?? "";
38075
38093
  const isR2Stream = !useFallback && hasR2Stream;
38076
38094
  const canAttemptR2 = hasR2Stream && !r2FallbackWorkspaces.has(workspaceId);
@@ -38085,7 +38103,8 @@ var VideoGridView = React144__default.memo(({
38085
38103
  hlsUrl,
38086
38104
  isR2Stream,
38087
38105
  shouldPlay,
38088
- lastSeenLabel
38106
+ lastSeenLabel,
38107
+ hasRecentHealthSignal: hasRecentHealthSignal(workspaceHealth?.lastHeartbeat)
38089
38108
  };
38090
38109
  });
38091
38110
  }, [
@@ -38096,7 +38115,7 @@ var VideoGridView = React144__default.memo(({
38096
38115
  lastSeenByWorkspaceId,
38097
38116
  getWorkspaceHlsUrl,
38098
38117
  r2FallbackWorkspaces,
38099
- streamsReady,
38118
+ streamsResolvedForWorkspaceSet,
38100
38119
  failedStreams
38101
38120
  ]);
38102
38121
  const croppedActiveCount = useMemo(() => {
@@ -38132,6 +38151,7 @@ var VideoGridView = React144__default.memo(({
38132
38151
  canvasFps: effectiveCanvasFps,
38133
38152
  displayName: resolveWorkspaceDisplayName(card.workspace),
38134
38153
  lastSeenLabel: card.lastSeenLabel,
38154
+ hasRecentHealthSignal: card.hasRecentHealthSignal,
38135
38155
  useRAF: effectiveUseRAF,
38136
38156
  displayMinuteBucket,
38137
38157
  compact: !selectedLine,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optifye/dashboard-core",
3
- "version": "6.12.16",
3
+ "version": "6.12.18",
4
4
  "description": "Reusable UI & logic for Optifye dashboard",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",