@optifye/dashboard-core 5.0.0 → 6.0.1

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
@@ -79,12 +79,15 @@ var DEFAULT_DATABASE_CONFIG = {
79
79
  }
80
80
  };
81
81
  var DEFAULT_ENTITY_CONFIG = {
82
- companyId: void 0,
83
- factoryId: void 0,
84
- defaultLineId: void 0,
85
- secondaryLineId: void 0,
82
+ companyId: "87ca8ebc-ef29-4543-9e12-efc526a9b669",
83
+ factoryId: "b3e44be4-730e-4276-b2ce-701c79d66ffa",
84
+ defaultLineId: "98a2287e-8d55-4020-b00d-b9940437e3e1",
85
+ secondaryLineId: "d93997bb-ecac-4478-a4a6-008d536b724c",
86
86
  factoryViewId: "factory",
87
- lineNames: {}
87
+ lineNames: {
88
+ "98a2287e-8d55-4020-b00d-b9940437e3e1": "Cell 8",
89
+ "d93997bb-ecac-4478-a4a6-008d536b724c": "Cell 7"
90
+ }
88
91
  };
89
92
  var DEFAULT_SHIFT_CONFIG = {
90
93
  dayShift: {
@@ -101,9 +104,12 @@ var DEFAULT_SHIFT_CONFIG = {
101
104
  };
102
105
  var DEFAULT_WORKSPACE_CONFIG = {
103
106
  displayNames: {
104
- "WS01": "fillin",
105
- "WS02": "Capping Station",
106
- "WS03": "Filling station"
107
+ "Cell 8 WS1": "Swaging 1",
108
+ "Cell 8 WS2": "Bond Testing 1",
109
+ "Cell 8 WS3": "QA Check 1",
110
+ "Cell 7 WS1": "Swaging 2",
111
+ "Cell 7 WS2": "Bond Testing 2",
112
+ "Cell 7 WS3": "QA Check 2"
107
113
  },
108
114
  specialWorkspaces: {
109
115
  startId: 19,
@@ -160,7 +166,8 @@ var DEFAULT_VIDEO_CONFIG = {
160
166
  useRAF: true
161
167
  }
162
168
  };
163
- var LINE_1_UUID = "910a224b-0abc-459a-babb-4c899824cfe7";
169
+ var LINE_1_UUID = "98a2287e-8d55-4020-b00d-b9940437e3e1";
170
+ var LINE_2_UUID = "d93997bb-ecac-4478-a4a6-008d536b724c";
164
171
  var DEFAULT_CONFIG = {
165
172
  apiBaseUrl: void 0,
166
173
  // No default base URL
@@ -1020,7 +1027,7 @@ var dashboardService = {
1020
1027
  const formattedStartDate = formatDate(startDate);
1021
1028
  const formattedEndDate = formatDate(endDate);
1022
1029
  try {
1023
- const { data, error } = await supabase.from(metricsTable).select("date, shift_id, efficiency, total_output, avg_cycle_time, ideal_output, avg_pph, pph_threshold, workspace_rank").eq("workspace_id", workspaceUuid).gte("date", formattedStartDate).lte("date", formattedEndDate).order("date", { ascending: true }).order("shift_id", { ascending: true });
1030
+ const { data, error } = await supabase.from(metricsTable).select("date, shift_id, efficiency, total_output, avg_cycle_time, ideal_output, avg_pph, pph_threshold, workspace_rank, idle_time").eq("workspace_id", workspaceUuid).gte("date", formattedStartDate).lte("date", formattedEndDate).order("date", { ascending: true }).order("shift_id", { ascending: true });
1024
1031
  if (error) throw error;
1025
1032
  if (!data) return [];
1026
1033
  const transformedData = data.map((item) => ({
@@ -1033,7 +1040,8 @@ var dashboardService = {
1033
1040
  ideal_output: item.ideal_output || 0,
1034
1041
  avg_pph: item.avg_pph || 0,
1035
1042
  pph_threshold: item.pph_threshold || 0,
1036
- workspace_rank: item.workspace_rank || 0
1043
+ workspace_rank: item.workspace_rank || 0,
1044
+ idle_time: item.idle_time || 0
1037
1045
  }));
1038
1046
  return transformedData;
1039
1047
  } catch (err) {
@@ -3392,6 +3400,9 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
3392
3400
  const databaseConfig = useDatabaseConfig();
3393
3401
  const dateTimeConfig = useDateTimeConfig();
3394
3402
  const shiftConfig = useShiftConfig();
3403
+ const defaultTimezone = dateTimeConfig?.defaultTimezone || "UTC";
3404
+ const configuredLineMetricsTable = databaseConfig?.tables?.lineMetrics ?? "line_metrics";
3405
+ const schema = databaseConfig?.schema ?? "public";
3395
3406
  const supabase = useSupabase();
3396
3407
  const [metrics2, setMetrics] = React14.useState(() => getCache(lineId) || { workspaceMetrics: [], lineMetrics: [] });
3397
3408
  const [isLoading, setIsLoading] = React14.useState(() => !getCache(lineId));
@@ -3404,9 +3415,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
3404
3415
  () => getCompanyMetricsTableName(entityConfig.companyId, "performance_metrics"),
3405
3416
  [entityConfig.companyId]
3406
3417
  );
3407
- const configuredLineMetricsTable = databaseConfig.tables?.lineMetrics ?? "line_metrics";
3408
- const schema = databaseConfig.schema ?? "public";
3409
- const defaultTimezone = dateTimeConfig.defaultTimezone || "UTC";
3410
3418
  React14.useEffect(() => {
3411
3419
  lineIdRef.current = lineId;
3412
3420
  const cachedData = getCache(lineId);
@@ -3416,7 +3424,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
3416
3424
  const fetchAllMetrics = React14.useCallback(async () => {
3417
3425
  const currentLineIdToUse = lineIdRef.current;
3418
3426
  if (!currentLineIdToUse || !supabase || isFetchingRef.current || companySpecificMetricsTable.includes("unknown_company")) {
3419
- if (!metrics2.workspaceMetrics.length && !metrics2.lineMetrics.length) setIsLoading(false);
3427
+ if (!metrics2?.workspaceMetrics?.length && !metrics2?.lineMetrics?.length) setIsLoading(false);
3420
3428
  if (companySpecificMetricsTable.includes("unknown_company") && !error) {
3421
3429
  setError({ message: "Company ID not configured for metrics table.", code: "CONFIG_ERROR" });
3422
3430
  }
@@ -3437,7 +3445,12 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
3437
3445
  if (targetLineIds.length === 0) {
3438
3446
  throw new Error("No target line IDs available for fetching metrics.");
3439
3447
  }
3440
- const { data: workspaceData, error: workspaceError } = await supabase.from(companySpecificMetricsTable).select("company_id,line_id,shift_id,date,workspace_id,workspace_name,total_output,avg_pph,performance_score,avg_cycle_time,trend_score,ideal_output,efficiency,total_day_output").eq("date", operationalDate).eq("shift_id", currentShiftDetails.shiftId).in("line_id", targetLineIds);
3448
+ const isFactoryView = currentLineIdToUse === (entityConfig.factoryViewId || "factory");
3449
+ let workspaceQuery = supabase.from(companySpecificMetricsTable).select("company_id,line_id,shift_id,date,workspace_id,workspace_name,total_output,avg_pph,performance_score,avg_cycle_time,trend_score,ideal_output,efficiency,total_day_output").eq("date", operationalDate).eq("shift_id", currentShiftDetails.shiftId);
3450
+ if (!isFactoryView) {
3451
+ workspaceQuery = workspaceQuery.in("line_id", targetLineIds);
3452
+ }
3453
+ const { data: workspaceData, error: workspaceError } = await workspaceQuery;
3441
3454
  if (workspaceError) {
3442
3455
  throw workspaceError;
3443
3456
  }
@@ -3468,7 +3481,11 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
3468
3481
  const wsNumB = parseInt(b.workspace_name?.replace(/[^0-9]/g, "") || "0");
3469
3482
  return wsNumA - wsNumB;
3470
3483
  });
3471
- const { data: lineData, error: lineError } = await supabase.from(configuredLineMetricsTable).select("*").eq("date", operationalDate).eq("shift_id", currentShiftDetails.shiftId).in("line_id", targetLineIds);
3484
+ let lineMetricsQuery = supabase.from(configuredLineMetricsTable).select("*").eq("date", operationalDate).eq("shift_id", currentShiftDetails.shiftId);
3485
+ if (!isFactoryView) {
3486
+ lineMetricsQuery = lineMetricsQuery.in("line_id", targetLineIds);
3487
+ }
3488
+ const { data: lineData, error: lineError } = await lineMetricsQuery;
3472
3489
  if (lineError) {
3473
3490
  throw lineError;
3474
3491
  }
@@ -3488,9 +3505,9 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
3488
3505
  }
3489
3506
  }, [
3490
3507
  supabase,
3491
- metrics2.workspaceMetrics.length,
3508
+ metrics2?.workspaceMetrics?.length || 0,
3492
3509
  // To re-evaluate setIsLoading in fetchAllMetrics if called directly
3493
- metrics2.lineMetrics.length,
3510
+ metrics2?.lineMetrics?.length || 0,
3494
3511
  // To re-evaluate setIsLoading in fetchAllMetrics if called directly
3495
3512
  companySpecificMetricsTable,
3496
3513
  configuredLineMetricsTable,
@@ -3578,8 +3595,8 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
3578
3595
  // Add lineId from props to re-run effect if it changes, managed by lineIdRef inside effect
3579
3596
  ]);
3580
3597
  return {
3581
- workspaceMetrics: metrics2.workspaceMetrics,
3582
- lineMetrics: metrics2.lineMetrics,
3598
+ workspaceMetrics: metrics2?.workspaceMetrics || [],
3599
+ lineMetrics: metrics2?.lineMetrics || [],
3583
3600
  isLoading,
3584
3601
  error,
3585
3602
  refetch: fetchAllMetrics
@@ -3612,6 +3629,7 @@ var setCache2 = (lineId, data) => {
3612
3629
  var useLineKPIs = ({ lineId }) => {
3613
3630
  useDashboardConfig();
3614
3631
  const entityConfig = useEntityConfig();
3632
+ const isFactoryView = lineId === (entityConfig.factoryViewId || "factory");
3615
3633
  const databaseConfig = useDatabaseConfig();
3616
3634
  const dateTimeConfig = useDateTimeConfig();
3617
3635
  const shiftConfig = useShiftConfig();
@@ -3669,7 +3687,7 @@ var useLineKPIs = ({ lineId }) => {
3669
3687
  isFetchingRef.current = false;
3670
3688
  updateQueueRef.current = false;
3671
3689
  }
3672
- }, [dashboardServiceInstance, kpis, defaultTimezone, shiftConfig, entityConfig.companyId]);
3690
+ }, [dashboardServiceInstance, kpis, defaultTimezone, shiftConfig, entityConfig.companyId, isFactoryView]);
3673
3691
  const queueUpdate = React14.useCallback(() => {
3674
3692
  if (updateQueueRef.current) return;
3675
3693
  updateQueueRef.current = true;
@@ -3744,7 +3762,7 @@ var useLineKPIs = ({ lineId }) => {
3744
3762
  }
3745
3763
  activeChannels.forEach((ch) => supabase.removeChannel(ch).catch((err) => console.error("[useLineKPIs] Error removing KPI channel:", err)));
3746
3764
  };
3747
- }, [supabase, lineId, fetchKPIs, queueUpdate, dashboardServiceInstance, entityConfig, schema, lineMetricsTable, companySpecificMetricsTable, defaultTimezone, shiftConfig, kpis]);
3765
+ }, [supabase, lineId, fetchKPIs, queueUpdate, dashboardServiceInstance, entityConfig, schema, lineMetricsTable, companySpecificMetricsTable, defaultTimezone, shiftConfig, kpis, isFactoryView]);
3748
3766
  return {
3749
3767
  kpis,
3750
3768
  isLoading,
@@ -5180,6 +5198,120 @@ var useActiveBreaks = (lineIds) => {
5180
5198
  error
5181
5199
  };
5182
5200
  };
5201
+ var useAllWorkspaceMetrics = (options) => {
5202
+ const entityConfig = useEntityConfig();
5203
+ const databaseConfig = useDatabaseConfig();
5204
+ const dateTimeConfig = useDateTimeConfig();
5205
+ const shiftConfig = useShiftConfig();
5206
+ const supabase = useSupabase();
5207
+ const [workspaces, setWorkspaces] = React14.useState([]);
5208
+ const [loading, setLoading] = React14.useState(true);
5209
+ const [error, setError] = React14.useState(null);
5210
+ const [initialized, setInitialized] = React14.useState(false);
5211
+ const queryShiftId = React14.useMemo(() => {
5212
+ const currentShift = getCurrentShift(
5213
+ dateTimeConfig.defaultTimezone || "Asia/Kolkata",
5214
+ shiftConfig
5215
+ );
5216
+ return options?.initialShiftId !== void 0 ? options.initialShiftId : currentShift.shiftId;
5217
+ }, [options?.initialShiftId, dateTimeConfig.defaultTimezone, shiftConfig]);
5218
+ const queryDate = React14.useMemo(() => {
5219
+ return options?.initialDate || getOperationalDate(dateTimeConfig.defaultTimezone);
5220
+ }, [options?.initialDate, dateTimeConfig.defaultTimezone]);
5221
+ const metricsTable = React14.useMemo(() => {
5222
+ const companyId = entityConfig.companyId;
5223
+ if (!companyId) return "";
5224
+ const metricsTablePrefix = getMetricsTablePrefix();
5225
+ return `${metricsTablePrefix}_${companyId.replace(/-/g, "_")}`;
5226
+ }, [entityConfig.companyId]);
5227
+ const schema = databaseConfig.schema ?? "public";
5228
+ const fetchWorkspaceMetrics = React14.useCallback(async () => {
5229
+ if (!initialized) {
5230
+ setLoading(true);
5231
+ }
5232
+ setError(null);
5233
+ try {
5234
+ console.log("Fetching all workspace metrics with params:", {
5235
+ queryDate,
5236
+ queryShiftId,
5237
+ metricsTable
5238
+ });
5239
+ const { data, error: fetchError } = await supabase.from(metricsTable).select(`
5240
+ workspace_name,
5241
+ total_output,
5242
+ avg_pph,
5243
+ efficiency,
5244
+ workspace_id,
5245
+ avg_cycle_time,
5246
+ performance_score,
5247
+ trend_score,
5248
+ line_id,
5249
+ total_day_output
5250
+ `).eq("date", queryDate).eq("shift_id", queryShiftId).order("efficiency", { ascending: false });
5251
+ if (fetchError) throw fetchError;
5252
+ const transformedData = (data || []).map((item) => ({
5253
+ company_id: entityConfig.companyId || "unknown",
5254
+ line_id: item.line_id,
5255
+ shift_id: queryShiftId,
5256
+ date: queryDate,
5257
+ workspace_uuid: item.workspace_id,
5258
+ workspace_name: item.workspace_name,
5259
+ action_count: item.total_output || 0,
5260
+ pph: item.avg_pph || 0,
5261
+ performance_score: item.performance_score || 0,
5262
+ avg_cycle_time: item.avg_cycle_time || 0,
5263
+ trend: item.trend_score === 1 ? 2 : 0,
5264
+ predicted_output: 0,
5265
+ efficiency: item.efficiency || 0,
5266
+ action_threshold: item.total_day_output || 0
5267
+ }));
5268
+ setWorkspaces(transformedData);
5269
+ setInitialized(true);
5270
+ } catch (err) {
5271
+ console.error("Error fetching all workspace metrics:", err);
5272
+ setError({ message: err.message, code: err.code || "FETCH_ERROR" });
5273
+ } finally {
5274
+ setLoading(false);
5275
+ }
5276
+ }, [queryDate, queryShiftId, metricsTable, supabase, entityConfig.companyId]);
5277
+ React14.useEffect(() => {
5278
+ if (!initialized) {
5279
+ fetchWorkspaceMetrics();
5280
+ }
5281
+ const setupSubscription = () => {
5282
+ const filter2 = `date=eq.${queryDate} AND shift_id=eq.${queryShiftId}`;
5283
+ console.log("Setting up subscription for all workspaces with filter:", filter2);
5284
+ const channel2 = supabase.channel(`all-workspace-metrics-${Date.now()}`).on(
5285
+ "postgres_changes",
5286
+ {
5287
+ event: "*",
5288
+ schema,
5289
+ table: metricsTable,
5290
+ filter: filter2
5291
+ },
5292
+ async (payload) => {
5293
+ console.log("All workspace metrics update received:", payload);
5294
+ await fetchWorkspaceMetrics();
5295
+ }
5296
+ ).subscribe();
5297
+ return channel2;
5298
+ };
5299
+ const channel = setupSubscription();
5300
+ return () => {
5301
+ if (channel) {
5302
+ supabase.removeChannel(channel);
5303
+ }
5304
+ };
5305
+ }, [queryDate, queryShiftId, metricsTable, fetchWorkspaceMetrics, initialized, supabase, schema]);
5306
+ React14.useEffect(() => {
5307
+ setInitialized(false);
5308
+ }, [queryDate, queryShiftId]);
5309
+ const refreshWorkspaces = fetchWorkspaceMetrics;
5310
+ return React14.useMemo(
5311
+ () => ({ workspaces, loading, error, refreshWorkspaces }),
5312
+ [workspaces, loading, error, refreshWorkspaces]
5313
+ );
5314
+ };
5183
5315
  var MAX_RETRIES = 10;
5184
5316
  var RETRY_DELAY = 500;
5185
5317
  function useNavigation(customNavigate) {
@@ -5226,8 +5358,8 @@ function useNavigation(customNavigate) {
5226
5358
  router$1.push("/shifts");
5227
5359
  }, [router$1]);
5228
5360
  const goToLeaderboard = React14.useCallback(() => {
5229
- const lineId = entityConfig?.defaultLineId || "line-1";
5230
- router$1.push(`/leaderboard/${lineId}`);
5361
+ entityConfig?.defaultLineId || "line-1";
5362
+ router$1.push(`/leaderboard`);
5231
5363
  }, [router$1, entityConfig?.defaultLineId]);
5232
5364
  const goToFactoryView = React14.useCallback(() => {
5233
5365
  router$1.push("/factory-view");
@@ -17367,7 +17499,8 @@ var VideoCard = React14__namespace.default.memo(({
17367
17499
  cropping,
17368
17500
  canvasFps = 30,
17369
17501
  useRAF = true,
17370
- className = ""
17502
+ className = "",
17503
+ compact = false
17371
17504
  }) => {
17372
17505
  const videoRef = React14.useRef(null);
17373
17506
  const canvasRef = React14.useRef(null);
@@ -17388,7 +17521,6 @@ var VideoCard = React14__namespace.default.memo(({
17388
17521
  });
17389
17522
  }
17390
17523
  const displayName = getWorkspaceDisplayName(workspace.workspace_name);
17391
- workspace.workspace_uuid || workspace.workspace_name;
17392
17524
  const getEfficiencyOverlayColor = (efficiency) => {
17393
17525
  if (efficiency >= 80) {
17394
17526
  return "bg-[#00D654]/25";
@@ -17431,15 +17563,15 @@ var VideoCard = React14__namespace.default.memo(({
17431
17563
  }
17432
17564
  },
17433
17565
  children: [
17434
- isVeryLowEfficiency && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-1 left-2 z-30", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
17566
+ isVeryLowEfficiency && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `absolute ${compact ? "top-0.5 left-1" : "top-1 left-2"} z-30`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
17435
17567
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -inset-1 bg-red-400/50 rounded-full blur-sm animate-pulse" }),
17436
17568
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -inset-0.5 bg-red-500/30 rounded-full blur-md animate-ping [animation-duration:1.5s]" }),
17437
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-[#E34329] w-5 h-5 rounded-full flex items-center justify-center text-white font-bold text-xs shadow-lg ring-2 ring-red-400/40 border border-red-400/80 animate-pulse", children: "!" })
17569
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `bg-[#E34329] ${compact ? "w-4 h-4" : "w-5 h-5"} rounded-full flex items-center justify-center text-white font-bold ${compact ? "text-[10px]" : "text-xs"} shadow-lg ring-2 ring-red-400/40 border border-red-400/80 animate-pulse`, children: "!" })
17438
17570
  ] }) }),
17439
17571
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full h-full overflow-hidden bg-black", children: [
17440
17572
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black z-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse flex flex-col items-center", children: [
17441
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Camera, { className: "w-6 h-6 text-gray-500" }),
17442
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-gray-500 mt-1", children: "Loading..." })
17573
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Camera, { className: `${compact ? "w-4 h-4" : "w-6 h-6"} text-gray-500` }),
17574
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: `${compact ? "text-[10px]" : "text-xs"} text-gray-500 mt-1`, children: "Loading..." })
17443
17575
  ] }) }),
