@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.mjs CHANGED
@@ -50,12 +50,15 @@ var DEFAULT_DATABASE_CONFIG = {
50
50
  }
51
51
  };
52
52
  var DEFAULT_ENTITY_CONFIG = {
53
- companyId: void 0,
54
- factoryId: void 0,
55
- defaultLineId: void 0,
56
- secondaryLineId: void 0,
53
+ companyId: "87ca8ebc-ef29-4543-9e12-efc526a9b669",
54
+ factoryId: "b3e44be4-730e-4276-b2ce-701c79d66ffa",
55
+ defaultLineId: "98a2287e-8d55-4020-b00d-b9940437e3e1",
56
+ secondaryLineId: "d93997bb-ecac-4478-a4a6-008d536b724c",
57
57
  factoryViewId: "factory",
58
- lineNames: {}
58
+ lineNames: {
59
+ "98a2287e-8d55-4020-b00d-b9940437e3e1": "Cell 8",
60
+ "d93997bb-ecac-4478-a4a6-008d536b724c": "Cell 7"
61
+ }
59
62
  };
60
63
  var DEFAULT_SHIFT_CONFIG = {
61
64
  dayShift: {
@@ -72,9 +75,12 @@ var DEFAULT_SHIFT_CONFIG = {
72
75
  };
73
76
  var DEFAULT_WORKSPACE_CONFIG = {
74
77
  displayNames: {
75
- "WS01": "fillin",
76
- "WS02": "Capping Station",
77
- "WS03": "Filling station"
78
+ "Cell 8 WS1": "Swaging 1",
79
+ "Cell 8 WS2": "Bond Testing 1",
80
+ "Cell 8 WS3": "QA Check 1",
81
+ "Cell 7 WS1": "Swaging 2",
82
+ "Cell 7 WS2": "Bond Testing 2",
83
+ "Cell 7 WS3": "QA Check 2"
78
84
  },
79
85
  specialWorkspaces: {
80
86
  startId: 19,
@@ -131,7 +137,8 @@ var DEFAULT_VIDEO_CONFIG = {
131
137
  useRAF: true
132
138
  }
133
139
  };
134
- var LINE_1_UUID = "910a224b-0abc-459a-babb-4c899824cfe7";
140
+ var LINE_1_UUID = "98a2287e-8d55-4020-b00d-b9940437e3e1";
141
+ var LINE_2_UUID = "d93997bb-ecac-4478-a4a6-008d536b724c";
135
142
  var DEFAULT_CONFIG = {
136
143
  apiBaseUrl: void 0,
137
144
  // No default base URL
@@ -991,7 +998,7 @@ var dashboardService = {
991
998
  const formattedStartDate = formatDate(startDate);
992
999
  const formattedEndDate = formatDate(endDate);
993
1000
  try {
994
- 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 });
1001
+ 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 });
995
1002
  if (error) throw error;
996
1003
  if (!data) return [];
997
1004
  const transformedData = data.map((item) => ({
@@ -1004,7 +1011,8 @@ var dashboardService = {
1004
1011
  ideal_output: item.ideal_output || 0,
1005
1012
  avg_pph: item.avg_pph || 0,
1006
1013
  pph_threshold: item.pph_threshold || 0,
1007
- workspace_rank: item.workspace_rank || 0
1014
+ workspace_rank: item.workspace_rank || 0,
1015
+ idle_time: item.idle_time || 0
1008
1016
  }));
1009
1017
  return transformedData;
1010
1018
  } catch (err) {
@@ -3363,6 +3371,9 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
3363
3371
  const databaseConfig = useDatabaseConfig();
3364
3372
  const dateTimeConfig = useDateTimeConfig();
3365
3373
  const shiftConfig = useShiftConfig();
3374
+ const defaultTimezone = dateTimeConfig?.defaultTimezone || "UTC";
3375
+ const configuredLineMetricsTable = databaseConfig?.tables?.lineMetrics ?? "line_metrics";
3376
+ const schema = databaseConfig?.schema ?? "public";
3366
3377
  const supabase = useSupabase();
3367
3378
  const [metrics2, setMetrics] = useState(() => getCache(lineId) || { workspaceMetrics: [], lineMetrics: [] });
3368
3379
  const [isLoading, setIsLoading] = useState(() => !getCache(lineId));
@@ -3375,9 +3386,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
3375
3386
  () => getCompanyMetricsTableName(entityConfig.companyId, "performance_metrics"),
3376
3387
  [entityConfig.companyId]
3377
3388
  );
3378
- const configuredLineMetricsTable = databaseConfig.tables?.lineMetrics ?? "line_metrics";
3379
- const schema = databaseConfig.schema ?? "public";
3380
- const defaultTimezone = dateTimeConfig.defaultTimezone || "UTC";
3381
3389
  useEffect(() => {
3382
3390
  lineIdRef.current = lineId;
3383
3391
  const cachedData = getCache(lineId);
@@ -3387,7 +3395,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
3387
3395
  const fetchAllMetrics = useCallback(async () => {
3388
3396
  const currentLineIdToUse = lineIdRef.current;
3389
3397
  if (!currentLineIdToUse || !supabase || isFetchingRef.current || companySpecificMetricsTable.includes("unknown_company")) {
3390
- if (!metrics2.workspaceMetrics.length && !metrics2.lineMetrics.length) setIsLoading(false);
3398
+ if (!metrics2?.workspaceMetrics?.length && !metrics2?.lineMetrics?.length) setIsLoading(false);
3391
3399
  if (companySpecificMetricsTable.includes("unknown_company") && !error) {
3392
3400
  setError({ message: "Company ID not configured for metrics table.", code: "CONFIG_ERROR" });
3393
3401
  }
@@ -3408,7 +3416,12 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
3408
3416
  if (targetLineIds.length === 0) {
3409
3417
  throw new Error("No target line IDs available for fetching metrics.");
3410
3418
  }
3411
- 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);
3419
+ const isFactoryView = currentLineIdToUse === (entityConfig.factoryViewId || "factory");
3420
+ 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);
3421
+ if (!isFactoryView) {
3422
+ workspaceQuery = workspaceQuery.in("line_id", targetLineIds);
3423
+ }
3424
+ const { data: workspaceData, error: workspaceError } = await workspaceQuery;
3412
3425
  if (workspaceError) {
3413
3426
  throw workspaceError;
3414
3427
  }
@@ -3439,7 +3452,11 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
3439
3452
  const wsNumB = parseInt(b.workspace_name?.replace(/[^0-9]/g, "") || "0");
3440
3453
  return wsNumA - wsNumB;
3441
3454
  });
3442
- const { data: lineData, error: lineError } = await supabase.from(configuredLineMetricsTable).select("*").eq("date", operationalDate).eq("shift_id", currentShiftDetails.shiftId).in("line_id", targetLineIds);
3455
+ let lineMetricsQuery = supabase.from(configuredLineMetricsTable).select("*").eq("date", operationalDate).eq("shift_id", currentShiftDetails.shiftId);
3456
+ if (!isFactoryView) {
3457
+ lineMetricsQuery = lineMetricsQuery.in("line_id", targetLineIds);
3458
+ }
3459
+ const { data: lineData, error: lineError } = await lineMetricsQuery;
3443
3460
  if (lineError) {
3444
3461
  throw lineError;
3445
3462
  }
@@ -3459,9 +3476,9 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
3459
3476
  }
3460
3477
  }, [
3461
3478
  supabase,
3462
- metrics2.workspaceMetrics.length,
3479
+ metrics2?.workspaceMetrics?.length || 0,
3463
3480
  // To re-evaluate setIsLoading in fetchAllMetrics if called directly
3464
- metrics2.lineMetrics.length,
3481
+ metrics2?.lineMetrics?.length || 0,
3465
3482
  // To re-evaluate setIsLoading in fetchAllMetrics if called directly
3466
3483
  companySpecificMetricsTable,
3467
3484
  configuredLineMetricsTable,
@@ -3549,8 +3566,8 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
3549
3566
  // Add lineId from props to re-run effect if it changes, managed by lineIdRef inside effect
3550
3567
  ]);
3551
3568
  return {
3552
- workspaceMetrics: metrics2.workspaceMetrics,
3553
- lineMetrics: metrics2.lineMetrics,
3569
+ workspaceMetrics: metrics2?.workspaceMetrics || [],
3570
+ lineMetrics: metrics2?.lineMetrics || [],
3554
3571
  isLoading,
3555
3572
  error,
3556
3573
  refetch: fetchAllMetrics
@@ -3583,6 +3600,7 @@ var setCache2 = (lineId, data) => {
3583
3600
  var useLineKPIs = ({ lineId }) => {
3584
3601
  useDashboardConfig();
3585
3602
  const entityConfig = useEntityConfig();
3603
+ const isFactoryView = lineId === (entityConfig.factoryViewId || "factory");
3586
3604
  const databaseConfig = useDatabaseConfig();
3587
3605
  const dateTimeConfig = useDateTimeConfig();
3588
3606
  const shiftConfig = useShiftConfig();
@@ -3640,7 +3658,7 @@ var useLineKPIs = ({ lineId }) => {
3640
3658
  isFetchingRef.current = false;
3641
3659
  updateQueueRef.current = false;
3642
3660
  }
3643
- }, [dashboardServiceInstance, kpis, defaultTimezone, shiftConfig, entityConfig.companyId]);
3661
+ }, [dashboardServiceInstance, kpis, defaultTimezone, shiftConfig, entityConfig.companyId, isFactoryView]);
3644
3662
  const queueUpdate = useCallback(() => {
3645
3663
  if (updateQueueRef.current) return;
3646
3664
  updateQueueRef.current = true;
@@ -3715,7 +3733,7 @@ var useLineKPIs = ({ lineId }) => {
3715
3733
  }
3716
3734
  activeChannels.forEach((ch) => supabase.removeChannel(ch).catch((err) => console.error("[useLineKPIs] Error removing KPI channel:", err)));
3717
3735
  };
3718
- }, [supabase, lineId, fetchKPIs, queueUpdate, dashboardServiceInstance, entityConfig, schema, lineMetricsTable, companySpecificMetricsTable, defaultTimezone, shiftConfig, kpis]);
3736
+ }, [supabase, lineId, fetchKPIs, queueUpdate, dashboardServiceInstance, entityConfig, schema, lineMetricsTable, companySpecificMetricsTable, defaultTimezone, shiftConfig, kpis, isFactoryView]);
3719
3737
  return {
3720
3738
  kpis,
3721
3739
  isLoading,
@@ -5151,6 +5169,120 @@ var useActiveBreaks = (lineIds) => {
5151
5169
  error
5152
5170
  };
5153
5171
  };
