@optifye/dashboard-core 6.5.0 → 6.5.2

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/index.js CHANGED
@@ -3286,35 +3286,6 @@ var useAudioService = () => {
3286
3286
  };
3287
3287
 
3288
3288
  // src/lib/utils/dateShiftUtils.ts
3289
- function getOperationalDate2(timezone = "Asia/Kolkata") {
3290
- const now2 = /* @__PURE__ */ new Date();
3291
- const localTime = new Date(now2.toLocaleString("en-US", { timeZone: timezone }));
3292
- const hour = localTime.getHours();
3293
- if (hour < 6) {
3294
- localTime.setDate(localTime.getDate() - 1);
3295
- }
3296
- return localTime.toISOString().split("T")[0];
3297
- }
3298
- function getCurrentShift2(timezone = "Asia/Kolkata") {
3299
- const now2 = /* @__PURE__ */ new Date();
3300
- const localTime = new Date(now2.toLocaleString("en-US", { timeZone: timezone }));
3301
- const hour = localTime.getHours();
3302
- if (hour >= 6 && hour < 18) {
3303
- return {
3304
- shiftId: 0,
3305
- shiftName: "Day Shift",
3306
- startTime: "06:00",
3307
- endTime: "18:00"
3308
- };
3309
- } else {
3310
- return {
3311
- shiftId: 1,
3312
- shiftName: "Night Shift",
3313
- startTime: "18:00",
3314
- endTime: "06:00"
3315
- };
3316
- }
3317
- }
3318
3289
  function isValidDateFormat(date) {
3319
3290
  return /^\d{4}-\d{2}-\d{2}$/.test(date);
3320
3291
  }
@@ -4181,6 +4152,23 @@ var S3ClipsAPIClient = class {
4181
4152
  };
4182
4153
  });
4183
4154
  }
4155
+ /**
4156
+ * Batch fetch multiple videos in parallel
4157
+ */
4158
+ async batchFetchVideos(workspaceId, date, shiftId, requests) {
4159
+ const batchKey = `batch:${workspaceId}:${date}:${shiftId}:${requests.length}`;
4160
+ return this.deduplicate(batchKey, async () => {
4161
+ const response = await this.fetchWithAuth("/api/clips/batch", {
4162
+ workspaceId,
4163
+ date,
4164
+ shift: shiftId.toString(),
4165
+ requests,
4166
+ sopCategories: this.sopCategories
4167
+ });
4168
+ console.log(`[S3ClipsAPIClient] Batch fetched ${response.videos.length} videos in ${response.performance.duration}ms`);
4169
+ return response.videos;
4170
+ });
4171
+ }
4184
4172
  /**
4185
4173
  * Convert S3 URI to CloudFront URL
4186
4174
  * In the API client, URLs are already signed from the server
@@ -4428,7 +4416,11 @@ var S3ClipsService = class {
4428
4416
  if (!workspaceId) {
4429
4417
  throw new Error("Valid Workspace ID is required");
4430
4418
  }
4431
- const date = inputDate || getOperationalDate2(this.config.dateTimeConfig?.defaultTimezone);
4419
+ const date = inputDate || getOperationalDate(
4420
+ this.config.dateTimeConfig?.defaultTimezone || "Asia/Kolkata",
4421
+ /* @__PURE__ */ new Date(),
4422
+ this.config.shiftConfig?.dayShift?.startTime || "06:00"
4423
+ );
4432
4424
  if (!isValidDateFormat(date)) {
4433
4425
  throw new Error("Invalid date format. Use YYYY-MM-DD.");
4434
4426
  }
@@ -4439,7 +4431,10 @@ var S3ClipsService = class {
4439
4431
  }
4440
4432
  shiftId = parseInt(shift, 10);