17444
17576
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 z-10", children: [
17445
17577
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -17462,11 +17594,11 @@ var VideoCard = React14__namespace.default.memo(({
17462
17594
  )
17463
17595
  ] }),
17464
17596
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: `absolute inset-0 z-20 pointer-events-none ${efficiencyOverlayClass}` }),
17465
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-2 right-2 z-30 bg-black/70 backdrop-blur-sm rounded px-2 py-0.5 text-white text-xs font-semibold border border-white/10", children: [
17597
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `absolute ${compact ? "top-1 right-1" : "top-2 right-2"} z-30 bg-black/70 backdrop-blur-sm rounded ${compact ? "px-1.5 py-0.5" : "px-2 py-0.5"} text-white ${compact ? "text-[10px]" : "text-xs"} font-semibold border border-white/10`, children: [
17466
17598
  Math.round(workspace.efficiency),
17467
17599
  "%"
17468
17600
  ] }),
17469
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 left-0 right-0 h-1 bg-black/50 z-30", children: /* @__PURE__ */ jsxRuntime.jsx(
17601
+ /* @__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(
17470
17602
  "div",
17471
17603
  {
17472
17604
  className: `h-full ${efficiencyBarClass} transition-all duration-500`,
@@ -17474,22 +17606,22 @@ var VideoCard = React14__namespace.default.memo(({
17474
17606
  }
17475
17607
  ) })
17476
17608
  ] }),
17477
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute bottom-0 left-0 right-0 bg-black bg-opacity-60 p-1.5 flex justify-between items-center z-10", children: [
17609
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `absolute bottom-0 left-0 right-0 bg-black bg-opacity-60 ${compact ? "p-1" : "p-1.5"} flex justify-between items-center z-10`, children: [
17478
17610
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
17479
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Camera, { size: 12, className: "text-white" }),
17480
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-white text-xs font-medium tracking-wide", children: displayName })
17611
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Camera, { size: compact ? 10 : 12, className: "text-white" }),
17612
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-white ${compact ? "text-[10px]" : "text-xs"} font-medium tracking-wide`, children: displayName })
17481
17613
  ] }),
17482
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
17614
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center ${compact ? "gap-1" : "gap-1.5"}`, children: [
17483
17615
  trendInfo && /* @__PURE__ */ jsxRuntime.jsx(
17484
17616
  "div",
17485
17617
  {
17486
- className: `text-lg ${trendInfo.color}`,
17618
+ className: `${compact ? "text-sm" : "text-lg"} ${trendInfo.color}`,
17487
17619
  style: { lineHeight: 1, display: "flex", alignItems: "center" },
17488
17620
  children: trendInfo.arrow
17489
17621
  }
17490
17622
  ),