5172
+ var useAllWorkspaceMetrics = (options) => {
5173
+ const entityConfig = useEntityConfig();
5174
+ const databaseConfig = useDatabaseConfig();
5175
+ const dateTimeConfig = useDateTimeConfig();
5176
+ const shiftConfig = useShiftConfig();
5177
+ const supabase = useSupabase();
5178
+ const [workspaces, setWorkspaces] = useState([]);
5179
+ const [loading, setLoading] = useState(true);
5180
+ const [error, setError] = useState(null);
5181
+ const [initialized, setInitialized] = useState(false);
5182
+ const queryShiftId = useMemo(() => {
5183
+ const currentShift = getCurrentShift(
5184
+ dateTimeConfig.defaultTimezone || "Asia/Kolkata",
5185
+ shiftConfig
5186
+ );
5187
+ return options?.initialShiftId !== void 0 ? options.initialShiftId : currentShift.shiftId;
5188
+ }, [options?.initialShiftId, dateTimeConfig.defaultTimezone, shiftConfig]);
5189
+ const queryDate = useMemo(() => {
5190
+ return options?.initialDate || getOperationalDate(dateTimeConfig.defaultTimezone);
5191
+ }, [options?.initialDate, dateTimeConfig.defaultTimezone]);
5192
+ const metricsTable = useMemo(() => {
5193
+ const companyId = entityConfig.companyId;
5194
+ if (!companyId) return "";
5195
+ const metricsTablePrefix = getMetricsTablePrefix();
5196
+ return `${metricsTablePrefix}_${companyId.replace(/-/g, "_")}`;
5197
+ }, [entityConfig.companyId]);
5198
+ const schema = databaseConfig.schema ?? "public";
5199
+ const fetchWorkspaceMetrics = useCallback(async () => {
5200
+ if (!initialized) {
5201
+ setLoading(true);
5202
+ }
5203
+ setError(null);
5204
+ try {
5205
+ console.log("Fetching all workspace metrics with params:", {
5206
+ queryDate,
5207
+ queryShiftId,
5208
+ metricsTable
5209
+ });
5210
+ const { data, error: fetchError } = await supabase.from(metricsTable).select(`
5211
+ workspace_name,
5212
+ total_output,
5213
+ avg_pph,
5214
+ efficiency,
5215
+ workspace_id,
5216
+ avg_cycle_time,
5217
+ performance_score,
5218
+ trend_score,
5219
+ line_id,
5220
+ total_day_output
5221
+ `).eq("date", queryDate).eq("shift_id", queryShiftId).order("efficiency", { ascending: false });
5222
+ if (fetchError) throw fetchError;
5223
+ const transformedData = (data || []).map((item) => ({
5224
+ company_id: entityConfig.companyId || "unknown",
5225
+ line_id: item.line_id,
5226
+ shift_id: queryShiftId,
5227
+ date: queryDate,
5228
+ workspace_uuid: item.workspace_id,
5229
+ workspace_name: item.workspace_name,
5230
+ action_count: item.total_output || 0,
5231
+ pph: item.avg_pph || 0,
5232
+ performance_score: item.performance_score || 0,
5233
+ avg_cycle_time: item.avg_cycle_time || 0,
5234
+ trend: item.trend_score === 1 ? 2 : 0,
5235
+ predicted_output: 0,
5236
+ efficiency: item.efficiency || 0,
5237
+ action_threshold: item.total_day_output || 0
5238
+ }));
5239
+ setWorkspaces(transformedData);
5240
+ setInitialized(true);
5241
+ } catch (err) {
5242
+ console.error("Error fetching all workspace metrics:", err);
5243
+ setError({ message: err.message, code: err.code || "FETCH_ERROR" });
5244
+ } finally {
5245
+ setLoading(false);
5246
+ }
5247
+ }, [queryDate, queryShiftId, metricsTable, supabase, entityConfig.companyId]);
5248
+ useEffect(() => {
5249
+ if (!initialized) {
5250
+ fetchWorkspaceMetrics();
5251
+ }
5252
+ const setupSubscription = () => {
5253
+ const filter2 = `date=eq.${queryDate} AND shift_id=eq.${queryShiftId}`;
5254
+ console.log("Setting up subscription for all workspaces with filter:", filter2);
5255
+ const channel2 = supabase.channel(`all-workspace-metrics-${Date.now()}`).on(
5256
+ "postgres_changes",
5257
+ {
5258
+ event: "*",
5259
+ schema,
5260
+ table: metricsTable,
5261
+ filter: filter2
5262
+ },
5263
+ async (payload) => {
5264
+ console.log("All workspace metrics update received:", payload);
5265
+ await fetchWorkspaceMetrics();
5266
+ }
5267
+ ).subscribe();
5268
+ return channel2;
5269
+ };
5270
+ const channel = setupSubscription();
5271
+ return () => {
5272
+ if (channel) {
5273
+ supabase.removeChannel(channel);
5274
+ }
5275
+ };
5276
+ }, [queryDate, queryShiftId, metricsTable, fetchWorkspaceMetrics, initialized, supabase, schema]);
5277
+ useEffect(() => {
5278
+ setInitialized(false);
5279
+ }, [queryDate, queryShiftId]);
5280
+ const refreshWorkspaces = fetchWorkspaceMetrics;
5281
+ return useMemo(
5282
+ () => ({ workspaces, loading, error, refreshWorkspaces }),
5283
+ [workspaces, loading, error, refreshWorkspaces]
5284
+ );
5285
+ };
5154
5286
  var MAX_RETRIES = 10;
5155
5287
  var RETRY_DELAY = 500;
5156
5288
  function useNavigation(customNavigate) {
@@ -5197,8 +5329,8 @@ function useNavigation(customNavigate) {
5197
5329
  router.push("/shifts");
5198
5330
  }, [router]);
5199
5331
  const goToLeaderboard = useCallback(() => {
5200
- const lineId = entityConfig?.defaultLineId || "line-1";
5201
- router.push(`/leaderboard/${lineId}`);
5332
+ entityConfig?.defaultLineId || "line-1";
5333
+ router.push(`/leaderboard`);
5202
5334
  }, [router, entityConfig?.defaultLineId]);
5203
5335
  const goToFactoryView = useCallback(() => {
5204
5336
  router.push("/factory-view");
@@ -17338,7 +17470,8 @@ var VideoCard = React14__default.memo(({
17338
17470
  cropping,
17339
17471
  canvasFps = 30,
17340
17472
  useRAF = true,
17341
- className = ""
17473
+ className = "",
17474
+ compact = false
17342
17475
  }) => {
17343
17476
  const videoRef = useRef(null);
17344
17477
  const canvasRef = useRef(null);
@@ -17359,7 +17492,6 @@ var VideoCard = React14__default.memo(({
17359
17492
  });
17360
17493
  }
17361
17494
  const displayName = getWorkspaceDisplayName(workspace.workspace_name);
17362
- workspace.workspace_uuid || workspace.workspace_name;
17363
17495
  const getEfficiencyOverlayColor = (efficiency) => {
17364
17496
  if (efficiency >= 80) {
17365
17497
  return "bg-[#00D654]/25";
@@ -17402,15 +17534,15 @@ var VideoCard = React14__default.memo(({
17402
17534
  }
17403
17535
  },
17404
17536
  children: [
17405
- isVeryLowEfficiency && /* @__PURE__ */ jsx("div", { className: "absolute top-1 left-2 z-30", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
17537
+ isVeryLowEfficiency && /* @__PURE__ */ jsx("div", { className: `absolute ${compact ? "top-0.5 left-1" : "top-1 left-2"} z-30`, children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
17406
17538
  /* @__PURE__ */ jsx("div", { className: "absolute -inset-1 bg-red-400/50 rounded-full blur-sm animate-pulse" }),
17407
17539
  /* @__PURE__ */ jsx("div", { className: "absolute -inset-0.5 bg-red-500/30 rounded-full blur-md animate-ping [animation-duration:1.5s]" }),
17408
- /* @__PURE__ */ 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: "!" })
17540
+ /* @__PURE__ */ 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: "!" })
17409
17541
  ] }) }),
17410
17542
  /* @__PURE__ */ jsxs("div", { className: "relative w-full h-full overflow-hidden bg-black", children: [
17411
17543
  /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black z-0", children: /* @__PURE__ */ jsxs("div", { className: "animate-pulse flex flex-col items-center", children: [
17412
- /* @__PURE__ */ jsx(Camera, { className: "w-6 h-6 text-gray-500" }),
17413
- /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-500 mt-1", children: "Loading..." })
17544
+ /* @__PURE__ */ jsx(Camera, { className: `${compact ? "w-4 h-4" : "w-6 h-6"} text-gray-500` }),
17545
+ /* @__PURE__ */ jsx("span", { className: `${compact ? "text-[10px]" : "text-xs"} text-gray-500 mt-1`, children: "Loading..." })
17414
17546
  ] }) }),
17415
17547
  /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 z-10", children: [
17416
17548
  /* @__PURE__ */ jsx(
@@ -17433,11 +17565,11 @@ var VideoCard = React14__default.memo(({
17433
17565
  )
17434
17566
  ] }),
17435
17567
  /* @__PURE__ */ jsx("div", { className: `absolute inset-0 z-20 pointer-events-none ${efficiencyOverlayClass}` }),
17436
- /* @__PURE__ */ 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: [
17568
+ /* @__PURE__ */ 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: [
17437
17569
  Math.round(workspace.efficiency),
17438
17570
  "%"
17439
17571
  ] }),