4441
4433
  } else {
4442
- const { shiftId: currentShiftId } = getCurrentShift2(this.config.dateTimeConfig?.defaultTimezone);
4434
+ const { shiftId: currentShiftId } = getCurrentShift(
4435
+ this.config.dateTimeConfig?.defaultTimezone || "Asia/Kolkata",
4436
+ this.config.shiftConfig
4437
+ );
4443
4438
  shiftId = currentShiftId;
4444
4439
  }
4445
4440
  console.log(`[S3ClipsService] Fetching clips for workspace ${workspaceId}`);
@@ -4457,6 +4452,23 @@ var S3ClipsService = class {
4457
4452
  );
4458
4453
  return result.videos;
4459
4454
  }
4455
+ /**
4456
+ * Batch fetch multiple videos in parallel
4457
+ */
4458
+ async batchFetchVideos(workspaceId, date, shiftId, requests) {
4459
+ try {
4460
+ const results = await this.apiClient.batchFetchVideos(
4461
+ workspaceId,
4462
+ date,
4463
+ shiftId,
4464
+ requests
4465
+ );
4466
+ return results.map((r2) => r2.video).filter((v) => v !== null);
4467
+ } catch (error) {
4468
+ console.error("[S3ClipsService] Error batch fetching videos:", error);
4469
+ return [];
4470
+ }
4471
+ }
4460
4472
  /**
4461
4473
  * Get videos page using pagination API
4462
4474
  */
@@ -8079,7 +8091,7 @@ var useActiveBreaks = (lineIds) => {
8079
8091
  }
8080
8092
  return { elapsedMinutes, remainingMinutes };
8081
8093
  };