17491
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-1.5 h-1.5 rounded-full bg-green-500" }),
17492
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-white text-xs", children: "Live" })
17623
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${compact ? "w-1 h-1" : "w-1.5 h-1.5"} rounded-full bg-green-500` }),
17624
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-white ${compact ? "text-[10px]" : "text-xs"}`, children: "Live" })
17493
17625
  ] })
17494
17626
  ] })
17495
17627
  ]
@@ -17516,7 +17648,6 @@ var VideoGridView = React14__namespace.default.memo(({
17516
17648
  workspaces,
17517
17649
  selectedLine,
17518
17650
  className = "",
17519
- lineIdMapping = {},
17520
17651
  videoSources = {}
17521
17652
  }) => {
17522
17653
  const router$1 = router.useRouter();
@@ -17581,15 +17712,15 @@ var VideoGridView = React14__namespace.default.memo(({
17581
17712
  let bestScore = 0;
17582
17713
  const targetAspectRatio = 16 / 9;
17583
17714
  const gap = 8;
17584
- const maxCols = Math.min(count, 6);
17715
+ const maxCols = Math.min(count, selectedLine ? 6 : 12);
17585
17716
  for (let cols = 1; cols <= maxCols; cols++) {
17586
17717
  const rows = Math.ceil(count / cols);
17587
17718
  const availableWidth = containerWidth - gap * (cols - 1);
17588
17719
  const availableHeight = containerHeight - gap * (rows - 1);
17589
17720
  const cellWidth = availableWidth / cols;
17590
17721
  const cellHeight = availableHeight / rows;
17591
- const minCellWidth = containerWidth < 800 ? 120 : 150;
17592
- const minCellHeight = containerHeight < 600 ? 80 : 100;
17722
+ const minCellWidth = selectedLine ? containerWidth < 800 ? 120 : 150 : containerWidth < 800 ? 80 : 100;
17723
+ const minCellHeight = selectedLine ? containerHeight < 600 ? 80 : 100 : containerHeight < 600 ? 60 : 80;
17593
17724
  if (cellWidth < minCellWidth || cellHeight < minCellHeight) continue;
17594
17725
  const totalUsedArea = cellWidth * cellHeight * count;
17595
17726
  const totalAvailableArea = containerWidth * containerHeight;
@@ -17606,7 +17737,7 @@ var VideoGridView = React14__namespace.default.memo(({
17606
17737
  bestCols = Math.ceil(Math.sqrt(count));
17607
17738
  }
17608
17739
  setGridCols(bestCols);
17609
- }, [filteredWorkspaces.length]);
17740
+ }, [filteredWorkspaces.length, selectedLine]);
17610
17741
  React14.useEffect(() => {
17611
17742
  calculateOptimalGrid();
17612
17743
  const handleResize = () => calculateOptimalGrid();
@@ -17665,16 +17796,17 @@ var VideoGridView = React14__namespace.default.memo(({
17665
17796
  minHeight: "100%"
17666
17797
  },
17667
17798
  children: filteredWorkspaces.sort((a, b) => {
17668
- const aNum = parseInt(a.workspace_name.slice(2));
17669
- const bNum = parseInt(b.workspace_name.slice(2));
17670
- if (!selectedLine) {
17671
- const aIsLine2 = a.line_id === lineIdMapping.line2;
17672
- const bIsLine2 = b.line_id === lineIdMapping.line2;
17673
- if (aIsLine2 !== bIsLine2) {
17674
- return aIsLine2 ? 1 : -1;
17675
- }
17799
+ if (a.line_id !== b.line_id) {
17800
+ return (a.line_id || "").localeCompare(b.line_id || "");
17801
+ }
17802
+ const aMatch = a.workspace_name.match(/WS(\d+)/);
17803
+ const bMatch = b.workspace_name.match(/WS(\d+)/);
17804
+ if (aMatch && bMatch) {
17805
+ const aNum = parseInt(aMatch[1]);
17806
+ const bNum = parseInt(bMatch[1]);
17807
+ return aNum - bNum;
17676
17808
  }
17677
- return aNum - bNum;
17809
+ return a.workspace_name.localeCompare(b.workspace_name);
17678
17810
  }).map((workspace) => {
17679
17811
  const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
17680
17812
  const isVisible = visibleWorkspaces.has(workspaceId);
@@ -17697,7 +17829,8 @@ var VideoGridView = React14__namespace.default.memo(({
17697
17829
  isVeryLowEfficiency,
17698
17830
  cropping: workspaceCropping,
17699
17831
  canvasFps: canvasConfig?.fps,
17700
- useRAF: canvasConfig?.useRAF
17832
+ useRAF: canvasConfig?.useRAF,
17833
+ compact: !selectedLine
17701
17834
  }
17702
17835
  )
17703
17836
  },
@@ -21261,7 +21394,7 @@ function isValidShiftId(shiftId) {
21261
21394
  }
21262
21395
 
21263
21396
  // src/lib/api/s3-clips-parser.ts
21264
- function parseS3Uri(s3Uri) {
21397
+ function parseS3Uri(s3Uri, sopCategories) {
21265
21398
  const path = new URL(s3Uri).pathname;
21266
21399
  const parts = path.split("/").filter((p) => p);
21267
21400
  console.log("S3 URI:", s3Uri);
@@ -21301,6 +21434,27 @@ function parseS3Uri(s3Uri) {
21301
21434
  let description = "Analysis Clip";
21302
21435
  const normalizedViolationType = violationType.toLowerCase().trim();
21303
21436
  console.log(`Parsing violation type: "${violationType}" (normalized: "${normalizedViolationType}") from path: ${s3Uri}`);
21437
+ if (sopCategories && sopCategories.length > 0) {
21438
+ const matchedCategory = sopCategories.find((category) => {
21439
+ const categoryId = category.id.toLowerCase();
21440
+ const s3FolderName = (category.s3FolderName || category.id).toLowerCase();
21441
+ return categoryId === normalizedViolationType || s3FolderName === normalizedViolationType || // Also check for partial matches for flexibility
21442
+ normalizedViolationType.includes(categoryId) || normalizedViolationType.includes(s3FolderName);
21443
+ });
21444
+ if (matchedCategory) {
21445
+ type = matchedCategory.id;
21446
+ description = matchedCategory.description || matchedCategory.label;
21447
+ if (matchedCategory.color.includes("red")) {
21448
+ severity = "high";
21449
+ } else if (matchedCategory.color.includes("yellow") || matchedCategory.color.includes("orange")) {
21450
+ severity = "medium";
21451
+ } else {
21452
+ severity = "low";
21453
+ }
21454
+ console.log(`Matched SOP category: ${matchedCategory.id} for violation type: ${violationType}`);
21455
+ return { timestamp, severity, description, type, originalUri: s3Uri };
21456
+ }
21457
+ }
21304
21458
  switch (normalizedViolationType) {
21305
21459
  case "idle_time":
21306
21460
  case "idle":
@@ -21540,11 +21694,23 @@ var S3ClipsService = class {
21540
21694
  const key = url.pathname.startsWith("/") ? url.pathname.substring(1) : url.pathname;
21541
21695
  return `${this.config.s3Config.cloudFrontDomain}/${key}`;
21542
21696
  }
21697
+ /**
21698
+ * Gets SOP categories for a specific workspace
21699
+ */
21700
+ getSOPCategories(workspaceId) {
21701
+ const sopConfig = this.config.s3Config?.sopCategories;
21702
+ if (!sopConfig) return void 0;
21703
+ if (sopConfig.workspaceOverrides && sopConfig.workspaceOverrides[workspaceId]) {
21704
+ return sopConfig.workspaceOverrides[workspaceId];
21705
+ }
21706
+ return sopConfig.default;
21707
+ }
21543
21708
  /**
21544
21709
  * Processes a single video completely
21545
21710
  */
21546
21711
  async processFullVideo(uri, index, workspaceId, date, shiftId, includeCycleTime, includeMetadata = false) {
21547
- const parsedInfo = parseS3Uri(uri);
21712
+ const sopCategories = this.getSOPCategories(workspaceId);
21713
+ const parsedInfo = parseS3Uri(uri, sopCategories);
21548
21714
  if (!parsedInfo) {
21549
21715
  console.warn(`Skipping URI due to parsing failure: ${uri}`);
21550
21716
  return null;
@@ -21577,27 +21743,32 @@ var S3ClipsService = class {
21577
21743
  async getVideoSummary(workspaceId, date, shiftId) {
21578
21744
  const s3Uris = await this.listS3Clips({ workspaceId, date, shiftId });
21579
21745
  console.log(`S3ClipsService getVideoSummary: Processing ${s3Uris.length} total URIs for accurate category counts`);
21580
- const counts = {
21581
- best_cycle_time: 0,
21582
- worst_cycle_time: 0,
21583
- bottleneck: 0,
21584
- low_value: 0,
21585
- long_cycle_time: 0,
21586
- missing_quality_check: 0,
21587
- cycle_completions: 0,
21588
- total: 0
21589
- };
21590
- const samples = {
21591
- best_cycle_time: null,
21592
- worst_cycle_time: null,
21593
- bottleneck: null,
21594
- low_value: null,
21595
- long_cycle_time: null,
21596
- missing_quality_check: null,
21597
- cycle_completions: null
21598
- };
21746
+ const sopCategories = this.getSOPCategories(workspaceId);
21747
+ const counts = { total: 0 };
21748
+ const samples = {};
21749
+ if (sopCategories && sopCategories.length > 0) {
21750
+ sopCategories.forEach((category) => {
21751
+ counts[category.id] = 0;
21752
+ samples[category.id] = null;
21753
+ });
21754
+ } else {
21755
+ counts.best_cycle_time = 0;
21756
+ counts.worst_cycle_time = 0;
21757
+ counts.bottleneck = 0;
21758
+ counts.low_value = 0;
21759
+ counts.long_cycle_time = 0;
21760
+ counts.missing_quality_check = 0;
21761
+ counts.cycle_completions = 0;
21762
+ samples.best_cycle_time = null;
21763
+ samples.worst_cycle_time = null;
21764
+ samples.bottleneck = null;
21765
+ samples.low_value = null;
21766
+ samples.long_cycle_time = null;
21767
+ samples.missing_quality_check = null;
21768
+ samples.cycle_completions = null;
21769
+ }
21599
21770
  for (const uri of s3Uris) {
21600
- const parsedInfo = parseS3Uri(uri);
21771
+ const parsedInfo = parseS3Uri(uri, sopCategories);
21601
21772
  if (parsedInfo) {
21602
21773
  const { type } = parsedInfo;
21603
21774
  counts[type] = (counts[type] || 0) + 1;
@@ -21659,7 +21830,7 @@ var S3ClipsService = class {
21659
21830
  }
21660
21831
  return summary;
21661
21832
  }
21662
- const limitPerCategory = limit ? Math.min(Math.max(limit, 1), 200) : 30;
21833
+ const limitPerCategory = limit ? Math.min(Math.max(limit, 1), 1e3) : 30;
21663
21834
  const shouldFetchAll = category === "missing_quality_check" || category === "low_value";
21664
21835
  const initialFetchLimit = shouldFetchAll ? void 0 : category ? limitPerCategory * 3 : void 0;
21665
21836
  const s3Uris = await this.listS3Clips({ workspaceId, date, shiftId, maxKeys: initialFetchLimit });
@@ -21810,6 +21981,14 @@ var BottlenecksContent = ({
21810
21981
  className
21811
21982
  }) => {
21812
21983
  const dashboardConfig = useDashboardConfig();
21984
+ const sopCategories = React14__namespace.default.useMemo(() => {
21985
+ const sopConfig = dashboardConfig?.s3Config?.sopCategories;
21986
+ if (!sopConfig) return null;
21987
+ if (sopConfig.workspaceOverrides && sopConfig.workspaceOverrides[workspaceId]) {
21988
+ return sopConfig.workspaceOverrides[workspaceId];
21989
+ }
21990
+ return sopConfig.default;
21991
+ }, [dashboardConfig, workspaceId]);
21813
21992
  const videoRef = React14.useRef(null);
21814
21993
  const fullscreenContainerRef = React14.useRef(null);
21815
21994
  const timestampFilterRef = React14.useRef(null);
@@ -21818,7 +21997,9 @@ var BottlenecksContent = ({
21818
21997
  const [duration, setDuration] = React14.useState(0);
21819
21998
  const [isFullscreen, setIsFullscreen] = React14.useState(false);
21820
21999
  const [currentIndex, setCurrentIndex] = React14.useState(0);
21821
- const [activeFilter, setActiveFilter] = React14.useState("low_value");
22000
+ const [activeFilter, setActiveFilter] = React14.useState(
22001
+ sopCategories && sopCategories.length > 0 ? sopCategories[0].id : "low_value"
22002
+ );
21822
22003
  const [allVideos, setAllVideos] = React14.useState([]);
21823
22004
  const [isLoading, setIsLoading] = React14.useState(true);
21824
22005
  const [error, setError] = React14.useState(null);
@@ -21930,27 +22111,41 @@ var BottlenecksContent = ({
21930
22111
  let filtered = [];
21931
22112
  if (activeFilter === "all") {
21932
22113
  filtered = [...allVideos];
21933
- } else if (activeFilter === "low_value") {
21934
- filtered = allVideos.filter((video) => video.type === "low_value");
21935
- } else if (activeFilter === "sop_deviations") {
21936
- filtered = allVideos.filter((video) => video.type === "missing_quality_check");
21937
- } else if (activeFilter === "best_cycle_time") {
21938
- filtered = allVideos.filter((video) => video.type === "best_cycle_time");
21939
- } else if (activeFilter === "worst_cycle_time") {
21940
- filtered = allVideos.filter((video) => video.type === "worst_cycle_time");
21941
- } else if (activeFilter === "cycle_completions") {
21942
- filtered = allVideos.filter((video) => video.type === "cycle_completions");
21943
- } else if (activeFilter === "long_cycle_time") {
21944
- filtered = allVideos.filter(
21945
- (video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
21946
- );
21947
22114
  } else {
21948
- filtered = allVideos.filter((video) => video.type === "bottleneck" && video.severity === activeFilter);
22115
+ if (sopCategories && sopCategories.length > 0) {
22116
+ const selectedCategory = sopCategories.find((cat) => cat.id === activeFilter);
22117
+ if (selectedCategory) {
22118
+ filtered = allVideos.filter((video) => video.type === selectedCategory.id);
22119
+ if (selectedCategory.id === "long_cycle_time") {
22120
+ filtered = allVideos.filter(
22121
+ (video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
22122
+ );
22123
+ }
22124
+ }
22125
+ } else {
22126
+ if (activeFilter === "low_value") {
22127
+ filtered = allVideos.filter((video) => video.type === "low_value");
22128
+ } else if (activeFilter === "sop_deviations") {
22129
+ filtered = allVideos.filter((video) => video.type === "missing_quality_check");
22130
+ } else if (activeFilter === "best_cycle_time") {
22131
+ filtered = allVideos.filter((video) => video.type === "best_cycle_time");
22132
+ } else if (activeFilter === "worst_cycle_time") {
22133
+ filtered = allVideos.filter((video) => video.type === "worst_cycle_time");
22134
+ } else if (activeFilter === "cycle_completions") {
22135
+ filtered = allVideos.filter((video) => video.type === "cycle_completions");
22136
+ } else if (activeFilter === "long_cycle_time") {
22137
+ filtered = allVideos.filter(
22138
+ (video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
22139
+ );
22140
+ } else {
22141
+ filtered = allVideos.filter((video) => video.type === "bottleneck" && video.severity === activeFilter);
22142
+ }
22143
+ }
21949
22144
  }
21950
22145
  return filtered.sort((a, b) => {
21951
22146
  return new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime();
21952
22147
  });
21953
- }, [activeFilter, allVideos]);
22148
+ }, [activeFilter, allVideos, sopCategories]);
21954
22149
  React14.useEffect(() => {
21955
22150
  if (filteredVideos.length === 0) return;
21956
22151
  const upcoming = [];
@@ -22224,35 +22419,34 @@ var BottlenecksContent = ({
22224
22419
  }
22225
22420
  };
22226
22421
  const clipCounts = React14.useMemo(() => {
22227
- if (!allVideos) return {
22228
- bottlenecks: 0,
22229
- lowValue: 0,
22230
- highSeverity: 0,
22231
- mediumSeverity: 0,
22232
- lowSeverity: 0,
22233
- sopDeviations: 0,
22234
- bestCycleTimes: 0,
22235
- worstCycleTimes: 0,
22236
- longCycleTimes: 0,
22237
- cycleCompletions: 0,
22238
- total: 0
22239
- };
22240
- return {
22241
- bottlenecks: allVideos.filter((video) => video.type === "bottleneck").length,
22242
- lowValue: allVideos.filter((video) => video.type === "low_value").length,
22243
- highSeverity: allVideos.filter((video) => video.severity === "high" && video.type === "bottleneck").length,
22244
- mediumSeverity: allVideos.filter((video) => video.severity === "medium" && video.type === "bottleneck").length,
22245
- lowSeverity: allVideos.filter((video) => video.severity === "low" && video.type === "bottleneck").length,
22246
- sopDeviations: allVideos.filter((video) => video.type === "missing_quality_check").length,
22247
- bestCycleTimes: allVideos.filter((video) => video.type === "best_cycle_time").length,
22248
- worstCycleTimes: allVideos.filter((video) => video.type === "worst_cycle_time").length,
22249
- longCycleTimes: allVideos.filter(
22422
+ if (!allVideos) return {};
22423
+ const counts = { total: allVideos.length };
22424
+ if (sopCategories && sopCategories.length > 0) {
22425
+ sopCategories.forEach((category) => {
22426
+ if (category.id === "long_cycle_time") {
22427
+ counts[category.id] = allVideos.filter(
22428
+ (video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
22429
+ ).length;
22430
+ } else {
22431
+ counts[category.id] = allVideos.filter((video) => video.type === category.id).length;
22432
+ }
22433
+ });
22434
+ } else {
22435
+ counts.bottlenecks = allVideos.filter((video) => video.type === "bottleneck").length;
22436
+ counts.lowValue = allVideos.filter((video) => video.type === "low_value").length;
22437
+ counts.highSeverity = allVideos.filter((video) => video.severity === "high" && video.type === "bottleneck").length;
22438
+ counts.mediumSeverity = allVideos.filter((video) => video.severity === "medium" && video.type === "bottleneck").length;
22439
+ counts.lowSeverity = allVideos.filter((video) => video.severity === "low" && video.type === "bottleneck").length;
22440
+ counts.sopDeviations = allVideos.filter((video) => video.type === "missing_quality_check").length;
22441
+ counts.bestCycleTimes = allVideos.filter((video) => video.type === "best_cycle_time").length;
22442
+ counts.worstCycleTimes = allVideos.filter((video) => video.type === "worst_cycle_time").length;
22443
+ counts.longCycleTimes = allVideos.filter(
22250
22444
  (video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
22251
- ).length,
22252
- cycleCompletions: allVideos.filter((video) => video.type === "cycle_completions").length,
22253
- total: allVideos.length
22254
- };
22255
- }, [allVideos]);
22445
+ ).length;
22446
+ counts.cycleCompletions = allVideos.filter((video) => video.type === "cycle_completions").length;
22447
+ }
22448
+ return counts;
22449
+ }, [allVideos, sopCategories]);
22256
22450
  const currentVideo = React14.useMemo(() => {
22257
22451
  if (!filteredVideos || filteredVideos.length === 0 || currentIndex >= filteredVideos.length) {
22258
22452
  return null;
@@ -22277,6 +22471,19 @@ var BottlenecksContent = ({
22277
22471
  return "Bottleneck";
22278
22472
  }
22279
22473
  };
22474
+ const getColorClasses = (color2) => {
22475
+ const colorMap = {
22476
+ purple: { text: "text-purple-500", bg: "bg-purple-500", dot: "bg-purple-500" },
22477
+ green: { text: "text-green-600", bg: "bg-green-600", dot: "bg-green-600" },
22478
+ red: { text: "text-red-700", bg: "bg-red-700", dot: "bg-red-700" },
22479
+ "red-dark": { text: "text-red-500", bg: "bg-red-500", dot: "bg-red-500" },
22480
+ blue: { text: "text-blue-600", bg: "bg-blue-600", dot: "bg-blue-600" },
22481
+ orange: { text: "text-orange-600", bg: "bg-orange-600", dot: "bg-orange-600" },
22482
+ yellow: { text: "text-yellow-600", bg: "bg-yellow-600", dot: "bg-yellow-600" },
22483
+ gray: { text: "text-gray-600", bg: "bg-gray-600", dot: "bg-gray-600" }
22484
+ };
22485
+ return colorMap[color2] || colorMap.gray;
22486
+ };
22280
22487
  const formatTimeOnly = (time2) => {
22281
22488
  if (!time2) return "";
22282
22489
  try {
@@ -22306,162 +22513,62 @@ var BottlenecksContent = ({
22306
22513
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-600 max-w-md", children: error })
22307
22514
  ] });
22308
22515
  }
22516
+ const categoriesToShow = sopCategories && sopCategories.length > 0 ? sopCategories : [
22517
+ // Default hardcoded categories if no configuration
22518
+ { id: "low_value", label: "Idle Moments", color: "purple", subtitle: "Idle time detected" },
22519
+ { id: "best_cycle_time", label: "Best Cycle Time", color: "green", subtitle: "Fastest cycle today" },
22520
+ { id: "worst_cycle_time", label: "Worst Cycle Time", color: "red", subtitle: "Slowest cycle today" },
22521
+ { id: "long_cycle_time", label: "Long Cycle Time", color: "red-dark", subtitle: "Above standard cycle times" },
22522
+ { id: "cycle_completions", label: "Cycle Completions", color: "blue", subtitle: "Completed production cycles" }
22523
+ ];
22309
22524
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-grow p-1.5 sm:p-2 lg:p-4 h-[calc(100vh-12rem)]", children: [
22310
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-3 mb-4", children: [
22311
- /* @__PURE__ */ jsxRuntime.jsxs(
22312
- Card2,
22313
- {
22314
- onClick: () => {
22315
- setActiveFilter("low_value");
22316
- trackCoreEvent("Idle Moments Filter Clicked", {
22317
- workspaceId,
22318
- workspaceName,
22319
- date,
22320
- filterType: "low_value",
22321
- clipCount: clipCounts.lowValue
22322
- });
22323
- },
22324
- className: `bg-white shadow-sm cursor-pointer transition-all duration-200 hover:bg-gray-50 ${activeFilter === "low_value" ? "bg-blue-50 shadow-md ring-1 ring-blue-200" : ""}`,
22325
- "aria-label": `Filter by Idle Moments (${clipCounts.lowValue} clips)`,
22326
- role: "button",
22327
- tabIndex: 0,
22328
- onKeyDown: (e) => e.key === "Enter" && setActiveFilter("low_value"),
22329
- children: [
22330
- /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: `text-lg ${activeFilter === "low_value" ? "text-blue-600" : ""}`, children: "Idle Moments" }) }),
22331
- /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col justify-center", children: [
22332
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-3xl font-bold text-purple-500", children: clipCounts.lowValue }),
22333
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
22334
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-purple-500 mr-1.5" }),
22335
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Idle time detected" })
22336
- ] })
22337
- ] }) })
22338
- ]
22339
- }
22340
- ),
22341
- /* @__PURE__ */ jsxRuntime.jsxs(
22525
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `grid grid-cols-1 sm:grid-cols-2 ${categoriesToShow.length <= 5 ? "lg:grid-cols-5" : "lg:grid-cols-6"} gap-3 mb-4`, children: categoriesToShow.map((category) => {
22526
+ const colorClasses = getColorClasses(category.color);
22527
+ const count = clipCounts[category.id] || 0;
22528
+ return /* @__PURE__ */ jsxRuntime.jsxs(
22342
22529
  Card2,
22343
22530
  {
22344
22531
  onClick: () => {
22345
- setActiveFilter("best_cycle_time");
22346
- trackCoreEvent("Best Cycle Time Filter Clicked", {
22532
+ setActiveFilter(category.id);
22533
+ trackCoreEvent(`${category.label} Filter Clicked`, {
22347
22534
  workspaceId,
22348
22535
  workspaceName,
22349
22536
  date,
22350
- filterType: "best_cycle_time",
22351
- clipCount: clipCounts.bestCycleTimes
22537
+ filterType: category.id,
22538
+ clipCount: count
22352
22539
  });
22353
22540
  },
22354
- className: `bg-white shadow-sm cursor-pointer transition-all duration-200 hover:bg-gray-50 ${activeFilter === "best_cycle_time" ? "bg-blue-50 shadow-md ring-1 ring-blue-200" : ""}`,
22355
- "aria-label": `Filter by Best Cycle Time (${clipCounts.bestCycleTimes} clips)`,
22541
+ className: `bg-white shadow-sm cursor-pointer transition-all duration-200 hover:bg-gray-50 ${activeFilter === category.id ? "bg-blue-50 shadow-md ring-1 ring-blue-200" : ""}`,
22542
+ "aria-label": `Filter by ${category.label} (${count} clips)`,
22356
22543
  role: "button",
22357
22544
  tabIndex: 0,
22358
- onKeyDown: (e) => e.key === "Enter" && setActiveFilter("best_cycle_time"),
22545
+ onKeyDown: (e) => e.key === "Enter" && setActiveFilter(category.id),
22359
22546
  children: [
22360
- /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: `text-lg ${activeFilter === "best_cycle_time" ? "text-blue-600" : ""}`, children: "Best Cycle Time" }) }),
22547
+ /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: `text-lg ${activeFilter === category.id ? "text-blue-600" : ""}`, children: category.label }) }),
22361
22548
  /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col justify-center", children: [
22362
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-3xl font-bold text-green-600", children: clipCounts.bestCycleTimes }),
22549
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-3xl font-bold ${colorClasses.text}`, children: count }),
22363
22550
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
22364
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-green-600 mr-1.5" }),
22365
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Fastest cycle today" })
22551
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `h-2 w-2 rounded-full ${colorClasses.dot} mr-1.5` }),
22552
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: category.subtitle || category.description || category.label })
22366
22553
  ] })
22367
22554
  ] }) })
22368
22555
  ]
22369
- }
22370
- ),
22371
- /* @__PURE__ */ jsxRuntime.jsxs(
22372
- Card2,
22373
- {
22374
- onClick: () => {
22375
- setActiveFilter("worst_cycle_time");
22376
- trackCoreEvent("Worst Cycle Time Filter Clicked", {
22377
- workspaceId,
22378
- workspaceName,
22379
- date,
22380
- filterType: "worst_cycle_time",
22381
- clipCount: clipCounts.worstCycleTimes
22382
- });
22383
- },
22384
- className: `bg-white shadow-sm cursor-pointer transition-all duration-200 hover:bg-gray-50 ${activeFilter === "worst_cycle_time" ? "bg-blue-50 shadow-md ring-1 ring-blue-200" : ""}`,
22385
- "aria-label": `Filter by Worst Cycle Time (${clipCounts.worstCycleTimes} clips)`,
22386
- role: "button",
22387
- tabIndex: 0,
22388
- onKeyDown: (e) => e.key === "Enter" && setActiveFilter("worst_cycle_time"),
22389
- children: [
22390
- /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: `text-lg ${activeFilter === "worst_cycle_time" ? "text-blue-600" : ""}`, children: "Worst Cycle Time" }) }),
22391
- /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col justify-center", children: [
22392
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-3xl font-bold text-red-700", children: clipCounts.worstCycleTimes }),
22393
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
22394
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-red-700 mr-1.5" }),
22395
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Slowest cycle today" })
22396
- ] })
22397
- ] }) })
22398
- ]
22399
- }
22400
- ),
22401
- /* @__PURE__ */ jsxRuntime.jsxs(
22402
- Card2,
22403
- {
22404
- onClick: () => {
22405
- setActiveFilter("long_cycle_time");
22406
- trackCoreEvent("Long Cycle Time Filter Clicked", {
22407
- workspaceId,
22408
- workspaceName,
22409
- date,
22410
- filterType: "long_cycle_time",
22411
- clipCount: clipCounts.longCycleTimes
22412
- });
22413
- },
22414
- className: `bg-white shadow-sm cursor-pointer transition-all duration-200 hover:bg-gray-50 ${activeFilter === "long_cycle_time" ? "bg-blue-50 shadow-md ring-1 ring-blue-200" : ""}`,
22415
- "aria-label": `Filter by Long Cycle Time Bottlenecks (${clipCounts.longCycleTimes} clips)`,
22416
- role: "button",
22417
- tabIndex: 0,
22418
- onKeyDown: (e) => e.key === "Enter" && setActiveFilter("long_cycle_time"),
22419
- children: [
22420
- /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: `text-lg ${activeFilter === "long_cycle_time" ? "text-blue-600" : ""}`, children: "Long Cycle Time" }) }),
22421
- /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col justify-center", children: [
22422
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-3xl font-bold text-red-500", children: clipCounts.longCycleTimes }),
22423
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
22424
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-red-500 mr-1.5" }),
22425
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Above standard cycle times" })
22426
- ] })
22427
- ] }) })
22428
- ]
22429
- }
22430
- ),
22431
- /* @__PURE__ */ jsxRuntime.jsxs(
22432
- Card2,
22433
- {
22434
- onClick: () => {
22435
- setActiveFilter("cycle_completions");
22436
- trackCoreEvent("Cycle Completions Filter Clicked", {
22437
- workspaceId,
22438
- workspaceName,
22439
- date,
22440
- filterType: "cycle_completions",
22441
- clipCount: clipCounts.cycleCompletions
22442
- });
22443
- },
22444
- className: `bg-white shadow-sm cursor-pointer transition-all duration-200 hover:bg-gray-50 ${activeFilter === "cycle_completions" ? "bg-blue-50 shadow-md ring-1 ring-blue-200" : ""}`,
22445
- "aria-label": `Filter by Cycle Completions (${clipCounts.cycleCompletions} clips)`,
22446
- role: "button",
22447
- tabIndex: 0,
22448
- onKeyDown: (e) => e.key === "Enter" && setActiveFilter("cycle_completions"),
22449
- children: [
22450
- /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: `text-lg ${activeFilter === "cycle_completions" ? "text-blue-600" : ""}`, children: "Cycle Completions" }) }),
22451
- /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col justify-center", children: [
22452
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-3xl font-bold text-blue-600", children: clipCounts.cycleCompletions }),
22453
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
22454
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-blue-600 mr-1.5" }),
22455
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Completed production cycles" })
22456
- ] })
22457
- ] }) })
22458
- ]
22459
- }
22460
- )
22461
- ] }),
22556
+ },
22557
+ category.id
22558
+ );
22559
+ }) }),
22462
22560
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg shadow-sm overflow-hidden", style: { height: "calc(100% - 8.5rem)" }, children: [
22463
22561
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-3 border-b border-gray-100", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [
22464
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-800", children: activeFilter === "low_value" ? `Idle Moments (${clipCounts.lowValue})` : activeFilter === "best_cycle_time" ? `Best Cycle Time (${clipCounts.bestCycleTimes})` : activeFilter === "worst_cycle_time" ? `Worst Cycle Time (${clipCounts.worstCycleTimes})` : activeFilter === "long_cycle_time" ? `Long Cycle Time (${clipCounts.longCycleTimes})` : activeFilter === "cycle_completions" ? `Cycle Completions (${clipCounts.cycleCompletions})` : `All Clips (${clipCounts.total})` }),
22562
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-800", children: (() => {
22563
+ if (activeFilter === "all") {
22564
+ return `All Clips (${clipCounts.total || 0})`;
22565
+ }
22566
+ const activeCategory = categoriesToShow.find((cat) => cat.id === activeFilter);
22567
+ if (activeCategory) {
22568
+ return `${activeCategory.label} (${clipCounts[activeCategory.id] || 0})`;
22569
+ }
22570
+ return activeFilter === "low_value" ? `Idle Moments (${clipCounts.lowValue || 0})` : activeFilter === "best_cycle_time" ? `Best Cycle Time (${clipCounts.bestCycleTimes || 0})` : activeFilter === "worst_cycle_time" ? `Worst Cycle Time (${clipCounts.worstCycleTimes || 0})` : activeFilter === "long_cycle_time" ? `Long Cycle Time (${clipCounts.longCycleTimes || 0})` : activeFilter === "cycle_completions" ? `Cycle Completions (${clipCounts.cycleCompletions || 0})` : `All Clips (${clipCounts.total || 0})`;
22571
+ })() }),
22465
22572
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-2", children: [
22466
22573
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", ref: timestampFilterRef, children: [
22467
22574
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -23501,7 +23608,7 @@ var KPISection = React14.memo(({
23501
23608
  });
23502
23609
  KPISection.displayName = "KPISection";
23503
23610
  var ISTTimer2 = ISTTimer_default;
23504
- var DashboardHeader = React14.memo(({ lineTitle, className = "" }) => {
23611
+ var DashboardHeader = React14.memo(({ lineTitle, className = "", headerControls }) => {
23505
23612
  const getShiftName = () => {
23506
23613
  const now2 = /* @__PURE__ */ new Date();
23507
23614
  const currentHour = now2.getHours();
@@ -23515,30 +23622,33 @@ var DashboardHeader = React14.memo(({ lineTitle, className = "" }) => {
23515
23622
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
23516
23623
  }
23517
23624
  };
23518
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-col ${className}`, children: [
23519
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 sm:gap-2 md:gap-3", children: [
23520
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-base sm:text-xl md:text-2xl lg:text-3xl font-bold text-gray-800 tracking-tight leading-none", children: lineTitle }),
23521
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1 w-1 sm:h-1.5 sm:w-1.5 md:h-2 md:w-2 rounded-full bg-green-500 animate-pulse ring-1 sm:ring-2 ring-green-500/30 ring-offset-1" })
23522
- ] }),
23523
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 inline-flex items-center gap-3", children: [
23524
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm font-medium text-gray-600", children: [
23525
- /* @__PURE__ */ jsxRuntime.jsx(ISTTimer2, {}),
23526
- " IST"
23625
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-row items-center justify-between w-full ${className}`, children: [
23626
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
23627
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 sm:gap-2 md:gap-3", children: [
23628
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-base sm:text-xl md:text-2xl lg:text-3xl font-bold text-gray-800 tracking-tight leading-none", children: lineTitle }),
23629
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1 w-1 sm:h-1.5 sm:w-1.5 md:h-2 md:w-2 rounded-full bg-green-500 animate-pulse ring-1 sm:ring-2 ring-green-500/30 ring-offset-1" })
23527
23630
  ] }),
23528
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1", children: [
23529
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children: getShiftIcon() }),
23530
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
23531
- getShiftName(),
23532
- " Shift"
23631
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 inline-flex items-center gap-3", children: [
23632
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm font-medium text-gray-600", children: [
23633
+ /* @__PURE__ */ jsxRuntime.jsx(ISTTimer2, {}),
23634
+ " IST"
23635
+ ] }),
23636
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1", children: [
23637
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children: getShiftIcon() }),
23638
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
23639
+ getShiftName(),
23640
+ " Shift"
23641
+ ] })
23533
23642
  ] })
23534
23643
  ] })
23535
- ] })
23644
+ ] }),
23645
+ headerControls && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-4", children: headerControls })
23536
23646
  ] });
23537
23647
  });
23538
23648
  DashboardHeader.displayName = "DashboardHeader";
23539
- var NoWorkspaceData = React14.memo(({ className = "" }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex h-full items-center justify-center ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg bg-white p-4 shadow-md", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-2 text-gray-500", children: [
23649
+ var NoWorkspaceData = React14.memo(({ message = "No workspace data available", className = "" }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex h-full items-center justify-center ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg bg-white p-4 shadow-md", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-2 text-gray-500", children: [
23540
23650
  /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", clipRule: "evenodd" }) }),
23541
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "No workspace data available" })
23651
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: message })
23542
23652
  ] }) }) }));
23543
23653
  NoWorkspaceData.displayName = "NoWorkspaceData";
23544
23654
  var WorkspaceMonthlyDataFetcher = ({
@@ -23880,15 +23990,14 @@ var SideNavBar = React14.memo(({
23880
23990
  }
23881
23991
  }
23882
23992
  }), [navigate, lineId]);
23883
- const handleLeaderboardClick = React14.useCallback(() => navigate(`/leaderboard/${lineId}`, {
23993
+ const handleLeaderboardClick = React14.useCallback(() => navigate(`/leaderboard`, {
23884
23994
  trackingEvent: {
23885
23995
  name: "Leaderboard Page Clicked",
23886
23996
  properties: {
23887
- source: "side_nav",
23888
- line_id: lineId
23997
+ source: "side_nav"
23889
23998
  }
23890
23999
  }
23891
- }), [navigate, lineId]);
24000
+ }), [navigate]);
23892
24001
  const handleKPIsClick = React14.useCallback(() => navigate(`/kpis`, {
23893
24002
  trackingEvent: {
23894
24003
  name: "KPI Page Clicked",
@@ -24835,14 +24944,6 @@ var AIAgentView = () => {
24835
24944
  return newMap;
24836
24945
  });
24837
24946
  },
24838
- onReasoning: (text) => {
24839
- setStreamingStates((prev) => {
24840
- const newMap = new Map(prev);
24841
- const current = newMap.get(currentThreadId) || { message: "", reasoning: "" };
24842
- newMap.set(currentThreadId, { ...current, reasoning: current.reasoning + text });
24843
- return newMap;
24844
- });
24845
- },
24846
24947
  onComplete: async (messageId) => {
24847
24948
  if (currentThreadId && !currentThreadId.startsWith("temp-")) {
24848
24949
  const updatedMessages = await getAllThreadMessages(currentThreadId);
@@ -27220,8 +27321,8 @@ var LoadingOverlayCmp = LoadingOverlay_default;
27220
27321
  function HomeView({
27221
27322
  defaultLineId,
27222
27323
  factoryViewId,
27223
- line1Uuid,
27224
- line2Uuid,
27324
+ lineIds: allLineIds = [],
27325
+ // Default to empty array
27225
27326
  lineNames,
27226
27327
  videoSources = {
27227
27328
  workspaceHlsUrls: {},
@@ -27230,14 +27331,21 @@ function HomeView({
27230
27331
  factoryName = "Simba Beer - Line 1"
27231
27332
  }) {
27232
27333
  const [isHydrated, setIsHydrated] = React14.useState(false);
27233
- const [selectedLineId, setSelectedLineId] = React14.useState(defaultLineId);
27334
+ const availableLineIds = React14.useMemo(() => [factoryViewId, ...allLineIds], [factoryViewId, allLineIds]);
27335
+ const [selectedLineId, setSelectedLineId] = React14.useState(factoryViewId);
27234
27336
  const [isChangingFilter, setIsChangingFilter] = React14.useState(false);
27235
27337
  const [errorMessage, setErrorMessage] = React14.useState(null);
27236
27338
  const [displayNamesInitialized, setDisplayNamesInitialized] = React14.useState(false);
27237
27339
  React14.useEffect(() => {
27238
27340
  const initDisplayNames = async () => {
27239
27341
  try {
27240
- await preInitializeWorkspaceDisplayNames(selectedLineId);
27342
+ if (selectedLineId === factoryViewId) {
27343
+ for (const lineId of allLineIds) {
27344
+ await preInitializeWorkspaceDisplayNames(lineId);
27345
+ }
27346
+ } else {
27347
+ await preInitializeWorkspaceDisplayNames(selectedLineId);
27348
+ }
27241
27349
  setDisplayNamesInitialized(true);
27242
27350
  } catch (error) {
27243
27351
  console.error("Failed to pre-initialize workspace display names:", error);
@@ -27245,7 +27353,7 @@ function HomeView({
27245
27353
  }
27246
27354
  };
27247
27355
  initDisplayNames();
27248
- }, [selectedLineId]);
27356
+ }, [selectedLineId, factoryViewId, allLineIds]);
27249
27357
  const {
27250
27358
  displayNames: workspaceDisplayNames,
27251
27359
  loading: displayNamesLoading,
@@ -27311,18 +27419,29 @@ function HomeView({
27311
27419
  setErrorMessage(null);
27312
27420
  }
27313
27421
  }, [metricsError, kpisError]);
27314
- React14.useCallback((e) => {
27422
+ const handleLineChange = React14.useCallback((value) => {
27315
27423
  setIsChangingFilter(true);
27316
- setSelectedLineId(e.target.value);
27424
+ setSelectedLineId(value);
27317
27425
  }, []);
27318
27426
  React14.useEffect(() => {
27319
- if (!metricsLoading && !kpisLoading && isChangingFilter && workspaceMetrics.length > 0) {
27320
- setIsChangingFilter(false);
27427
+ if (!metricsLoading && !kpisLoading && isChangingFilter) {
27428
+ if (workspaceMetrics.length > 0 || selectedLineId === factoryViewId) {
27429
+ setIsChangingFilter(false);
27430
+ }
27321
27431
  }
27322
- }, [metricsLoading, kpisLoading, workspaceMetrics, isChangingFilter]);
27432
+ }, [metricsLoading, kpisLoading, workspaceMetrics, isChangingFilter, selectedLineId, factoryViewId]);
27323
27433
  const lineTitle = React14.useMemo(() => {
27324
27434
  return factoryName;
27325
27435
  }, [factoryName]);
27436
+ const lineSelectorComponent = React14.useMemo(() => {
27437
+ if (allLineIds.length <= 1) {
27438
+ return null;
27439
+ }
27440
+ return /* @__PURE__ */ jsxRuntime.jsxs(Select, { onValueChange: handleLineChange, defaultValue: selectedLineId, children: [
27441
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "w-full sm:w-[200px] bg-white border border-gray-200 shadow-sm rounded-md h-9 text-sm", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Select a line" }) }),
27442
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { className: "z-50 bg-white shadow-lg border border-gray-200 rounded-md", children: availableLineIds.map((id3) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: id3, children: lineNames[id3] || (id3 === factoryViewId ? "All Lines" : `Line ${id3.substring(0, 4)}`) }, id3)) })
27443
+ ] });
27444
+ }, [availableLineIds, handleLineChange, selectedLineId, lineNames, factoryViewId, allLineIds.length]);
27326
27445
  const isLoading = !isHydrated || metricsLoading || kpisLoading || isChangingFilter || displayNamesLoading || !displayNamesInitialized;
27327
27446
  if (isLoading) {
27328
27447
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen bg-slate-50", children: /* @__PURE__ */ jsxRuntime.jsx(LoadingPageCmp, { message: "Loading dashboard..." }) });
@@ -27336,7 +27455,7 @@ function HomeView({
27336
27455
  ] })
27337
27456
  ] }) }) });
27338
27457
  }
27339
- if ((metricsLoading || kpisLoading) && (!workspaceMetrics || workspaceMetrics.length === 0)) {
27458
+ if ((metricsLoading || kpisLoading) && (!workspaceMetrics || workspaceMetrics.length === 0) && selectedLineId !== factoryViewId) {
27340
27459
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen bg-slate-50", children: /* @__PURE__ */ jsxRuntime.jsx(LoadingPageCmp, { message: "Loading metrics..." }) });
27341
27460
  }
27342
27461
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -27347,28 +27466,36 @@ function HomeView({
27347
27466
  animate: { opacity: 1 },
27348
27467
  children: [
27349
27468
  /* @__PURE__ */ jsxRuntime.jsx(LoadingOverlayCmp, { isVisible: isChangingFilter, message: "Loading new metrics..." }),
27350
- /* @__PURE__ */ jsxRuntime.jsxs("main", { className: "flex flex-1 flex-col", children: [
27351
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-10 sm:static bg-white shadow-sm border-b border-gray-200/80", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center sm:justify-between px-3 sm:px-6 lg:px-8 py-1.5 sm:py-2.5", children: [
27352
- /* @__PURE__ */ jsxRuntime.jsx(DashboardHeader, { lineTitle, className: "mb-1 sm:mb-0" }),
27353
- memoizedKPIs && /* @__PURE__ */ jsxRuntime.jsx(KPISection2, { kpis: memoizedKPIs, className: "w-full sm:w-auto" })
27354
- ] }) }),
27355
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto sm:overflow-hidden", children: memoizedWorkspaceMetrics.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full sm:h-full min-h-[calc(100vh-80px)] sm:min-h-0", children: React14__namespace.default.createElement(WorkspaceGrid, {
27356
- workspaces: memoizedWorkspaceMetrics,
27357
- lineNames,
27358
- factoryView: factoryViewId,
27359
- line2Uuid,
27360
- videoSources,
27361
- className: "h-full"
27362
- }) }) : /* @__PURE__ */ jsxRuntime.jsx(NoWorkspaceData, {}) })
27363
- ] }),
27364
- /* @__PURE__ */ jsxRuntime.jsx(
27365
- BreakNotificationPopup,
27366
- {
27367
- activeBreaks,
27368
- lineNames,
27369
- isVisible: !breaksLoading && !breaksError
27370
- }
27371
- )
27469
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-1", children: [
27470
+ /* @__PURE__ */ jsxRuntime.jsxs("main", { className: "flex flex-1 flex-col", children: [
27471
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-30 sm:static bg-white shadow-sm border-b border-gray-200/80", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col sm:flex-row sm:items-center sm:justify-between px-3 sm:px-6 lg:px-8 py-1.5 sm:py-2.5", children: /* @__PURE__ */ jsxRuntime.jsx(
27472
+ DashboardHeader,
27473
+ {
27474
+ lineTitle,
27475
+ className: "w-full",
27476
+ headerControls: memoizedKPIs ? /* @__PURE__ */ jsxRuntime.jsx(KPISection2, { kpis: memoizedKPIs, className: "w-full sm:w-auto" }) : null
27477
+ }
27478
+ ) }) }),
27479
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto sm:overflow-hidden relative", children: [
27480
+ lineSelectorComponent && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-3 top-2 sm:right-6 sm:top-3 z-30", children: lineSelectorComponent }),
27481
+ memoizedWorkspaceMetrics.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full sm:h-full min-h-[calc(100vh-80px)] sm:min-h-0", children: React14__namespace.default.createElement(WorkspaceGrid, {
27482
+ workspaces: memoizedWorkspaceMetrics,
27483
+ lineNames,
27484
+ factoryView: factoryViewId,
27485
+ videoSources,
27486
+ className: "h-full"
27487
+ }) }) : /* @__PURE__ */ jsxRuntime.jsx(NoWorkspaceData, { message: "No workspace data available. Select another line or check configurations." })
27488
+ ] })
27489
+ ] }),
27490
+ /* @__PURE__ */ jsxRuntime.jsx(
27491
+ BreakNotificationPopup,
27492
+ {
27493
+ activeBreaks,
27494
+ lineNames,
27495
+ isVisible: !breaksLoading && !breaksError
27496
+ }
27497
+ )
27498
+ ] })
27372
27499
  ]
27373
27500
  }
27374
27501
  );
@@ -27532,7 +27659,7 @@ var BottomSection = React14.memo(({
27532
27659
  "div",
27533
27660
  {
27534
27661
  className: "p-1.5 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer",
27535
- onClick: () => handleNavigate && handleNavigate(`/leaderboard/${lineInfo?.line_id}`),
27662
+ onClick: () => handleNavigate && handleNavigate(`/leaderboard`),
27536
27663
  children: /* @__PURE__ */ jsxRuntime.jsx(outline.ArrowRightIcon, { className: "w-5 h-5 text-gray-500" })
27537
27664
  }
27538
27665
  )
@@ -28631,7 +28758,7 @@ var LeaderboardDetailView = React14.memo(({
28631
28758
  className = ""
28632
28759
  }) => {
28633
28760
  const navigation = useNavigation();
28634
- const [sortAscending, setSortAscending] = React14.useState(true);
28761
+ const [sortAscending, setSortAscending] = React14.useState(false);
28635
28762
  const handleSortToggle = React14.useCallback(() => {
28636
28763
  setSortAscending(!sortAscending);
28637
28764
  }, [sortAscending]);
@@ -28647,13 +28774,15 @@ var LeaderboardDetailView = React14.memo(({
28647
28774
  error: metricsError,
28648
28775
  refreshMetrics
28649
28776
  } = useRealtimeLineMetrics(realtimeMetricsParams);
28650
- const memoizedLineId = React14.useMemo(() => lineId || "", [lineId]);
28651
28777
  const {
28652
28778
  workspaces,
28653
28779
  loading: workspacesLoading,
28654
28780
  error: workspacesError,
28655
28781
  refreshWorkspaces
28656
- } = useLineWorkspaceMetrics(memoizedLineId);
28782
+ } = useAllWorkspaceMetrics({
28783
+ initialDate: date,
28784
+ initialShiftId: typeof shift === "number" ? shift : typeof shift === "string" ? parseInt(shift) : void 0
28785
+ });
28657
28786
  const getShiftName = React14.useCallback((shiftId) => {
28658
28787
  if (shiftId === void 0) return "Day";
28659
28788
  return shiftId === 0 ? "Day" : "Night";
@@ -28707,7 +28836,7 @@ var LeaderboardDetailView = React14.memo(({
28707
28836
  });
28708
28837
  const displayName = getWorkspaceDisplayName(workspace.workspace_name);
28709
28838
  const navParams = workspace.workspace_uuid ? getWorkspaceNavigationParams(workspace.workspace_uuid, displayName) : "";
28710
- const returnToParam = `&returnTo=${encodeURIComponent(`/leaderboard/${lineId}`)}`;
28839
+ const returnToParam = `&returnTo=${encodeURIComponent(`/leaderboard`)}`;
28711
28840
  if (onWorkspaceClick) {
28712
28841
  onWorkspaceClick(workspace, rank);
28713
28842
  } else {
@@ -32247,6 +32376,7 @@ exports.KPIHeader = KPIHeader;
32247
32376
  exports.KPISection = KPISection;
32248
32377
  exports.KPIsOverviewView = KPIsOverviewView_default;
32249
32378
  exports.LINE_1_UUID = LINE_1_UUID;
32379
+ exports.LINE_2_UUID = LINE_2_UUID;
32250
32380
  exports.LargeOutputProgressChart = LargeOutputProgressChart;
32251
32381
  exports.LeaderboardDetailView = LeaderboardDetailView_default;
32252
32382
  exports.Legend = Legend6;
@@ -32396,6 +32526,7 @@ exports.trackCoreEvent = trackCoreEvent;
32396
32526
  exports.trackCorePageView = trackCorePageView;
32397
32527
  exports.updateThreadTitle = updateThreadTitle;
32398
32528
  exports.useActiveBreaks = useActiveBreaks;
32529
+ exports.useAllWorkspaceMetrics = useAllWorkspaceMetrics;
32399
32530
  exports.useAnalyticsConfig = useAnalyticsConfig;
32400
32531
  exports.useAuth = useAuth;
32401
32532
  exports.useAuthConfig = useAuthConfig;