17440
- /* @__PURE__ */ jsx("div", { className: "absolute bottom-0 left-0 right-0 h-1 bg-black/50 z-30", children: /* @__PURE__ */ jsx(
17572
+ /* @__PURE__ */ jsx("div", { className: `absolute bottom-0 left-0 right-0 ${compact ? "h-0.5" : "h-1"} bg-black/50 z-30`, children: /* @__PURE__ */ jsx(
17441
17573
  "div",
17442
17574
  {
17443
17575
  className: `h-full ${efficiencyBarClass} transition-all duration-500`,
@@ -17445,22 +17577,22 @@ var VideoCard = React14__default.memo(({
17445
17577
  }
17446
17578
  ) })
17447
17579
  ] }),
17448
- /* @__PURE__ */ 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: [
17580
+ /* @__PURE__ */ 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: [
17449
17581
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
17450
- /* @__PURE__ */ jsx(Camera, { size: 12, className: "text-white" }),
17451
- /* @__PURE__ */ jsx("p", { className: "text-white text-xs font-medium tracking-wide", children: displayName })
17582
+ /* @__PURE__ */ jsx(Camera, { size: compact ? 10 : 12, className: "text-white" }),
17583
+ /* @__PURE__ */ jsx("p", { className: `text-white ${compact ? "text-[10px]" : "text-xs"} font-medium tracking-wide`, children: displayName })
17452
17584
  ] }),
17453
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
17585
+ /* @__PURE__ */ jsxs("div", { className: `flex items-center ${compact ? "gap-1" : "gap-1.5"}`, children: [
17454
17586
  trendInfo && /* @__PURE__ */ jsx(
17455
17587
  "div",
17456
17588
  {
17457
- className: `text-lg ${trendInfo.color}`,
17589
+ className: `${compact ? "text-sm" : "text-lg"} ${trendInfo.color}`,
17458
17590
  style: { lineHeight: 1, display: "flex", alignItems: "center" },
17459
17591
  children: trendInfo.arrow
17460
17592
  }
17461
17593
  ),
17462
- /* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 rounded-full bg-green-500" }),
17463
- /* @__PURE__ */ jsx("span", { className: "text-white text-xs", children: "Live" })
17594
+ /* @__PURE__ */ jsx("div", { className: `${compact ? "w-1 h-1" : "w-1.5 h-1.5"} rounded-full bg-green-500` }),
17595
+ /* @__PURE__ */ jsx("span", { className: `text-white ${compact ? "text-[10px]" : "text-xs"}`, children: "Live" })
17464
17596
  ] })
17465
17597
  ] })
17466
17598
  ]