8082
- const getCurrentShift3 = (currentMinutes, dayStart, nightStart) => {
8094
+ const getCurrentShift2 = (currentMinutes, dayStart, nightStart) => {
8083
8095
  const dayStartMinutes = parseTimeToMinutes2(dayStart);
8084
8096
  const nightStartMinutes = parseTimeToMinutes2(nightStart);
8085
8097
  if (nightStartMinutes < dayStartMinutes) {
@@ -8111,7 +8123,7 @@ var useActiveBreaks = (lineIds) => {
8111
8123
  const dayShift = dayShifts?.find((s) => s.line_id === lineId);
8112
8124
  const nightShift = nightShifts?.find((s) => s.line_id === lineId);
8113
8125
  if (!dayShift || !nightShift) continue;
8114
- const currentShift = getCurrentShift3(
8126
+ const currentShift = getCurrentShift2(
8115
8127
  currentMinutes,
8116
8128
  dayShift.start_time || "06:00",
8117
8129
  nightShift.start_time || "18:00"
@@ -11608,9 +11620,12 @@ var usePrefetchClipCounts = ({
11608
11620
  shiftStr = "0";
11609
11621
  console.log(`[usePrefetchClipCounts] No shift provided for historical date ${date}, defaulting to day shift (0)`);
11610
11622
  } else {
11611
- const currentShift = getCurrentShift2();
11623
+ const currentShift = getCurrentShift(
11624
+ dashboardConfig.dateTimeConfig?.defaultTimezone || "Asia/Kolkata",
11625
+ dashboardConfig.shiftConfig
11626
+ );
11612
11627
  shiftStr = currentShift.shiftId.toString();
11613
- console.log(`[usePrefetchClipCounts] Using current operational shift: ${shiftStr} (${currentShift.shiftName})`);
11628
+ console.log(`[usePrefetchClipCounts] Using current operational shift: ${shiftStr}`);
11614
11629
  }
11615
11630
  return {
11616
11631
  workspaceId: workspaceId || "",
@@ -26947,11 +26962,14 @@ var BottlenecksContent = ({
26947
26962
  console.log(`[BottlenecksContent] No shift provided for historical date ${date}, defaulting to day shift (0)`);
26948
26963
  return "0";
26949
26964
  } else {
26950
- const currentShift = getCurrentShift2();
26951
- console.log(`[BottlenecksContent] Using current operational shift: ${currentShift.shiftId} (${currentShift.shiftName})`);
26965
+ const currentShift = getCurrentShift(
26966
+ dashboardConfig.dateTimeConfig?.defaultTimezone || "Asia/Kolkata",
26967
+ dashboardConfig.shiftConfig
26968
+ );
26969
+ console.log(`[BottlenecksContent] Using current operational shift: ${currentShift.shiftId}`);
26952
26970
  return currentShift.shiftId.toString();
26953
26971
  }
26954
- }, [shift, date]);
26972
+ }, [shift, date, dashboardConfig]);
26955
26973
  const {
26956
26974
  data: prefetchData,
26957
26975
  isFullyIndexed,
@@ -27040,44 +27058,73 @@ var BottlenecksContent = ({
27040
27058
  if (indicesToLoad.length === 0) return;
27041
27059
  console.log(`[ensureVideosLoaded] Preloading ${indicesToLoad.length} videos around index ${centerIndex}: [${indicesToLoad.join(", ")}]`);
27042
27060
  indicesToLoad.forEach((idx) => loadingVideosRef.current.add(idx));
27043
- const loadPromises = indicesToLoad.map(async (index) => {
27044
- try {
27045
- let video = null;
27046
- if (!video) {
27047
- const operationalDate = date || getOperationalDate();
27048
- const shiftStr = effectiveShift;
27049
- video = await s3ClipsService.getClipByIndex(
27061
+ const operationalDate = date || getOperationalDate();
27062
+ const shiftStr = effectiveShift;
27063
+ console.log(`[ensureVideosLoaded] Batch fetching ${indicesToLoad.length} videos in parallel`);
27064
+ try {
27065
+ const batchRequests = indicesToLoad.map((index) => ({
27066
+ category: effectiveFilter,
27067
+ index,
27068
+ includeMetadata: false
27069
+ // No metadata during bulk preloading
27070
+ }));
27071
+ const videos = await s3ClipsService.batchFetchVideos(
27072
+ workspaceId,
27073
+ operationalDate,
27074
+ shiftStr,
27075
+ batchRequests
27076
+ );
27077
+ if (videos.length > 0 && isMountedRef.current) {
27078
+ videos.forEach((video, idx) => {
27079
+ if (video) {
27080
+ setAllVideos((prev) => {
27081
+ const exists = prev.some((v) => v.id === video.id);
27082
+ if (!exists) {
27083
+ return [...prev, video];
27084
+ }
27085
+ return prev;
27086
+ });
27087
+ const originalIndex = indicesToLoad[idx];
27088
+ loadedIndices.add(originalIndex);
27089
+ preloadVideoUrl(video.src);
27090
+ }
27091
+ });
27092
+ console.log(`[ensureVideosLoaded] Successfully loaded ${videos.length} videos in batch`);
27093
+ }
27094
+ } catch (error2) {
27095
+ console.error("[ensureVideosLoaded] Batch fetch failed:", error2);
27096
+ const loadPromises = indicesToLoad.map(async (index) => {
27097
+ try {
27098
+ const video = await s3ClipsService.getClipByIndex(
27050
27099
  workspaceId,
27051
27100
  operationalDate,
27052
27101
  shiftStr,
27053
27102
  effectiveFilter,
27054
27103
  index,
27055
27104
  true,
27056
- // includeCycleTime - OK for preloading
27105
+ // includeCycleTime
27057
27106
  false
27058
- // includeMetadata - NO metadata during bulk preloading to prevent flooding
27107
+ // includeMetadata
27059
27108
  );
27109
+ if (video && isMountedRef.current) {
27110
+ setAllVideos((prev) => {
27111
+ const exists = prev.some((v) => v.id === video.id);
27112
+ if (!exists) {
27113
+ return [...prev, video];
27114
+ }
27115
+ return prev;
27116
+ });
27117
+ loadedIndices.add(index);
27118
+ preloadVideoUrl(video.src);
27119
+ }
27120
+ } catch (err) {
27121
+ console.warn(`[ensureVideosLoaded] Failed to load video at index ${index}:`, err);
27060
27122
  }
27061
- if (video && isMountedRef.current) {
27062
- setAllVideos((prev) => {
27063
- const exists = prev.some((v) => v.id === video.id);
27064
- if (!exists) {
27065
- return [...prev, video];
27066
- }
27067
- return prev;
27068
- });
27069
- loadedIndices.add(index);
27070
- preloadVideoUrl(video.src);
27071
- }
27072
- } catch (error2) {
27073
- console.warn(`[ensureVideosLoaded] Failed to load video at index ${index}:`, error2);
27074
- } finally {
27075
- loadingVideosRef.current.delete(index);
27076
- }
27077
- });
27078
- Promise.all(loadPromises).catch((err) => {
27079
- console.warn("[ensureVideosLoaded] Some videos failed to preload:", err);
27080
- });
27123
+ });
27124
+ await Promise.all(loadPromises);
27125
+ } finally {
27126
+ indicesToLoad.forEach((idx) => loadingVideosRef.current.delete(idx));
27127
+ }
27081
27128
  }, [s3ClipsService, workspaceId, clipCounts, sopCategories, date, effectiveShift]);
27082
27129
  const loadFirstVideoForCategory = React19.useCallback(async (category) => {
27083
27130
  if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
@@ -28663,7 +28710,6 @@ var WorkspaceHealthCard = ({
28663
28710
  };
28664
28711
  const config = getStatusConfig();
28665
28712
  const StatusIcon = config.icon;
28666
- workspace.isStale ? lucideReact.WifiOff : lucideReact.Wifi;
28667
28713
  const handleClick = () => {
28668
28714
  if (onClick) {
28669
28715
  onClick(workspace);
@@ -28711,34 +28757,13 @@ var WorkspaceHealthCard = ({
28711
28757
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: config.statusText })
28712
28758
  ] })
28713
28759
  ] }),
28714
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
28715
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
28716
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
28717
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-3.5 w-3.5 text-gray-400" }),
28718
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-gray-600 dark:text-gray-400 whitespace-nowrap", children: [
28719
- "Last seen: ",
28720
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: formatTimeAgo(workspace.timeSinceLastUpdate) })
28721
- ] })
28722
- ] }),
28723
- workspace.isStale && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
28724
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.WifiOff, { className: "h-3.5 w-3.5 text-amber-500" }),
28725
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-amber-600 dark:text-amber-400 text-xs", children: "No recent updates" })
28726
- ] })
28727
- ] }),
28728
- config.pulse && !workspace.isStale && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
28729
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex h-2 w-2", children: [
28730
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx(
28731
- "animate-ping absolute inline-flex h-full w-full rounded-full opacity-75",
28732
- workspace.status === "healthy" ? "bg-emerald-400" : "bg-amber-400"
28733
- ) }),
28734
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx(
28735
- "relative inline-flex rounded-full h-2 w-2",
28736
- workspace.status === "healthy" ? "bg-emerald-500" : "bg-amber-500"
28737
- ) })
28738
- ] }),
28739
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Live" })
28760
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
28761
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-3.5 w-3.5 text-gray-400" }),
28762
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-gray-600 dark:text-gray-400 whitespace-nowrap", children: [
28763
+ "Last seen: ",
28764
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: formatTimeAgo(workspace.timeSinceLastUpdate) })
28740
28765
  ] })
28741
- ] })
28766
+ ] }) }) })
28742
28767
  ] })
28743
28768
  }
28744
28769
  );
@@ -28819,16 +28844,16 @@ var CompactWorkspaceHealthCard = ({
28819
28844
  var HealthStatusGrid = ({
28820
28845
  workspaces,
28821
28846
  onWorkspaceClick,
28822
- viewMode: initialViewMode = "grid",
28823
28847
  showFilters = true,
28824
28848
  groupBy: initialGroupBy = "none",
28825
28849
  className = ""
28826
28850
  }) => {
28827
- const [viewMode, setViewMode] = React19.useState(initialViewMode);
28828
28851
  const [searchTerm, setSearchTerm] = React19.useState("");
28829
28852
  const [statusFilter, setStatusFilter] = React19.useState("all");
28830
28853
  const [groupBy, setGroupBy] = React19.useState(initialGroupBy);
28831
28854
  const [expandedGroups, setExpandedGroups] = React19.useState(/* @__PURE__ */ new Set());
28855
+ const lastGroupByRef = React19.useRef(initialGroupBy);
28856
+ const hasInitializedGroupsRef = React19.useRef(false);
28832
28857
  const filteredWorkspaces = React19.useMemo(() => {
28833
28858
  let filtered = [...workspaces];
28834
28859
  if (searchTerm) {
@@ -28869,7 +28894,17 @@ var HealthStatusGrid = ({
28869
28894
  return sortedGroups;
28870
28895
  }, [filteredWorkspaces, groupBy]);
28871
28896
  React19.useEffect(() => {
28872
- if (groupBy !== "none") {
28897
+ if (groupBy !== lastGroupByRef.current) {
28898
+ lastGroupByRef.current = groupBy;
28899
+ hasInitializedGroupsRef.current = false;
28900
+ if (groupBy === "none") {
28901
+ setExpandedGroups(/* @__PURE__ */ new Set());
28902
+ }
28903
+ }
28904
+ }, [groupBy]);
28905
+ React19.useEffect(() => {
28906
+ if (groupBy !== "none" && !hasInitializedGroupsRef.current && Object.keys(groupedWorkspaces).length > 0) {
28907
+ hasInitializedGroupsRef.current = true;
28873
28908
  setExpandedGroups(new Set(Object.keys(groupedWorkspaces)));
28874
28909
  }
28875
28910
  }, [groupBy, groupedWorkspaces]);
@@ -28913,13 +28948,13 @@ var HealthStatusGrid = ({
28913
28948
  ] }) }),
28914
28949
  /* @__PURE__ */ jsxRuntime.jsxs(Select, { value: statusFilter, onValueChange: (value) => setStatusFilter(value), children: [
28915
28950
  /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "w-full sm:w-[180px] bg-white border-gray-200", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "All statuses" }) }),
28916
- /* @__PURE__ */ jsxRuntime.jsxs(SelectContent, { children: [
28917
- /* @__PURE__ */ jsxRuntime.jsxs(SelectItem, { value: "all", children: [
28951
+ /* @__PURE__ */ jsxRuntime.jsxs(SelectContent, { className: "bg-white border border-gray-200 shadow-lg", children: [
28952
+ /* @__PURE__ */ jsxRuntime.jsxs(SelectItem, { value: "all", className: "text-gray-700 hover:bg-gray-50 focus:bg-gray-50 border-b border-gray-100 last:border-b-0", children: [
28918
28953
  "All (",
28919
28954
  workspaces.length,
28920
28955
  ")"
28921
28956
  ] }),
28922
- /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "healthy", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
28957
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "healthy", className: "text-gray-700 hover:bg-gray-50 focus:bg-gray-50 border-b border-gray-100 last:border-b-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
28923
28958
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-green-500" }),
28924
28959
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
28925
28960
  "Healthy (",
@@ -28927,7 +28962,7 @@ var HealthStatusGrid = ({
28927
28962
  ")"
28928
28963
  ] })
28929
28964
  ] }) }),
28930
- /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "unhealthy", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
28965
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "unhealthy", className: "text-gray-700 hover:bg-gray-50 focus:bg-gray-50 border-b border-gray-100 last:border-b-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
28931
28966
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-red-500" }),
28932
28967
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
28933
28968
  "Unhealthy (",
@@ -28935,57 +28970,23 @@ var HealthStatusGrid = ({
28935
28970
  ")"
28936
28971
  ] })
28937
28972
  ] }) }),