@@ -17487,7 +17619,6 @@ var VideoGridView = React14__default.memo(({
17487
17619
  workspaces,
17488
17620
  selectedLine,
17489
17621
  className = "",
17490
- lineIdMapping = {},
17491
17622
  videoSources = {}
17492
17623
  }) => {
17493
17624
  const router = useRouter();
@@ -17552,15 +17683,15 @@ var VideoGridView = React14__default.memo(({
17552
17683
  let bestScore = 0;
17553
17684
  const targetAspectRatio = 16 / 9;
17554
17685
  const gap = 8;
17555
- const maxCols = Math.min(count, 6);
17686
+ const maxCols = Math.min(count, selectedLine ? 6 : 12);
17556
17687
  for (let cols = 1; cols <= maxCols; cols++) {
17557
17688
  const rows = Math.ceil(count / cols);
17558
17689
  const availableWidth = containerWidth - gap * (cols - 1);
17559
17690
  const availableHeight = containerHeight - gap * (rows - 1);
17560
17691
  const cellWidth = availableWidth / cols;
17561
17692
  const cellHeight = availableHeight / rows;
17562
- const minCellWidth = containerWidth < 800 ? 120 : 150;
17563
- const minCellHeight = containerHeight < 600 ? 80 : 100;
17693
+ const minCellWidth = selectedLine ? containerWidth < 800 ? 120 : 150 : containerWidth < 800 ? 80 : 100;
17694
+ const minCellHeight = selectedLine ? containerHeight < 600 ? 80 : 100 : containerHeight < 600 ? 60 : 80;
17564
17695
  if (cellWidth < minCellWidth || cellHeight < minCellHeight) continue;
17565
17696
  const totalUsedArea = cellWidth * cellHeight * count;
17566
17697
  const totalAvailableArea = containerWidth * containerHeight;
@@ -17577,7 +17708,7 @@ var VideoGridView = React14__default.memo(({
17577
17708
  bestCols = Math.ceil(Math.sqrt(count));
17578
17709
  }
17579
17710
  setGridCols(bestCols);
17580
- }, [filteredWorkspaces.length]);
17711
+ }, [filteredWorkspaces.length, selectedLine]);
17581
17712
  useEffect(() => {
17582
17713
  calculateOptimalGrid();
17583
17714
  const handleResize = () => calculateOptimalGrid();
@@ -17636,16 +17767,17 @@ var VideoGridView = React14__default.memo(({
17636
17767
  minHeight: "100%"
17637
17768
  },
17638
17769
  children: filteredWorkspaces.sort((a, b) => {
17639
- const aNum = parseInt(a.workspace_name.slice(2));
17640
- const bNum = parseInt(b.workspace_name.slice(2));
17641
- if (!selectedLine) {
17642
- const aIsLine2 = a.line_id === lineIdMapping.line2;
17643
- const bIsLine2 = b.line_id === lineIdMapping.line2;
17644
- if (aIsLine2 !== bIsLine2) {
17645
- return aIsLine2 ? 1 : -1;
17646
- }
17770
+ if (a.line_id !== b.line_id) {
17771
+ return (a.line_id || "").localeCompare(b.line_id || "");
17772
+ }
17773
+ const aMatch = a.workspace_name.match(/WS(\d+)/);
17774
+ const bMatch = b.workspace_name.match(/WS(\d+)/);
17775
+ if (aMatch && bMatch) {
17776
+ const aNum = parseInt(aMatch[1]);
17777
+ const bNum = parseInt(bMatch[1]);
17778
+ return aNum - bNum;
17647
17779
  }
17648
- return aNum - bNum;
17780
+ return a.workspace_name.localeCompare(b.workspace_name);
17649
17781
  }).map((workspace) => {
17650
17782
  const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
17651
17783
  const isVisible = visibleWorkspaces.has(workspaceId);
@@ -17668,7 +17800,8 @@ var VideoGridView = React14__default.memo(({
17668
17800
  isVeryLowEfficiency,
17669
17801
  cropping: workspaceCropping,
17670
17802
  canvasFps: canvasConfig?.fps,
17671
- useRAF: canvasConfig?.useRAF
17803
+ useRAF: canvasConfig?.useRAF,
17804
+ compact: !selectedLine
17672
17805
  }
17673
17806
  )
17674
17807
  },
@@ -21232,7 +21365,7 @@ function isValidShiftId(shiftId) {
21232
21365
  }
21233
21366
 
21234
21367
  // src/lib/api/s3-clips-parser.ts
21235
- function parseS3Uri(s3Uri) {
21368
+ function parseS3Uri(s3Uri, sopCategories) {
21236
21369
  const path = new URL(s3Uri).pathname;
21237
21370
  const parts = path.split("/").filter((p) => p);
21238
21371
  console.log("S3 URI:", s3Uri);
@@ -21272,6 +21405,27 @@ function parseS3Uri(s3Uri) {
21272
21405
  let description = "Analysis Clip";
21273
21406
  const normalizedViolationType = violationType.toLowerCase().trim();
21274
21407
  console.log(`Parsing violation type: "${violationType}" (normalized: "${normalizedViolationType}") from path: ${s3Uri}`);
21408
+ if (sopCategories && sopCategories.length > 0) {
21409
+ const matchedCategory = sopCategories.find((category) => {
21410
+ const categoryId = category.id.toLowerCase();
21411
+ const s3FolderName = (category.s3FolderName || category.id).toLowerCase();
21412
+ return categoryId === normalizedViolationType || s3FolderName === normalizedViolationType || // Also check for partial matches for flexibility
21413
+ normalizedViolationType.includes(categoryId) || normalizedViolationType.includes(s3FolderName);
21414
+ });
21415
+ if (matchedCategory) {
21416
+ type = matchedCategory.id;
21417
+ description = matchedCategory.description || matchedCategory.label;
21418
+ if (matchedCategory.color.includes("red")) {
21419
+ severity = "high";
21420
+ } else if (matchedCategory.color.includes("yellow") || matchedCategory.color.includes("orange")) {
21421
+ severity = "medium";
21422
+ } else {
21423
+ severity = "low";
21424
+ }
21425
+ console.log(`Matched SOP category: ${matchedCategory.id} for violation type: ${violationType}`);
21426
+ return { timestamp, severity, description, type, originalUri: s3Uri };
21427
+ }
21428
+ }
21275
21429
  switch (normalizedViolationType) {
21276
21430
  case "idle_time":
21277
21431
  case "idle":
@@ -21511,11 +21665,23 @@ var S3ClipsService = class {
21511
21665
  const key = url.pathname.startsWith("/") ? url.pathname.substring(1) : url.pathname;
21512
21666
  return `${this.config.s3Config.cloudFrontDomain}/${key}`;
21513
21667
  }
21668
+ /**
21669
+ * Gets SOP categories for a specific workspace
21670
+ */
21671
+ getSOPCategories(workspaceId) {
21672
+ const sopConfig = this.config.s3Config?.sopCategories;
21673
+ if (!sopConfig) return void 0;
21674
+ if (sopConfig.workspaceOverrides && sopConfig.workspaceOverrides[workspaceId]) {
21675
+ return sopConfig.workspaceOverrides[workspaceId];
21676
+ }
21677
+ return sopConfig.default;
21678
+ }
21514
21679
  /**
21515
21680
  * Processes a single video completely
21516
21681
  */
21517
21682
  async processFullVideo(uri, index, workspaceId, date, shiftId, includeCycleTime, includeMetadata = false) {
21518
- const parsedInfo = parseS3Uri(uri);
21683
+ const sopCategories = this.getSOPCategories(workspaceId);
21684
+ const parsedInfo = parseS3Uri(uri, sopCategories);
21519
21685
  if (!parsedInfo) {
21520
21686
  console.warn(`Skipping URI due to parsing failure: ${uri}`);
21521
21687
  return null;
@@ -21548,27 +21714,32 @@ var S3ClipsService = class {
21548
21714
  async getVideoSummary(workspaceId, date, shiftId) {
21549
21715
  const s3Uris = await this.listS3Clips({ workspaceId, date, shiftId });
21550
21716
  console.log(`S3ClipsService getVideoSummary: Processing ${s3Uris.length} total URIs for accurate category counts`);
21551
- const counts = {
21552
- best_cycle_time: 0,
21553
- worst_cycle_time: 0,
21554
- bottleneck: 0,
21555
- low_value: 0,
21556
- long_cycle_time: 0,
21557
- missing_quality_check: 0,
21558
- cycle_completions: 0,
21559
- total: 0
21560
- };
21561
- const samples = {
21562
- best_cycle_time: null,
21563
- worst_cycle_time: null,
21564
- bottleneck: null,
21565
- low_value: null,
21566
- long_cycle_time: null,
21567
- missing_quality_check: null,
21568
- cycle_completions: null
21569
- };
21717
+ const sopCategories = this.getSOPCategories(workspaceId);
21718
+ const counts = { total: 0 };
21719
+ const samples = {};
21720
+ if (sopCategories && sopCategories.length > 0) {
21721
+ sopCategories.forEach((category) => {
21722
+ counts[category.id] = 0;
21723
+ samples[category.id] = null;
21724
+ });
21725
+ } else {
21726
+ counts.best_cycle_time = 0;
21727
+ counts.worst_cycle_time = 0;
21728
+ counts.bottleneck = 0;
21729
+ counts.low_value = 0;
21730
+ counts.long_cycle_time = 0;
21731
+ counts.missing_quality_check = 0;
21732
+ counts.cycle_completions = 0;
21733
+ samples.best_cycle_time = null;
21734
+ samples.worst_cycle_time = null;
21735
+ samples.bottleneck = null;
21736
+ samples.low_value = null;
21737
+ samples.long_cycle_time = null;
21738
+ samples.missing_quality_check = null;
21739
+ samples.cycle_completions = null;
21740
+ }
21570
21741
  for (const uri of s3Uris) {
21571
- const parsedInfo = parseS3Uri(uri);
21742
+ const parsedInfo = parseS3Uri(uri, sopCategories);
21572
21743
  if (parsedInfo) {
21573
21744
  const { type } = parsedInfo;
21574
21745
  counts[type] = (counts[type] || 0) + 1;
@@ -21630,7 +21801,7 @@ var S3ClipsService = class {
21630
21801
  }
21631
21802
  return summary;
21632
21803
  }
21633
- const limitPerCategory = limit ? Math.min(Math.max(limit, 1), 200) : 30;
21804
+ const limitPerCategory = limit ? Math.min(Math.max(limit, 1), 1e3) : 30;
21634
21805
  const shouldFetchAll = category === "missing_quality_check" || category === "low_value";
21635
21806
  const initialFetchLimit = shouldFetchAll ? void 0 : category ? limitPerCategory * 3 : void 0;
21636
21807
  const s3Uris = await this.listS3Clips({ workspaceId, date, shiftId, maxKeys: initialFetchLimit });
@@ -21781,6 +21952,14 @@ var BottlenecksContent = ({
21781
21952
  className
21782
21953
  }) => {
21783
21954
  const dashboardConfig = useDashboardConfig();
21955
+ const sopCategories = React14__default.useMemo(() => {
21956
+ const sopConfig = dashboardConfig?.s3Config?.sopCategories;
21957
+ if (!sopConfig) return null;
21958
+ if (sopConfig.workspaceOverrides && sopConfig.workspaceOverrides[workspaceId]) {
21959
+ return sopConfig.workspaceOverrides[workspaceId];
21960
+ }
21961
+ return sopConfig.default;
21962
+ }, [dashboardConfig, workspaceId]);
21784
21963
  const videoRef = useRef(null);
21785
21964
  const fullscreenContainerRef = useRef(null);
21786
21965
  const timestampFilterRef = useRef(null);
@@ -21789,7 +21968,9 @@ var BottlenecksContent = ({
21789
21968
  const [duration, setDuration] = useState(0);
21790
21969
  const [isFullscreen, setIsFullscreen] = useState(false);
21791
21970
  const [currentIndex, setCurrentIndex] = useState(0);
21792
- const [activeFilter, setActiveFilter] = useState("low_value");
21971
+ const [activeFilter, setActiveFilter] = useState(
21972
+ sopCategories && sopCategories.length > 0 ? sopCategories[0].id : "low_value"
21973
+ );
21793
21974
  const [allVideos, setAllVideos] = useState([]);
21794
21975
  const [isLoading, setIsLoading] = useState(true);
21795
21976
  const [error, setError] = useState(null);
@@ -21901,27 +22082,41 @@ var BottlenecksContent = ({
21901
22082
  let filtered = [];
21902
22083
  if (activeFilter === "all") {
21903
22084
  filtered = [...allVideos];
21904
- } else if (activeFilter === "low_value") {
21905
- filtered = allVideos.filter((video) => video.type === "low_value");
21906
- } else if (activeFilter === "sop_deviations") {
21907
- filtered = allVideos.filter((video) => video.type === "missing_quality_check");
21908
- } else if (activeFilter === "best_cycle_time") {
21909
- filtered = allVideos.filter((video) => video.type === "best_cycle_time");
21910
- } else if (activeFilter === "worst_cycle_time") {
21911
- filtered = allVideos.filter((video) => video.type === "worst_cycle_time");
21912
- } else if (activeFilter === "cycle_completions") {
21913
- filtered = allVideos.filter((video) => video.type === "cycle_completions");
21914
- } else if (activeFilter === "long_cycle_time") {
21915
- filtered = allVideos.filter(
21916
- (video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
21917
- );
21918
22085
  } else {
21919
- filtered = allVideos.filter((video) => video.type === "bottleneck" && video.severity === activeFilter);
22086
+ if (sopCategories && sopCategories.length > 0) {
22087
+ const selectedCategory = sopCategories.find((cat) => cat.id === activeFilter);
22088
+ if (selectedCategory) {
22089
+ filtered = allVideos.filter((video) => video.type === selectedCategory.id);
22090
+ if (selectedCategory.id === "long_cycle_time") {
22091
+ filtered = allVideos.filter(
22092
+ (video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
22093
+ );
22094
+ }
22095
+ }
22096
+ } else {
22097
+ if (activeFilter === "low_value") {
22098
+ filtered = allVideos.filter((video) => video.type === "low_value");
22099
+ } else if (activeFilter === "sop_deviations") {
22100
+ filtered = allVideos.filter((video) => video.type === "missing_quality_check");
22101
+ } else if (activeFilter === "best_cycle_time") {
22102
+ filtered = allVideos.filter((video) => video.type === "best_cycle_time");
22103
+ } else if (activeFilter === "worst_cycle_time") {
22104
+ filtered = allVideos.filter((video) => video.type === "worst_cycle_time");
22105
+ } else if (activeFilter === "cycle_completions") {
22106
+ filtered = allVideos.filter((video) => video.type === "cycle_completions");
22107
+ } else if (activeFilter === "long_cycle_time") {
22108
+ filtered = allVideos.filter(
22109
+ (video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
22110
+ );
22111
+ } else {
22112
+ filtered = allVideos.filter((video) => video.type === "bottleneck" && video.severity === activeFilter);
22113
+ }
22114
+ }
21920
22115
  }
21921
22116
  return filtered.sort((a, b) => {
21922
22117
  return new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime();
21923
22118
  });
21924
- }, [activeFilter, allVideos]);
22119
+ }, [activeFilter, allVideos, sopCategories]);
21925
22120
  useEffect(() => {
21926
22121
  if (filteredVideos.length === 0) return;
21927
22122
  const upcoming = [];
@@ -22195,35 +22390,34 @@ var BottlenecksContent = ({
22195
22390
  }
22196
22391
  };
22197
22392
  const clipCounts = useMemo(() => {
22198
- if (!allVideos) return {
22199
- bottlenecks: 0,
22200
- lowValue: 0,
22201
- highSeverity: 0,
22202
- mediumSeverity: 0,
22203
- lowSeverity: 0,
22204
- sopDeviations: 0,
22205
- bestCycleTimes: 0,
22206
- worstCycleTimes: 0,
22207
- longCycleTimes: 0,
22208
- cycleCompletions: 0,
22209
- total: 0
22210
- };
22211
- return {
22212
- bottlenecks: allVideos.filter((video) => video.type === "bottleneck").length,
22213
- lowValue: allVideos.filter((video) => video.type === "low_value").length,
22214
- highSeverity: allVideos.filter((video) => video.severity === "high" && video.type === "bottleneck").length,
22215
- mediumSeverity: allVideos.filter((video) => video.severity === "medium" && video.type === "bottleneck").length,
22216
- lowSeverity: allVideos.filter((video) => video.severity === "low" && video.type === "bottleneck").length,
22217
- sopDeviations: allVideos.filter((video) => video.type === "missing_quality_check").length,
22218
- bestCycleTimes: allVideos.filter((video) => video.type === "best_cycle_time").length,
22219
- worstCycleTimes: allVideos.filter((video) => video.type === "worst_cycle_time").length,
22220
- longCycleTimes: allVideos.filter(
22393
+ if (!allVideos) return {};
22394
+ const counts = { total: allVideos.length };
22395
+ if (sopCategories && sopCategories.length > 0) {
22396
+ sopCategories.forEach((category) => {
22397
+ if (category.id === "long_cycle_time") {
22398
+ counts[category.id] = allVideos.filter(
22399
+ (video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
22400
+ ).length;
22401
+ } else {
22402
+ counts[category.id] = allVideos.filter((video) => video.type === category.id).length;
22403
+ }
22404
+ });
22405
+ } else {
22406
+ counts.bottlenecks = allVideos.filter((video) => video.type === "bottleneck").length;
22407
+ counts.lowValue = allVideos.filter((video) => video.type === "low_value").length;
22408
+ counts.highSeverity = allVideos.filter((video) => video.severity === "high" && video.type === "bottleneck").length;
22409
+ counts.mediumSeverity = allVideos.filter((video) => video.severity === "medium" && video.type === "bottleneck").length;
22410
+ counts.lowSeverity = allVideos.filter((video) => video.severity === "low" && video.type === "bottleneck").length;
22411
+ counts.sopDeviations = allVideos.filter((video) => video.type === "missing_quality_check").length;
22412
+ counts.bestCycleTimes = allVideos.filter((video) => video.type === "best_cycle_time").length;
22413
+ counts.worstCycleTimes = allVideos.filter((video) => video.type === "worst_cycle_time").length;
22414
+ counts.longCycleTimes = allVideos.filter(
22221
22415
  (video) => video.type === "bottleneck" && video.description.toLowerCase().includes("cycle time")
22222
- ).length,
22223
- cycleCompletions: allVideos.filter((video) => video.type === "cycle_completions").length,
22224
- total: allVideos.length
22225
- };
22226
- }, [allVideos]);
22416
+ ).length;
22417
+ counts.cycleCompletions = allVideos.filter((video) => video.type === "cycle_completions").length;
22418
+ }
22419
+ return counts;
22420
+ }, [allVideos, sopCategories]);
22227
22421
  const currentVideo = useMemo(() => {
22228
22422
  if (!filteredVideos || filteredVideos.length === 0 || currentIndex >= filteredVideos.length) {
22229
22423
  return null;
@@ -22248,6 +22442,19 @@ var BottlenecksContent = ({
22248
22442
  return "Bottleneck";
22249
22443
  }
22250
22444
  };
22445
+ const getColorClasses = (color2) => {
22446
+ const colorMap = {
22447
+ purple: { text: "text-purple-500", bg: "bg-purple-500", dot: "bg-purple-500" },
22448
+ green: { text: "text-green-600", bg: "bg-green-600", dot: "bg-green-600" },
22449
+ red: { text: "text-red-700", bg: "bg-red-700", dot: "bg-red-700" },
22450
+ "red-dark": { text: "text-red-500", bg: "bg-red-500", dot: "bg-red-500" },
22451
+ blue: { text: "text-blue-600", bg: "bg-blue-600", dot: "bg-blue-600" },
22452
+ orange: { text: "text-orange-600", bg: "bg-orange-600", dot: "bg-orange-600" },
22453
+ yellow: { text: "text-yellow-600", bg: "bg-yellow-600", dot: "bg-yellow-600" },
22454
+ gray: { text: "text-gray-600", bg: "bg-gray-600", dot: "bg-gray-600" }
22455
+ };
22456
+ return colorMap[color2] || colorMap.gray;
22457
+ };
22251
22458
  const formatTimeOnly = (time2) => {
22252
22459
  if (!time2) return "";
22253
22460
  try {
@@ -22277,162 +22484,62 @@ var BottlenecksContent = ({
22277
22484
  /* @__PURE__ */ jsx("p", { className: "text-gray-600 max-w-md", children: error })
22278
22485
  ] });
22279
22486
  }
22487
+ const categoriesToShow = sopCategories && sopCategories.length > 0 ? sopCategories : [
22488
+ // Default hardcoded categories if no configuration
22489
+ { id: "low_value", label: "Idle Moments", color: "purple", subtitle: "Idle time detected" },
22490
+ { id: "best_cycle_time", label: "Best Cycle Time", color: "green", subtitle: "Fastest cycle today" },
22491
+ { id: "worst_cycle_time", label: "Worst Cycle Time", color: "red", subtitle: "Slowest cycle today" },
22492
+ { id: "long_cycle_time", label: "Long Cycle Time", color: "red-dark", subtitle: "Above standard cycle times" },
22493
+ { id: "cycle_completions", label: "Cycle Completions", color: "blue", subtitle: "Completed production cycles" }
22494
+ ];
22280
22495
  return /* @__PURE__ */ jsxs("div", { className: "flex-grow p-1.5 sm:p-2 lg:p-4 h-[calc(100vh-12rem)]", children: [
22281
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-3 mb-4", children: [
22282
- /* @__PURE__ */ jsxs(
22283
- Card2,
22284
- {
22285
- onClick: () => {
22286
- setActiveFilter("low_value");
22287
- trackCoreEvent("Idle Moments Filter Clicked", {
22288
- workspaceId,
22289
- workspaceName,
22290
- date,
22291
- filterType: "low_value",
22292
- clipCount: clipCounts.lowValue
22293
- });
22294
- },
22295
- 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" : ""}`,
22296
- "aria-label": `Filter by Idle Moments (${clipCounts.lowValue} clips)`,
22297
- role: "button",
22298
- tabIndex: 0,
22299
- onKeyDown: (e) => e.key === "Enter" && setActiveFilter("low_value"),
22300
- children: [
22301
- /* @__PURE__ */ jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsx(CardTitle2, { className: `text-lg ${activeFilter === "low_value" ? "text-blue-600" : ""}`, children: "Idle Moments" }) }),
22302
- /* @__PURE__ */ jsx(CardContent2, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col justify-center", children: [
22303
- /* @__PURE__ */ jsx("p", { className: "text-3xl font-bold text-purple-500", children: clipCounts.lowValue }),
22304
- /* @__PURE__ */ jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
22305
- /* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-purple-500 mr-1.5" }),
22306
- /* @__PURE__ */ jsx("span", { children: "Idle time detected" })
22307
- ] })
22308
- ] }) })
22309
- ]
22310
- }
22311
- ),
22312
- /* @__PURE__ */ jsxs(
22496
+ /* @__PURE__ */ 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) => {
22497
+ const colorClasses = getColorClasses(category.color);
22498
+ const count = clipCounts[category.id] || 0;
22499
+ return /* @__PURE__ */ jsxs(
22313
22500
  Card2,
22314
22501
  {
22315
22502
  onClick: () => {
22316
- setActiveFilter("best_cycle_time");
22317
- trackCoreEvent("Best Cycle Time Filter Clicked", {
22503
+ setActiveFilter(category.id);
22504
+ trackCoreEvent(`${category.label} Filter Clicked`, {
22318
22505
  workspaceId,
22319
22506
  workspaceName,
22320
22507
  date,
22321
- filterType: "best_cycle_time",
22322
- clipCount: clipCounts.bestCycleTimes
22508
+ filterType: category.id,
22509
+ clipCount: count
22323
22510
  });
22324
22511
  },
22325
- 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" : ""}`,
22326
- "aria-label": `Filter by Best Cycle Time (${clipCounts.bestCycleTimes} clips)`,
22512
+ 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" : ""}`,
22513
+ "aria-label": `Filter by ${category.label} (${count} clips)`,
22327
22514
  role: "button",
22328
22515
  tabIndex: 0,
22329
- onKeyDown: (e) => e.key === "Enter" && setActiveFilter("best_cycle_time"),
22516
+ onKeyDown: (e) => e.key === "Enter" && setActiveFilter(category.id),
22330
22517
  children: [
22331
- /* @__PURE__ */ jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsx(CardTitle2, { className: `text-lg ${activeFilter === "best_cycle_time" ? "text-blue-600" : ""}`, children: "Best Cycle Time" }) }),
22518
+ /* @__PURE__ */ jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsx(CardTitle2, { className: `text-lg ${activeFilter === category.id ? "text-blue-600" : ""}`, children: category.label }) }),
22332
22519
  /* @__PURE__ */ jsx(CardContent2, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col justify-center", children: [
22333
- /* @__PURE__ */ jsx("p", { className: "text-3xl font-bold text-green-600", children: clipCounts.bestCycleTimes }),
22520
+ /* @__PURE__ */ jsx("p", { className: `text-3xl font-bold ${colorClasses.text}`, children: count }),
22334
22521
  /* @__PURE__ */ jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
22335
- /* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-green-600 mr-1.5" }),
22336
- /* @__PURE__ */ jsx("span", { children: "Fastest cycle today" })
22522
+ /* @__PURE__ */ jsx("div", { className: `h-2 w-2 rounded-full ${colorClasses.dot} mr-1.5` }),
22523
+ /* @__PURE__ */ jsx("span", { children: category.subtitle || category.description || category.label })
22337
22524
  ] })
22338
22525
  ] }) })
22339
22526
  ]
22340
- }
22341
- ),
22342
- /* @__PURE__ */ jsxs(
22343
- Card2,
22344
- {
22345
- onClick: () => {
22346
- setActiveFilter("worst_cycle_time");
22347
- trackCoreEvent("Worst Cycle Time Filter Clicked", {
22348
- workspaceId,
22349
- workspaceName,
22350
- date,
22351
- filterType: "worst_cycle_time",
22352
- clipCount: clipCounts.worstCycleTimes
22353
- });
22354
- },
22355
- 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" : ""}`,
22356
- "aria-label": `Filter by Worst Cycle Time (${clipCounts.worstCycleTimes} clips)`,
22357
- role: "button",
22358
- tabIndex: 0,
22359
- onKeyDown: (e) => e.key === "Enter" && setActiveFilter("worst_cycle_time"),
22360
- children: [
22361
- /* @__PURE__ */ jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsx(CardTitle2, { className: `text-lg ${activeFilter === "worst_cycle_time" ? "text-blue-600" : ""}`, children: "Worst Cycle Time" }) }),
22362
- /* @__PURE__ */ jsx(CardContent2, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col justify-center", children: [
22363
- /* @__PURE__ */ jsx("p", { className: "text-3xl font-bold text-red-700", children: clipCounts.worstCycleTimes }),
22364
- /* @__PURE__ */ jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
22365
- /* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-red-700 mr-1.5" }),
22366
- /* @__PURE__ */ jsx("span", { children: "Slowest cycle today" })
22367
- ] })
22368
- ] }) })
22369
- ]
22370
- }
22371
- ),
22372
- /* @__PURE__ */ jsxs(
22373
- Card2,
22374
- {
22375
- onClick: () => {
22376
- setActiveFilter("long_cycle_time");
22377
- trackCoreEvent("Long Cycle Time Filter Clicked", {
22378
- workspaceId,
22379
- workspaceName,
22380
- date,
22381
- filterType: "long_cycle_time",
22382
- clipCount: clipCounts.longCycleTimes
22383
- });
22384
- },
22385
- 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" : ""}`,
22386
- "aria-label": `Filter by Long Cycle Time Bottlenecks (${clipCounts.longCycleTimes} clips)`,
22387
- role: "button",
22388
- tabIndex: 0,
22389
- onKeyDown: (e) => e.key === "Enter" && setActiveFilter("long_cycle_time"),
22390
- children: [
22391
- /* @__PURE__ */ jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsx(CardTitle2, { className: `text-lg ${activeFilter === "long_cycle_time" ? "text-blue-600" : ""}`, children: "Long Cycle Time" }) }),
22392
- /* @__PURE__ */ jsx(CardContent2, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col justify-center", children: [
22393
- /* @__PURE__ */ jsx("p", { className: "text-3xl font-bold text-red-500", children: clipCounts.longCycleTimes }),
22394
- /* @__PURE__ */ jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
22395
- /* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-red-500 mr-1.5" }),
22396
- /* @__PURE__ */ jsx("span", { children: "Above standard cycle times" })
22397
- ] })
22398
- ] }) })
22399
- ]
22400
- }
22401
- ),
22402
- /* @__PURE__ */ jsxs(
22403
- Card2,
22404
- {
22405
- onClick: () => {
22406
- setActiveFilter("cycle_completions");
22407
- trackCoreEvent("Cycle Completions Filter Clicked", {
22408
- workspaceId,
22409
- workspaceName,
22410
- date,
22411
- filterType: "cycle_completions",
22412
- clipCount: clipCounts.cycleCompletions
22413
- });
22414
- },
22415
- 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" : ""}`,
22416
- "aria-label": `Filter by Cycle Completions (${clipCounts.cycleCompletions} clips)`,
22417
- role: "button",
22418
- tabIndex: 0,
22419
- onKeyDown: (e) => e.key === "Enter" && setActiveFilter("cycle_completions"),
22420
- children: [
22421
- /* @__PURE__ */ jsx(CardHeader2, { className: "pb-2", children: /* @__PURE__ */ jsx(CardTitle2, { className: `text-lg ${activeFilter === "cycle_completions" ? "text-blue-600" : ""}`, children: "Cycle Completions" }) }),
22422
- /* @__PURE__ */ jsx(CardContent2, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col justify-center", children: [
22423
- /* @__PURE__ */ jsx("p", { className: "text-3xl font-bold text-blue-600", children: clipCounts.cycleCompletions }),
22424
- /* @__PURE__ */ jsxs("div", { className: "flex items-center text-sm text-gray-500 mt-1", children: [
22425
- /* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-blue-600 mr-1.5" }),
22426
- /* @__PURE__ */ jsx("span", { children: "Completed production cycles" })
22427
- ] })
22428
- ] }) })
22429
- ]
22430
- }
22431
- )
22432
- ] }),
22527
+ },
22528
+ category.id
22529
+ );
22530
+ }) }),
22433
22531
  /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm overflow-hidden", style: { height: "calc(100% - 8.5rem)" }, children: [