28938
- /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "warning", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
28973
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "warning", className: "text-gray-700 hover:bg-gray-50 focus:bg-gray-50 border-b border-gray-100 last:border-b-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
28939
28974
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-yellow-500" }),
28940
28975
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
28941
28976
  "Warning (",
28942
28977
  statusCounts.warning,
28943
28978
  ")"
28944
28979
  ] })
28945
- ] }) }),
28946
- /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "unknown", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
28947
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-gray-400" }),
28948
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
28949
- "Unknown (",
28950
- statusCounts.unknown,
28951
- ")"
28952
- ] })
28953
28980
  ] }) })
28954
28981
  ] })
28955
28982
  ] }),
28956
28983
  /* @__PURE__ */ jsxRuntime.jsxs(Select, { value: groupBy, onValueChange: (value) => setGroupBy(value), children: [
28957
28984
  /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "w-full sm:w-[160px] bg-white border-gray-200", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Group by" }) }),
28958
- /* @__PURE__ */ jsxRuntime.jsxs(SelectContent, { children: [
28959
- /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "none", children: "No grouping" }),
28960
- /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "line", children: "Group by Line" }),
28961
- /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "status", children: "Group by Status" })
28985
+ /* @__PURE__ */ jsxRuntime.jsxs(SelectContent, { className: "bg-white border border-gray-200 shadow-lg", children: [
28986
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "none", className: "text-gray-700 hover:bg-gray-50 focus:bg-gray-50 border-b border-gray-100 last:border-b-0", children: "No grouping" }),
28987
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "line", className: "text-gray-700 hover:bg-gray-50 focus:bg-gray-50 border-b border-gray-100 last:border-b-0", children: "Group by Line" }),
28988
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "status", className: "text-gray-700 hover:bg-gray-50 focus:bg-gray-50 border-b border-gray-100 last:border-b-0", children: "Group by Status" })
28962
28989
  ] })