22434
22532
  /* @__PURE__ */ jsx("div", { className: "px-4 py-3 border-b border-gray-100", children: /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center", children: [
22435
- /* @__PURE__ */ 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})` }),
22533
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-gray-800", children: (() => {
22534
+ if (activeFilter === "all") {
22535
+ return `All Clips (${clipCounts.total || 0})`;
22536
+ }
22537
+ const activeCategory = categoriesToShow.find((cat) => cat.id === activeFilter);
22538
+ if (activeCategory) {
22539
+ return `${activeCategory.label} (${clipCounts[activeCategory.id] || 0})`;
22540
+ }
22541
+ 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})`;
22542
+ })() }),
22436
22543
  /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
22437
22544
  /* @__PURE__ */ jsxs("div", { className: "relative", ref: timestampFilterRef, children: [
22438
22545
  /* @__PURE__ */ jsx(
@@ -23472,7 +23579,7 @@ var KPISection = memo(({
23472
23579
  });
23473
23580
  KPISection.displayName = "KPISection";
23474
23581
  var ISTTimer2 = ISTTimer_default;
23475
- var DashboardHeader = memo(({ lineTitle, className = "" }) => {
23582
+ var DashboardHeader = memo(({ lineTitle, className = "", headerControls }) => {
23476
23583
  const getShiftName = () => {
23477
23584
  const now2 = /* @__PURE__ */ new Date();
23478
23585
  const currentHour = now2.getHours();
@@ -23486,30 +23593,33 @@ var DashboardHeader = memo(({ lineTitle, className = "" }) => {
23486
23593
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
23487
23594
  }
23488
23595
  };
23489
- return /* @__PURE__ */ jsxs("div", { className: `flex flex-col ${className}`, children: [
23490
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 sm:gap-2 md:gap-3", children: [
23491
- /* @__PURE__ */ 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 }),
23492
- /* @__PURE__ */ 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" })
23493
- ] }),
23494
- /* @__PURE__ */ jsxs("div", { className: "mt-2 inline-flex items-center gap-3", children: [
23495
- /* @__PURE__ */ jsxs("div", { className: "text-sm font-medium text-gray-600", children: [
23496
- /* @__PURE__ */ jsx(ISTTimer2, {}),
23497
- " IST"
23596
+ return /* @__PURE__ */ jsxs("div", { className: `flex flex-row items-center justify-between w-full ${className}`, children: [
23597
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
23598
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 sm:gap-2 md:gap-3", children: [
23599
+ /* @__PURE__ */ 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 }),
23600
+ /* @__PURE__ */ 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" })
23498
23601
  ] }),
23499
- /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1", children: [
23500
- /* @__PURE__ */ jsx("div", { className: "text-gray-600", children: getShiftIcon() }),
23501
- /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
23502
- getShiftName(),
23503
- " Shift"
23602
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 inline-flex items-center gap-3", children: [
23603
+ /* @__PURE__ */ jsxs("div", { className: "text-sm font-medium text-gray-600", children: [
23604
+ /* @__PURE__ */ jsx(ISTTimer2, {}),
23605
+ " IST"
23606
+ ] }),
23607
+ /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1", children: [
23608
+ /* @__PURE__ */ jsx("div", { className: "text-gray-600", children: getShiftIcon() }),
23609
+ /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
23610
+ getShiftName(),
23611
+ " Shift"
23612
+ ] })
23504
23613
  ] })
23505
23614
  ] })
23506
- ] })
23615
+ ] }),
23616
+ headerControls && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-4", children: headerControls })
23507
23617
  ] });