28963
- ] }),
28964
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
28965
- /* @__PURE__ */ jsxRuntime.jsx(
28966
- "button",
28967
- {
28968
- onClick: () => setViewMode("grid"),
28969
- className: clsx(
28970
- "p-2 rounded-lg transition-colors",
28971
- viewMode === "grid" ? "bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400" : "text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700"
28972
- ),
28973
- "aria-label": "Grid view",
28974
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Grid3x3, { className: "h-5 w-5" })
28975
- }
28976
- ),
28977
- /* @__PURE__ */ jsxRuntime.jsx(
28978
- "button",
28979
- {
28980
- onClick: () => setViewMode("list"),
28981
- className: clsx(
28982
- "p-2 rounded-lg transition-colors",
28983
- viewMode === "list" ? "bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400" : "text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700"
28984
- ),
28985
- "aria-label": "List view",
28986
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.List, { className: "h-5 w-5" })
28987
- }
28988
- )
28989
28990
  ] })
28990
28991
  ] }),
28991
28992
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 text-sm text-gray-500 dark:text-gray-400", children: [
@@ -29025,32 +29026,15 @@ var HealthStatusGrid = ({
29025
29026
  ]
29026
29027
  }
29027
29028
  ),
29028
- isExpanded && /* @__PURE__ */ jsxRuntime.jsx(
29029
- "div",
29029
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4", children: groupWorkspaces.map((workspace) => /* @__PURE__ */ jsxRuntime.jsx(
29030
+ WorkspaceHealthCard,
29030
29031
  {
29031
- className: clsx(
29032
- viewMode === "grid" ? "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4" : "space-y-2"
29033
- ),
29034
- children: groupWorkspaces.map(
29035
- (workspace) => viewMode === "grid" ? /* @__PURE__ */ jsxRuntime.jsx(
29036
- WorkspaceHealthCard,
29037
- {
29038
- workspace,
29039
- onClick: onWorkspaceClick,
29040
- showDetails: true
29041
- },
29042
- workspace.workspace_id
29043
- ) : /* @__PURE__ */ jsxRuntime.jsx(
29044
- CompactWorkspaceHealthCard,
29045
- {
29046
- workspace,
29047
- onClick: onWorkspaceClick
29048
- },
29049
- workspace.workspace_id
29050
- )
29051
- )
29052
- }
29053
- )
29032
+ workspace,
29033
+ onClick: onWorkspaceClick,
29034
+ showDetails: true
29035
+ },
29036
+ workspace.workspace_id
29037
+ )) })
29054
29038
  ] }, groupName);