23508
23618
  });
23509
23619
  DashboardHeader.displayName = "DashboardHeader";
23510
- var NoWorkspaceData = memo(({ className = "" }) => /* @__PURE__ */ jsx("div", { className: `flex h-full items-center justify-center ${className}`, children: /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-white p-4 shadow-md", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2 text-gray-500", children: [
23620
+ var NoWorkspaceData = memo(({ message = "No workspace data available", className = "" }) => /* @__PURE__ */ jsx("div", { className: `flex h-full items-center justify-center ${className}`, children: /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-white p-4 shadow-md", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2 text-gray-500", children: [
23511
23621
  /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ 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" }) }),
23512
- /* @__PURE__ */ jsx("span", { children: "No workspace data available" })
23622
+ /* @__PURE__ */ jsx("span", { children: message })
23513
23623
  ] }) }) }));
23514
23624
  NoWorkspaceData.displayName = "NoWorkspaceData";
23515
23625
  var WorkspaceMonthlyDataFetcher = ({
@@ -23851,15 +23961,14 @@ var SideNavBar = memo(({
23851
23961
  }
23852
23962
  }
23853
23963
  }), [navigate, lineId]);
23854
- const handleLeaderboardClick = useCallback(() => navigate(`/leaderboard/${lineId}`, {
23964
+ const handleLeaderboardClick = useCallback(() => navigate(`/leaderboard`, {
23855
23965
  trackingEvent: {
23856
23966
  name: "Leaderboard Page Clicked",
23857
23967
  properties: {
23858
- source: "side_nav",
23859
- line_id: lineId
23968
+ source: "side_nav"
23860
23969
  }
23861
23970
  }
23862
- }), [navigate, lineId]);
23971
+ }), [navigate]);
23863
23972
  const handleKPIsClick = useCallback(() => navigate(`/kpis`, {
23864
23973
  trackingEvent: {
23865
23974
  name: "KPI Page Clicked",
@@ -24806,14 +24915,6 @@ var AIAgentView = () => {
24806
24915
  return newMap;
24807
24916
  });
24808
24917
  },
24809
- onReasoning: (text) => {
24810
- setStreamingStates((prev) => {
24811
- const newMap = new Map(prev);
24812
- const current = newMap.get(currentThreadId) || { message: "", reasoning: "" };
24813
- newMap.set(currentThreadId, { ...current, reasoning: current.reasoning + text });
24814
- return newMap;
24815
- });
24816
- },
24817
24918
  onComplete: async (messageId) => {
24818
24919
  if (currentThreadId && !currentThreadId.startsWith("temp-")) {
24819
24920
  const updatedMessages = await getAllThreadMessages(currentThreadId);
@@ -27191,8 +27292,8 @@ var LoadingOverlayCmp = LoadingOverlay_default;
27191
27292
  function HomeView({
27192
27293
  defaultLineId,
27193
27294
  factoryViewId,
27194
- line1Uuid,
27195
- line2Uuid,
27295
+ lineIds: allLineIds = [],
27296
+ // Default to empty array
27196
27297
  lineNames,
27197
27298
  videoSources = {
27198
27299
  workspaceHlsUrls: {},
@@ -27201,14 +27302,21 @@ function HomeView({
27201
27302
  factoryName = "Simba Beer - Line 1"
27202
27303
  }) {
27203
27304
  const [isHydrated, setIsHydrated] = useState(false);
27204
- const [selectedLineId, setSelectedLineId] = useState(defaultLineId);
27305
+ const availableLineIds = useMemo(() => [factoryViewId, ...allLineIds], [factoryViewId, allLineIds]);
27306
+ const [selectedLineId, setSelectedLineId] = useState(factoryViewId);
27205
27307
  const [isChangingFilter, setIsChangingFilter] = useState(false);
27206
27308
  const [errorMessage, setErrorMessage] = useState(null);
27207
27309
  const [displayNamesInitialized, setDisplayNamesInitialized] = useState(false);
27208
27310
  useEffect(() => {
27209
27311
  const initDisplayNames = async () => {
27210
27312
  try {
27211
- await preInitializeWorkspaceDisplayNames(selectedLineId);
27313
+ if (selectedLineId === factoryViewId) {
27314
+ for (const lineId of allLineIds) {
27315
+ await preInitializeWorkspaceDisplayNames(lineId);
27316
+ }
27317
+ } else {
27318
+ await preInitializeWorkspaceDisplayNames(selectedLineId);
27319
+ }
27212
27320
  setDisplayNamesInitialized(true);
27213
27321
  } catch (error) {
27214
27322
  console.error("Failed to pre-initialize workspace display names:", error);
@@ -27216,7 +27324,7 @@ function HomeView({
27216
27324
  }
27217
27325
  };
27218
27326
  initDisplayNames();
27219
- }, [selectedLineId]);
27327
+ }, [selectedLineId, factoryViewId, allLineIds]);
27220
27328
  const {
27221
27329
  displayNames: workspaceDisplayNames,
27222
27330
  loading: displayNamesLoading,
@@ -27282,18 +27390,29 @@ function HomeView({
27282
27390
  setErrorMessage(null);
27283
27391
  }
27284
27392
  }, [metricsError, kpisError]);
27285
- useCallback((e) => {
27393
+ const handleLineChange = useCallback((value) => {
27286
27394
  setIsChangingFilter(true);
27287
- setSelectedLineId(e.target.value);
27395
+ setSelectedLineId(value);
27288
27396
  }, []);
27289
27397
  useEffect(() => {
27290
- if (!metricsLoading && !kpisLoading && isChangingFilter && workspaceMetrics.length > 0) {
27291
- setIsChangingFilter(false);
27398
+ if (!metricsLoading && !kpisLoading && isChangingFilter) {
27399
+ if (workspaceMetrics.length > 0 || selectedLineId === factoryViewId) {
27400
+ setIsChangingFilter(false);
27401
+ }
27292
27402
  }
27293
- }, [metricsLoading, kpisLoading, workspaceMetrics, isChangingFilter]);
27403
+ }, [metricsLoading, kpisLoading, workspaceMetrics, isChangingFilter, selectedLineId, factoryViewId]);
27294
27404
  const lineTitle = useMemo(() => {
27295
27405
  return factoryName;
27296
27406
  }, [factoryName]);
27407
+ const lineSelectorComponent = useMemo(() => {
27408
+ if (allLineIds.length <= 1) {
27409
+ return null;
27410
+ }
27411
+ return /* @__PURE__ */ jsxs(Select, { onValueChange: handleLineChange, defaultValue: selectedLineId, children: [
27412
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "w-full sm:w-[200px] bg-white border border-gray-200 shadow-sm rounded-md h-9 text-sm", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select a line" }) }),
27413
+ /* @__PURE__ */ jsx(SelectContent, { className: "z-50 bg-white shadow-lg border border-gray-200 rounded-md", children: availableLineIds.map((id3) => /* @__PURE__ */ jsx(SelectItem, { value: id3, children: lineNames[id3] || (id3 === factoryViewId ? "All Lines" : `Line ${id3.substring(0, 4)}`) }, id3)) })
27414
+ ] });
27415
+ }, [availableLineIds, handleLineChange, selectedLineId, lineNames, factoryViewId, allLineIds.length]);
27297
27416
  const isLoading = !isHydrated || metricsLoading || kpisLoading || isChangingFilter || displayNamesLoading || !displayNamesInitialized;
27298
27417
  if (isLoading) {
27299
27418
  return /* @__PURE__ */ jsx("div", { className: "min-h-screen bg-slate-50", children: /* @__PURE__ */ jsx(LoadingPageCmp, { message: "Loading dashboard..." }) });
@@ -27307,7 +27426,7 @@ function HomeView({
27307
27426
  ] })
27308
27427
  ] }) }) });
27309
27428
  }
27310
- if ((metricsLoading || kpisLoading) && (!workspaceMetrics || workspaceMetrics.length === 0)) {
27429
+ if ((metricsLoading || kpisLoading) && (!workspaceMetrics || workspaceMetrics.length === 0) && selectedLineId !== factoryViewId) {
27311
27430
  return /* @__PURE__ */ jsx("div", { className: "min-h-screen bg-slate-50", children: /* @__PURE__ */ jsx(LoadingPageCmp, { message: "Loading metrics..." }) });
27312
27431
  }
27313
27432
  return /* @__PURE__ */ jsxs(
@@ -27318,28 +27437,36 @@ function HomeView({
27318
27437
  animate: { opacity: 1 },
27319
27438
  children: [
27320
27439
  /* @__PURE__ */ jsx(LoadingOverlayCmp, { isVisible: isChangingFilter, message: "Loading new metrics..." }),
27321
- /* @__PURE__ */ jsxs("main", { className: "flex flex-1 flex-col", children: [
27322
- /* @__PURE__ */ jsx("div", { className: "sticky top-0 z-10 sm:static bg-white shadow-sm border-b border-gray-200/80", children: /* @__PURE__ */ 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: [
27323
- /* @__PURE__ */ jsx(DashboardHeader, { lineTitle, className: "mb-1 sm:mb-0" }),
27324
- memoizedKPIs && /* @__PURE__ */ jsx(KPISection2, { kpis: memoizedKPIs, className: "w-full sm:w-auto" })
27325
- ] }) }),
27326
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto sm:overflow-hidden", children: memoizedWorkspaceMetrics.length > 0 ? /* @__PURE__ */ jsx("div", { className: "h-full sm:h-full min-h-[calc(100vh-80px)] sm:min-h-0", children: React14__default.createElement(WorkspaceGrid, {
27327
- workspaces: memoizedWorkspaceMetrics,
27328
- lineNames,
27329
- factoryView: factoryViewId,
27330
- line2Uuid,
27331
- videoSources,
27332
- className: "h-full"
27333
- }) }) : /* @__PURE__ */ jsx(NoWorkspaceData, {}) })
27334
- ] }),
27335
- /* @__PURE__ */ jsx(
27336
- BreakNotificationPopup,
27337
- {
27338
- activeBreaks,
27339
- lineNames,
27340
- isVisible: !breaksLoading && !breaksError
27341
- }
27342
- )
27440
+ /* @__PURE__ */ jsxs("div", { className: "relative flex flex-1", children: [
27441
+ /* @__PURE__ */ jsxs("main", { className: "flex flex-1 flex-col", children: [
27442
+ /* @__PURE__ */ jsx("div", { className: "sticky top-0 z-30 sm:static bg-white shadow-sm border-b border-gray-200/80", children: /* @__PURE__ */ 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__ */ jsx(
27443
+ DashboardHeader,
27444
+ {
27445
+ lineTitle,
27446
+ className: "w-full",
27447
+ headerControls: memoizedKPIs ? /* @__PURE__ */ jsx(KPISection2, { kpis: memoizedKPIs, className: "w-full sm:w-auto" }) : null
27448
+ }
27449
+ ) }) }),
27450
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto sm:overflow-hidden relative", children: [
27451
+ lineSelectorComponent && /* @__PURE__ */ jsx("div", { className: "absolute right-3 top-2 sm:right-6 sm:top-3 z-30", children: lineSelectorComponent }),
27452
+ memoizedWorkspaceMetrics.length > 0 ? /* @__PURE__ */ jsx("div", { className: "h-full sm:h-full min-h-[calc(100vh-80px)] sm:min-h-0", children: React14__default.createElement(WorkspaceGrid, {
27453
+ workspaces: memoizedWorkspaceMetrics,
27454
+ lineNames,
27455
+ factoryView: factoryViewId,
27456
+ videoSources,
27457
+ className: "h-full"
27458
+ }) }) : /* @__PURE__ */ jsx(NoWorkspaceData, { message: "No workspace data available. Select another line or check configurations." })
27459
+ ] })
27460
+ ] }),
27461
+ /* @__PURE__ */ jsx(
27462
+ BreakNotificationPopup,
27463
+ {
27464
+ activeBreaks,
27465
+ lineNames,
27466
+ isVisible: !breaksLoading && !breaksError
27467
+ }
27468
+ )
27469
+ ] })
27343
27470
  ]