29055
29039
  }) }),
29056
29040
  filteredWorkspaces.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-500 dark:text-gray-400", children: searchTerm || statusFilter !== "all" ? "No workspaces found matching your filters." : "No workspaces available." }) })
@@ -37772,7 +37756,23 @@ var WorkspaceDetailView = ({
37772
37756
  "aria-label": "Navigate back to previous page"
37773
37757
  }
37774
37758
  ) }),
37775
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-1/2 transform -translate-x-1/2", children: /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-semibold text-gray-900", children: formattedWorkspaceName }) }),
37759
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-1/2 transform -translate-x-1/2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
37760
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-semibold text-gray-900", children: formattedWorkspaceName }),
37761
+ workspaceHealth && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex h-2.5 w-2.5", children: [
37762
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx(
37763
+ "animate-ping absolute inline-flex h-full w-full rounded-full opacity-75",
37764
+ workspaceHealth.status === "healthy" ? "bg-green-400" : "bg-red-400"
37765
+ ) }),
37766
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx(
37767
+ "relative inline-flex rounded-full h-2.5 w-2.5",
37768
+ workspaceHealth.status === "healthy" ? "bg-green-500" : "bg-red-500"
37769
+ ) })
37770
+ ] })
37771
+ ] }) }),
37772
+ workspaceHealth && activeTab !== "monthly_history" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-0 top-0 flex items-center h-8", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-500", children: [
37773
+ "Last update: ",
37774
+ workspaceHealth.timeSinceLastUpdate
37775
+ ] }) }),
37776
37776
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-8" })
37777
37777
  ] }),
37778
37778
  activeTab !== "monthly_history" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 bg-blue-50 px-3 py-2 rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-4", children: [
@@ -37800,19 +37800,6 @@ var WorkspaceDetailView = ({
37800
37800
  workspace.shift_type,
37801
37801
  " Shift"
37802
37802
  ] })
37803
- ] }),
37804
- workspaceHealth && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
37805
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" }),
37806
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
37807
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx(
37808
- "h-1.5 w-1.5 rounded-full",
37809
- workspaceHealth.status === "healthy" ? "bg-green-600" : workspaceHealth.status === "unhealthy" ? "bg-red-600" : workspaceHealth.status === "warning" ? "bg-amber-600" : "bg-gray-500"
37810
- ) }),
37811
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-blue-700", children: [
37812
- "Last update: ",
37813
- workspaceHealth.timeSinceLastUpdate
37814
- ] })
37815
- ] })
37816
37803
  ] })
37817
37804
  ] }) }),