27344
27471
  }
27345
27472
  );
@@ -27503,7 +27630,7 @@ var BottomSection = memo(({
27503
27630
  "div",
27504
27631
  {
27505
27632
  className: "p-1.5 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer",
27506
- onClick: () => handleNavigate && handleNavigate(`/leaderboard/${lineInfo?.line_id}`),
27633
+ onClick: () => handleNavigate && handleNavigate(`/leaderboard`),
27507
27634
  children: /* @__PURE__ */ jsx(ArrowRightIcon, { className: "w-5 h-5 text-gray-500" })
27508
27635
  }
27509
27636
  )
@@ -28602,7 +28729,7 @@ var LeaderboardDetailView = memo(({
28602
28729
  className = ""
28603
28730
  }) => {
28604
28731
  const navigation = useNavigation();
28605
- const [sortAscending, setSortAscending] = useState(true);
28732
+ const [sortAscending, setSortAscending] = useState(false);
28606
28733
  const handleSortToggle = useCallback(() => {
28607
28734
  setSortAscending(!sortAscending);
28608
28735
  }, [sortAscending]);
@@ -28618,13 +28745,15 @@ var LeaderboardDetailView = memo(({
28618
28745
  error: metricsError,
28619
28746
  refreshMetrics
28620
28747
  } = useRealtimeLineMetrics(realtimeMetricsParams);
28621
- const memoizedLineId = useMemo(() => lineId || "", [lineId]);
28622
28748
  const {
28623
28749
  workspaces,
28624
28750
  loading: workspacesLoading,
28625
28751
  error: workspacesError,
28626
28752
  refreshWorkspaces
28627
- } = useLineWorkspaceMetrics(memoizedLineId);
28753
+ } = useAllWorkspaceMetrics({
28754
+ initialDate: date,
28755
+ initialShiftId: typeof shift === "number" ? shift : typeof shift === "string" ? parseInt(shift) : void 0
28756
+ });
28628
28757
  const getShiftName = useCallback((shiftId) => {
28629
28758
  if (shiftId === void 0) return "Day";
28630
28759
  return shiftId === 0 ? "Day" : "Night";
@@ -28678,7 +28807,7 @@ var LeaderboardDetailView = memo(({
28678
28807
  });
28679
28808
  const displayName = getWorkspaceDisplayName(workspace.workspace_name);
28680
28809
  const navParams = workspace.workspace_uuid ? getWorkspaceNavigationParams(workspace.workspace_uuid, displayName) : "";
28681
- const returnToParam = `&returnTo=${encodeURIComponent(`/leaderboard/${lineId}`)}`;
28810
+ const returnToParam = `&returnTo=${encodeURIComponent(`/leaderboard`)}`;
28682
28811
  if (onWorkspaceClick) {
28683
28812
  onWorkspaceClick(workspace, rank);
28684
28813
  } else {
@@ -32161,4 +32290,4 @@ var S3Service = class {
32161
32290
  }
32162
32291
  };
32163
32292
 
32164
- export { ACTION_NAMES, AIAgentView_default as AIAgentView, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedTargetsView, BarChart, BaseHistoryCalendar, BottlenecksContent, BreakNotificationPopup, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, EmptyStateMessage, FactoryView_default as FactoryView, GaugeChart, GridComponentsPlaceholder, Header, HelpView_default as HelpView, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend6 as Legend, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LiveTimer, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSpinner_default as LoadingSpinner, LoginPage, LoginView_default as LoginView, MainLayout, MetricCard_default as MetricCard, NoWorkspaceData, OptifyeAgentClient, OutputProgressChart, PageHeader, PieChart4 as PieChart, ProfileView_default as ProfileView, RegistryProvider, S3Service, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SingleVideoStream_default as SingleVideoStream, Skeleton, SlackAPI, SupabaseProvider, TargetWorkspaceGrid, TargetsView_default as TargetsView, ThreadSidebar, TimeDisplay_default as TimeDisplay, TimePickerDropdown, VideoCard, VideoGridView, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, authCoreService, authOTPService, authRateLimitService, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createStreamProxyHandler, createSupabaseClient, createThrottledReload, dashboardService, deleteThread, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatTimeInZone, fromUrlFriendlyName, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getCurrentShift, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultTabForWorkspace, getManufacturingInsights, getMetricsTablePrefix, getOperationalDate, getS3SignedUrl, getS3VideoSrc, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getThreadMessages, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, identifyCoreUser, initializeCoreMixpanel, isTransitionPeriod, isValidLineInfoPayload, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, mergeWithDefaultConfig, optifyeAgentClient, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, s3VideoPreloader, storeWorkspaceMapping, streamProxyConfig, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, updateThreadTitle, useActiveBreaks, useAnalyticsConfig, useAuth, useAuthConfig, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineWorkspaceMetrics, useMessages, useMetrics, useNavigation, useOverrides, usePageOverride, useRealtimeLineMetrics, useRegistry, useShiftConfig, useShifts, useSupabase, useSupabaseClient, useTargets, useTheme, useThemeConfig, useThreads, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, videoPreloader, whatsappService, withAuth, withRegistry, workspaceService };
32293
+ export { ACTION_NAMES, AIAgentView_default as AIAgentView, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedTargetsView, BarChart, BaseHistoryCalendar, BottlenecksContent, BreakNotificationPopup, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, EmptyStateMessage, FactoryView_default as FactoryView, GaugeChart, GridComponentsPlaceholder, Header, HelpView_default as HelpView, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend6 as Legend, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LiveTimer, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSpinner_default as LoadingSpinner, LoginPage, LoginView_default as LoginView, MainLayout, MetricCard_default as MetricCard, NoWorkspaceData, OptifyeAgentClient, OutputProgressChart, PageHeader, PieChart4 as PieChart, ProfileView_default as ProfileView, RegistryProvider, S3Service, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SingleVideoStream_default as SingleVideoStream, Skeleton, SlackAPI, SupabaseProvider, TargetWorkspaceGrid, TargetsView_default as TargetsView, ThreadSidebar, TimeDisplay_default as TimeDisplay, TimePickerDropdown, VideoCard, VideoGridView, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, authCoreService, authOTPService, authRateLimitService, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createStreamProxyHandler, createSupabaseClient, createThrottledReload, dashboardService, deleteThread, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatTimeInZone, fromUrlFriendlyName, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getCurrentShift, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultTabForWorkspace, getManufacturingInsights, getMetricsTablePrefix, getOperationalDate, getS3SignedUrl, getS3VideoSrc, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getThreadMessages, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, identifyCoreUser, initializeCoreMixpanel, isTransitionPeriod, isValidLineInfoPayload, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, mergeWithDefaultConfig, optifyeAgentClient, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, s3VideoPreloader, storeWorkspaceMapping, streamProxyConfig, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, updateThreadTitle, useActiveBreaks, useAllWorkspaceMetrics, useAnalyticsConfig, useAuth, useAuthConfig, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineWorkspaceMetrics, useMessages, useMetrics, useNavigation, useOverrides, usePageOverride, useRealtimeLineMetrics, useRegistry, useShiftConfig, useShifts, useSupabase, useSupabaseClient, useTargets, useTheme, useThemeConfig, useThreads, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, videoPreloader, whatsappService, withAuth, withRegistry, workspaceService };