37818
37805
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 sm:mt-1.5 lg:mt-2 flex items-center justify-between", children: [
@@ -38356,7 +38343,6 @@ var WorkspaceHealthView = ({
38356
38343
  className = ""
38357
38344
  }) => {
38358
38345
  const router$1 = router.useRouter();
38359
- const [viewMode, setViewMode] = React19.useState("grid");
38360
38346
  const [groupBy, setGroupBy] = React19.useState("line");
38361
38347
  const operationalDate = getOperationalDate();
38362
38348
  const currentHour = (/* @__PURE__ */ new Date()).getHours();
@@ -38521,7 +38507,7 @@ var WorkspaceHealthView = ({
38521
38507
  transition: { duration: 0.3, delay: 0.1 },
38522
38508
  className: "grid grid-cols-2 sm:grid-cols-2 md:grid-cols-5 gap-2 sm:gap-3 lg:gap-4",
38523
38509
  children: [
38524
- /* @__PURE__ */ jsxRuntime.jsxs(Card2, { className: "col-span-2 sm:col-span-2 md:col-span-2", children: [
38510
+ /* @__PURE__ */ jsxRuntime.jsxs(Card2, { className: "col-span-2 sm:col-span-2 md:col-span-2 bg-white", children: [
38525
38511
  /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-3", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-sm font-medium text-gray-500 dark:text-gray-400", children: "Overall System Status" }) }),
38526
38512
  /* @__PURE__ */ jsxRuntime.jsxs(CardContent2, { children: [
38527
38513
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2", children: [
@@ -38539,33 +38525,33 @@ var WorkspaceHealthView = ({
38539
38525
  ] })
38540
38526
  ] })
38541
38527
  ] }),
38542
- /* @__PURE__ */ jsxRuntime.jsxs(Card2, { children: [
38528
+ /* @__PURE__ */ jsxRuntime.jsxs(Card2, { className: "bg-white", children: [
38543
38529
  /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-3", children: /* @__PURE__ */ jsxRuntime.jsxs(CardTitle2, { className: "text-sm font-medium text-gray-500 dark:text-gray-400 flex items-center gap-2", children: [
38544
38530
  getStatusIcon("healthy"),
38545
38531
  "Healthy"
38546
38532
  ] }) }),
38547
38533
  /* @__PURE__ */ jsxRuntime.jsxs(CardContent2, { children: [
38548
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-2xl font-bold text-green-600 dark:text-green-400", children: summary.healthyWorkspaces }),
38534
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-2xl font-bold text-gray-900 dark:text-gray-50", children: summary.healthyWorkspaces }),
38549
38535
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: "Operating normally" })
38550
38536
  ] })
38551
38537
  ] }),
38552
- /* @__PURE__ */ jsxRuntime.jsxs(Card2, { children: [
38538
+ /* @__PURE__ */ jsxRuntime.jsxs(Card2, { className: "bg-white", children: [
38553
38539
  /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-3", children: /* @__PURE__ */ jsxRuntime.jsxs(CardTitle2, { className: "text-sm font-medium text-gray-500 dark:text-gray-400 flex items-center gap-2", children: [
38554
38540
  getStatusIcon("warning"),
38555
38541
  "Warning"
38556
38542
  ] }) }),
38557
38543
  /* @__PURE__ */ jsxRuntime.jsxs(CardContent2, { children: [
38558
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-2xl font-bold text-yellow-600 dark:text-yellow-400", children: summary.warningWorkspaces }),
38544
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-2xl font-bold text-gray-900 dark:text-gray-50", children: summary.warningWorkspaces }),
38559
38545
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: "Delayed updates" })
38560
38546
  ] })
38561
38547
  ] }),
38562
- /* @__PURE__ */ jsxRuntime.jsxs(Card2, { children: [
38548
+ /* @__PURE__ */ jsxRuntime.jsxs(Card2, { className: "bg-white", children: [
38563
38549
  /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-3", children: /* @__PURE__ */ jsxRuntime.jsxs(CardTitle2, { className: "text-sm font-medium text-gray-500 dark:text-gray-400 flex items-center gap-2", children: [
38564
38550
  getStatusIcon("unhealthy"),
38565
38551
  "Unhealthy"
38566
38552
  ] }) }),
38567
38553
  /* @__PURE__ */ jsxRuntime.jsxs(CardContent2, { children: [
38568
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-2xl font-bold text-red-600 dark:text-red-400", children: summary.unhealthyWorkspaces }),
38554
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-2xl font-bold text-gray-900 dark:text-gray-50", children: summary.unhealthyWorkspaces }),
38569
38555
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: "Requires attention" })
38570
38556
  ] })
38571
38557
  ] })
@@ -38583,7 +38569,6 @@ var WorkspaceHealthView = ({
38583
38569
  {
38584
38570
  workspaces,
38585
38571
  onWorkspaceClick: handleWorkspaceClick,
38586
- viewMode,
38587
38572
  showFilters: true,
38588
38573
  groupBy
38589
38574
  }