@optifye/dashboard-core 6.5.1 → 6.5.3

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
@@ -13,7 +13,7 @@ import { noop, warning, invariant, progress, secondsToMilliseconds, milliseconds
13
13
  import { getValueTransition, hover, press, isPrimaryPointer, GroupPlaybackControls, setDragLock, supportsLinearEasing, attachTimeline, isGenerator, calcGeneratorDuration, isWaapiSupportedEasing, mapEasingToNativeEasing, maxGeneratorDuration, generateLinearEasing, isBezierDefinition } from 'motion-dom';
14
14
  import { BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, Tooltip, Legend, Bar, LabelList, ResponsiveContainer, LineChart as LineChart$1, Line, PieChart, Pie, Cell, ReferenceLine, ComposedChart, Area, ScatterChart, Scatter } from 'recharts';
15
15
  import { Slot } from '@radix-ui/react-slot';
16
- import { Camera, ChevronDown, ChevronUp, Check, ShieldCheck, Star, Award, X, Coffee, Plus, ArrowLeft, Clock, Calendar, Save, Minus, ArrowDown, ArrowUp, Settings2, CheckCircle2, Search, Loader2, AlertCircle, Edit2, CheckCircle, AlertTriangle, Info, Share2, Trophy, Target, Download, User, XCircle, ChevronLeft, ChevronRight, Sun, Moon, MessageSquare, Trash2, RefreshCw, Menu, Send, Copy, UserCheck, LogOut, Package, TrendingUp, TrendingDown, Activity, Settings, LifeBuoy, EyeOff, Eye, Zap, UserCircle } from 'lucide-react';
16
+ import { Camera, ChevronDown, ChevronUp, Check, ShieldCheck, Star, Award, X, Coffee, Plus, ArrowLeft, Clock, Calendar, Save, Minus, ArrowDown, ArrowUp, Settings2, CheckCircle2, Search, Loader2, AlertCircle, Edit2, CheckCircle, AlertTriangle, Info, Share2, Trophy, Target, Download, User, XCircle, ChevronLeft, ChevronRight, Activity, Sun, Moon, MessageSquare, Trash2, RefreshCw, Menu, Send, Copy, UserCheck, LogOut, Package, TrendingUp, TrendingDown, Settings, LifeBuoy, EyeOff, Eye, Zap, UserCircle } from 'lucide-react';
17
17
  import { DayPicker, useNavigation as useNavigation$1 } from 'react-day-picker';
18
18
  import { XMarkIcon, ArrowRightIcon, HomeIcon, TrophyIcon, ChartBarIcon, AdjustmentsHorizontalIcon, ClockIcon, CubeIcon, SparklesIcon, QuestionMarkCircleIcon, HeartIcon, UserCircleIcon, ExclamationCircleIcon, EnvelopeIcon, DocumentTextIcon, ChevronUpIcon, ChevronDownIcon, Bars3Icon, CheckCircleIcon, ChatBubbleLeftRightIcon, XCircleIcon, InformationCircleIcon, ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/24/outline';
19
19
  import { CheckIcon } from '@heroicons/react/24/solid';
@@ -1875,7 +1875,29 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
1875
1875
  throw error;
1876
1876
  }
1877
1877
  const processedData = (data || []).map((item) => this.processHealthStatus(item));
1878
- let filteredData = processedData;
1878
+ let uptimeMap = /* @__PURE__ */ new Map();
1879
+ if (options.companyId || data && data.length > 0) {
1880
+ const companyId = options.companyId || data[0]?.company_id;
1881
+ if (companyId) {
1882
+ try {
1883
+ uptimeMap = await this.calculateWorkspaceUptime(companyId);
1884
+ } catch (error2) {
1885
+ console.error("Error calculating uptime:", error2);
1886
+ }
1887
+ }
1888
+ }
1889
+ const dataWithUptime = processedData.map((workspace) => {
1890
+ const uptimeDetails = uptimeMap.get(workspace.workspace_id);
1891
+ if (uptimeDetails) {
1892
+ return {
1893
+ ...workspace,
1894
+ uptimePercentage: uptimeDetails.percentage,
1895
+ uptimeDetails
1896
+ };
1897
+ }
1898
+ return workspace;
1899
+ });
1900
+ let filteredData = dataWithUptime;
1879
1901
  try {
1880
1902
  const { data: enabledWorkspaces, error: workspaceError } = await supabase.from("workspaces").select("workspace_id, display_name").eq("enable", true);
1881
1903
  if (!workspaceError && enabledWorkspaces && enabledWorkspaces.length > 0) {
@@ -1951,13 +1973,31 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
1951
1973
  const healthyWorkspaces = workspaces.filter((w) => w.status === "healthy").length;
1952
1974
  const unhealthyWorkspaces = workspaces.filter((w) => w.status === "unhealthy").length;
1953
1975
  const warningWorkspaces = workspaces.filter((w) => w.status === "warning").length;
1954
- const uptimePercentage = totalWorkspaces > 0 ? healthyWorkspaces / totalWorkspaces * 100 : 0;
1976
+ let uptimePercentage = 0;
1977
+ let totalDowntimeMinutes = 0;
1978
+ if (totalWorkspaces > 0) {
1979
+ const workspacesWithUptime = workspaces.filter((w) => w.uptimePercentage !== void 0 && w.uptimeDetails !== void 0);
1980
+ if (workspacesWithUptime.length > 0) {
1981
+ const totalUptime = workspacesWithUptime.reduce((sum, w) => sum + (w.uptimePercentage || 0), 0);
1982
+ uptimePercentage = totalUptime / workspacesWithUptime.length;
1983
+ totalDowntimeMinutes = workspacesWithUptime.reduce((sum, w) => {
1984
+ if (w.uptimeDetails) {
1985
+ const downtime = Math.max(0, w.uptimeDetails.expectedMinutes - w.uptimeDetails.actualMinutes);
1986
+ return sum + downtime;
1987
+ }
1988
+ return sum;
1989
+ }, 0);
1990
+ } else {
1991
+ uptimePercentage = healthyWorkspaces / totalWorkspaces * 100;
1992
+ }
1993
+ }
1955
1994
  return {
1956
1995
  totalWorkspaces,
1957
1996
  healthyWorkspaces,
1958
1997
  unhealthyWorkspaces,
1959
1998
  warningWorkspaces,
1960
1999
  uptimePercentage,
2000
+ totalDowntimeMinutes,
1961
2001
  lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
1962
2002
  };
1963
2003
  }
@@ -2037,6 +2077,155 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2037
2077
  clearCache() {
2038
2078
  this.cache.clear();
2039
2079
  }
2080
+ async calculateWorkspaceUptime(companyId) {
2081
+ const supabase = _getSupabaseInstance();
2082
+ if (!supabase) throw new Error("Supabase client not initialized");
2083
+ const dashboardConfig = _getDashboardConfigInstance();
2084
+ const timezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
2085
+ const shiftConfig = dashboardConfig?.shiftConfig;
2086
+ const currentShiftInfo = getCurrentShift(timezone, shiftConfig);
2087
+ const currentDate = currentShiftInfo.date;
2088
+ const currentShiftId = currentShiftInfo.shiftId;
2089
+ const now2 = /* @__PURE__ */ new Date();
2090
+ const currentHour = now2.getHours();
2091
+ const currentMinute = now2.getMinutes();
2092
+ let shiftStartHour;
2093
+ let shiftEndHour;
2094
+ if (currentShiftId === 0) {
2095
+ shiftStartHour = 9;
2096
+ shiftEndHour = 18;
2097
+ } else {
2098
+ shiftStartHour = 20;
2099
+ shiftEndHour = 3;
2100
+ }
2101
+ let elapsedMinutes = 0;
2102
+ if (currentShiftId === 0) {
2103
+ if (currentHour >= shiftStartHour && currentHour < shiftEndHour) {
2104
+ elapsedMinutes = (currentHour - shiftStartHour) * 60 + currentMinute;
2105
+ } else if (currentHour >= shiftEndHour) {
2106
+ elapsedMinutes = (shiftEndHour - shiftStartHour) * 60;
2107
+ }
2108
+ } else {
2109
+ if (currentHour >= shiftStartHour) {
2110
+ elapsedMinutes = (currentHour - shiftStartHour) * 60 + currentMinute;
2111
+ } else if (currentHour < shiftEndHour) {
2112
+ elapsedMinutes = (24 - shiftStartHour + currentHour) * 60 + currentMinute;
2113
+ }
2114
+ }
2115
+ const tableName = `performance_metrics_${companyId.replace(/-/g, "_")}`;
2116
+ const query = `
2117
+ WITH workspace_uptime AS (
2118
+ SELECT
2119
+ workspace_id,
2120
+ workspace_display_name,
2121
+ idle_time_hourly,
2122
+ output_hourly,
2123
+ shift_start,
2124
+ shift_end
2125
+ FROM ${tableName}
2126
+ WHERE date = $1::date
2127
+ AND shift_id = $2
2128
+ ),
2129
+ calculated_uptime AS (
2130
+ SELECT
2131
+ workspace_id,
2132
+ workspace_display_name,
2133
+ -- Calculate actual minutes from hourly data
2134
+ (
2135
+ SELECT COALESCE(SUM(
2136
+ CASE
2137
+ WHEN jsonb_array_length(idle_time_hourly->key::text) >= 58 THEN 60
2138
+ WHEN jsonb_array_length(idle_time_hourly->key::text) > 0 THEN jsonb_array_length(idle_time_hourly->key::text)
2139
+ ELSE 0
2140
+ END
2141
+ ), 0)
2142
+ FROM jsonb_object_keys(idle_time_hourly) AS key
2143
+ WHERE key::int >= $3 AND key::int < $4
2144
+ ) +
2145
+ -- Add current hour's data if applicable
2146
+ CASE
2147
+ WHEN $4::int >= $3 AND $4::int < $5 THEN
2148
+ LEAST($6::int,
2149
+ COALESCE(jsonb_array_length(idle_time_hourly->$4::text), 0))
2150
+ ELSE 0
2151
+ END as actual_minutes
2152
+ FROM workspace_uptime
2153
+ )
2154
+ SELECT
2155
+ workspace_id,
2156
+ workspace_display_name,
2157
+ actual_minutes,
2158
+ $7::int as expected_minutes,
2159
+ ROUND(
2160
+ CASE
2161
+ WHEN $7::int > 0 THEN (actual_minutes::numeric / $7::numeric) * 100
2162
+ ELSE 100
2163
+ END, 1
2164
+ ) as uptime_percentage
2165
+ FROM calculated_uptime
2166
+ `;
2167
+ try {
2168
+ const { data, error } = await supabase.rpc("sql_query", {
2169
+ query_text: query,
2170
+ params: [
2171
+ currentDate,
2172
+ currentShiftId,
2173
+ shiftStartHour,
2174
+ currentHour,
2175
+ shiftEndHour,
2176
+ currentMinute,
2177
+ elapsedMinutes
2178
+ ]
2179
+ }).single();
2180
+ if (error) {
2181
+ const { data: queryData, error: queryError } = await supabase.from(tableName).select("workspace_id, workspace_display_name, idle_time_hourly, output_hourly").eq("date", currentDate).eq("shift_id", currentShiftId);
2182
+ if (queryError) {
2183
+ console.error("Error fetching performance metrics:", queryError);
2184
+ return /* @__PURE__ */ new Map();
2185
+ }
2186
+ const uptimeMap2 = /* @__PURE__ */ new Map();
2187
+ for (const record of queryData || []) {
2188
+ let actualMinutes = 0;
2189
+ const idleTimeHourly = record.idle_time_hourly || {};
2190
+ if (idleTimeHourly && typeof idleTimeHourly === "object") {
2191
+ for (const [hour, dataArray] of Object.entries(idleTimeHourly)) {
2192
+ const hourNum = parseInt(hour);
2193
+ if (hourNum >= shiftStartHour && hourNum < currentHour) {
2194
+ const arrayLength = Array.isArray(dataArray) ? dataArray.length : 0;
2195
+ actualMinutes += arrayLength >= 58 ? 60 : arrayLength;
2196
+ } else if (hourNum === currentHour && currentHour >= shiftStartHour) {
2197
+ const arrayLength = Array.isArray(dataArray) ? dataArray.length : 0;
2198
+ actualMinutes += Math.min(currentMinute, arrayLength);
2199
+ }
2200
+ }
2201
+ }
2202
+ const percentage = elapsedMinutes > 0 ? Math.round(actualMinutes / elapsedMinutes * 1e3) / 10 : 100;
2203
+ uptimeMap2.set(record.workspace_id, {
2204
+ expectedMinutes: elapsedMinutes,
2205
+ actualMinutes,
2206
+ percentage,
2207
+ lastCalculated: (/* @__PURE__ */ new Date()).toISOString()
2208
+ });
2209
+ }
2210
+ return uptimeMap2;
2211
+ }
2212
+ const uptimeMap = /* @__PURE__ */ new Map();
2213
+ if (Array.isArray(data)) {
2214
+ for (const record of data) {
2215
+ uptimeMap.set(record.workspace_id, {
2216
+ expectedMinutes: record.expected_minutes,
2217
+ actualMinutes: record.actual_minutes,
2218
+ percentage: record.uptime_percentage,
2219
+ lastCalculated: (/* @__PURE__ */ new Date()).toISOString()
2220
+ });
2221
+ }
2222
+ }
2223
+ return uptimeMap;
2224
+ } catch (error) {
2225
+ console.error("Error calculating workspace uptime:", error);
2226
+ return /* @__PURE__ */ new Map();
2227
+ }
2228
+ }
2040
2229
  };
2041
2230
  var workspaceHealthService = WorkspaceHealthService.getInstance();
2042
2231
 
@@ -4122,6 +4311,23 @@ var S3ClipsAPIClient = class {
4122
4311
  };
4123
4312
  });
4124
4313
  }
4314
+ /**
4315
+ * Batch fetch multiple videos in parallel
4316
+ */
4317
+ async batchFetchVideos(workspaceId, date, shiftId, requests) {
4318
+ const batchKey = `batch:${workspaceId}:${date}:${shiftId}:${requests.length}`;
4319
+ return this.deduplicate(batchKey, async () => {
4320
+ const response = await this.fetchWithAuth("/api/clips/batch", {
4321
+ workspaceId,
4322
+ date,
4323
+ shift: shiftId.toString(),
4324
+ requests,
4325
+ sopCategories: this.sopCategories
4326
+ });
4327
+ console.log(`[S3ClipsAPIClient] Batch fetched ${response.videos.length} videos in ${response.performance.duration}ms`);
4328
+ return response.videos;
4329
+ });
4330
+ }
4125
4331
  /**
4126
4332
  * Convert S3 URI to CloudFront URL
4127
4333
  * In the API client, URLs are already signed from the server
@@ -4405,6 +4611,23 @@ var S3ClipsService = class {
4405
4611
  );
4406
4612
  return result.videos;
4407
4613
  }
4614
+ /**
4615
+ * Batch fetch multiple videos in parallel
4616
+ */
4617
+ async batchFetchVideos(workspaceId, date, shiftId, requests) {
4618
+ try {
4619
+ const results = await this.apiClient.batchFetchVideos(
4620
+ workspaceId,
4621
+ date,
4622
+ shiftId,
4623
+ requests
4624
+ );
4625
+ return results.map((r2) => r2.video).filter((v) => v !== null);
4626
+ } catch (error) {
4627
+ console.error("[S3ClipsService] Error batch fetching videos:", error);
4628
+ return [];
4629
+ }
4630
+ }
4408
4631
  /**
4409
4632
  * Get videos page using pagination API
4410
4633
  */
@@ -19661,7 +19884,7 @@ var OptifyeLogoLoader = ({
19661
19884
  className: `${sizeClasses[size]} h-auto animate-pulse select-none pointer-events-none`
19662
19885
  }
19663
19886
  ),
19664
- message && /* @__PURE__ */ jsx("div", { className: "mt-3 text-gray-600 text-sm font-medium text-center", children: message })
19887
+ message && /* @__PURE__ */ jsx("div", { className: "mt-3 text-gray-600 text-base sm:text-sm font-medium text-center", children: message })
19665
19888
  ]
19666
19889
  }
19667
19890
  );
@@ -21572,8 +21795,8 @@ var VideoCard = React19__default.memo(({
21572
21795
  ] }) }),
21573
21796
  /* @__PURE__ */ jsxs("div", { className: "relative w-full h-full overflow-hidden bg-black", children: [
21574
21797
  /* @__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: [
21575
- /* @__PURE__ */ jsx(Camera, { className: `${compact ? "w-4 h-4" : "w-6 h-6"} text-gray-500` }),
21576
- /* @__PURE__ */ jsx("span", { className: `${compact ? "text-[10px]" : "text-xs"} text-gray-500 mt-1`, children: "Loading..." })
21798
+ /* @__PURE__ */ jsx(Camera, { className: `w-5 h-5 sm:${compact ? "w-4 h-4" : "w-6 h-6"} text-gray-500` }),
21799
+ /* @__PURE__ */ jsx("span", { className: `text-[11px] sm:${compact ? "text-[10px]" : "text-xs"} text-gray-500 mt-1`, children: "Loading..." })
21577
21800
  ] }) }),
21578
21801
  /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 z-10", children: [
21579
21802
  /* @__PURE__ */ jsx(
@@ -21608,10 +21831,10 @@ var VideoCard = React19__default.memo(({
21608
21831
  }
21609
21832
  ) })
21610
21833
  ] }),
21611
- /* @__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: [
21834
+ /* @__PURE__ */ jsxs("div", { className: `absolute bottom-0 left-0 right-0 bg-black bg-opacity-60 p-1.5 sm:${compact ? "p-1" : "p-1.5"} flex justify-between items-center z-10`, children: [
21612
21835
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
21613
21836
  /* @__PURE__ */ jsx(Camera, { size: compact ? 10 : 12, className: "text-white" }),
21614
- /* @__PURE__ */ jsx("p", { className: `text-white ${compact ? "text-[10px]" : "text-xs"} font-medium tracking-wide`, children: displayName })
21837
+ /* @__PURE__ */ jsx("p", { className: `text-white text-[11px] sm:${compact ? "text-[10px]" : "text-xs"} font-medium tracking-wide`, children: displayName })
21615
21838
  ] }),
21616
21839
  /* @__PURE__ */ jsxs("div", { className: `flex items-center ${compact ? "gap-1" : "gap-1.5"}`, children: [
21617
21840
  trendInfo && /* @__PURE__ */ jsx(
@@ -21623,7 +21846,7 @@ var VideoCard = React19__default.memo(({
21623
21846
  }
21624
21847
  ),
21625
21848
  /* @__PURE__ */ jsx("div", { className: `${compact ? "w-1 h-1" : "w-1.5 h-1.5"} rounded-full bg-green-500` }),
21626
- /* @__PURE__ */ jsx("span", { className: `text-white ${compact ? "text-[10px]" : "text-xs"}`, children: "Live" })
21849
+ /* @__PURE__ */ jsx("span", { className: `text-white text-[11px] sm:${compact ? "text-[10px]" : "text-xs"}`, children: "Live" })
21627
21850
  ] })
21628
21851
  ] })
21629
21852
  ]
@@ -21833,10 +22056,10 @@ var VideoGridView = React19__default.memo(({
21833
22056
  view_type: "video_grid"
21834
22057
  });
21835
22058
  }, []);
21836
- return /* @__PURE__ */ jsx("div", { className: `relative overflow-hidden h-full w-full ${className}`, children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "h-full w-full p-2", children: /* @__PURE__ */ jsx(
22059
+ return /* @__PURE__ */ jsx("div", { className: `relative overflow-hidden h-full w-full ${className}`, children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "h-full w-full p-3 sm:p-2", children: /* @__PURE__ */ jsx(
21837
22060
  "div",
21838
22061
  {
21839
- className: "grid h-full w-full gap-2",
22062
+ className: "grid h-full w-full gap-3 sm:gap-2",
21840
22063
  style: {
21841
22064
  gridTemplateColumns: `repeat(${gridCols}, 1fr)`,
21842
22065
  gridTemplateRows: `repeat(${gridRows}, 1fr)`,
@@ -22621,15 +22844,15 @@ var BreakNotificationPopup = ({
22621
22844
  /* @__PURE__ */ jsx("div", { className: "w-2 h-2 bg-amber-500 rounded-full animate-pulse flex-shrink-0 mt-2" }),
22622
22845
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
22623
22846
  /* @__PURE__ */ jsxs("div", { className: "mb-1", children: [
22624
- /* @__PURE__ */ jsx("h4", { className: "font-semibold text-sm text-gray-900", children: breakItem.remarks || "Break" }),
22625
- (activeBreaks.length > 1 || lineNames[breakItem.lineId]) && /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500 mt-0.5", children: lineNames[breakItem.lineId] || `Line ${breakItem.lineId.substring(0, 8)}` })
22847
+ /* @__PURE__ */ jsx("h4", { className: "font-semibold text-base sm:text-sm text-gray-900", children: breakItem.remarks || "Break" }),
22848
+ (activeBreaks.length > 1 || lineNames[breakItem.lineId]) && /* @__PURE__ */ jsx("div", { className: "text-sm sm:text-xs text-gray-500 mt-0.5", children: lineNames[breakItem.lineId] || `Line ${breakItem.lineId.substring(0, 8)}` })
22626
22849
  ] }),
22627
- /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-600 font-medium", children: [
22850
+ /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxs("div", { className: "text-sm sm:text-xs text-gray-600 font-medium", children: [
22628
22851
  breakItem.startTime,
22629
22852
  " - ",
22630
22853
  breakItem.endTime
22631
22854
  ] }) }),
22632
- /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-500", children: [
22855
+ /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxs("div", { className: "text-sm sm:text-xs text-gray-500", children: [
22633
22856
  formatTime3(breakItem.elapsedMinutes),
22634
22857
  " / ",
22635
22858
  formatTime3(breakItem.duration)
@@ -23347,7 +23570,7 @@ var TimeDisplay = ({ className, variant = "default" }) => {
23347
23570
  className: `flex items-center space-x-1.5 bg-white/60 backdrop-blur-sm px-2 py-0.5 rounded-md shadow-xs ${className || ""}`,
23348
23571
  children: [
23349
23572
  /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-3 w-3 text-[var(--primary-DEFAULT)]", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z", clipRule: "evenodd" }) }),
23350
- /* @__PURE__ */ jsxs("span", { className: "text-[11px] font-medium text-gray-800 tabular-nums tracking-tight", children: [
23573
+ /* @__PURE__ */ jsxs("span", { className: "text-xs sm:text-[11px] font-medium text-gray-800 tabular-nums tracking-tight", children: [
23351
23574
  time2,
23352
23575
  " ",
23353
23576
  timeSuffix
@@ -26994,44 +27217,73 @@ var BottlenecksContent = ({
26994
27217
  if (indicesToLoad.length === 0) return;
26995
27218
  console.log(`[ensureVideosLoaded] Preloading ${indicesToLoad.length} videos around index ${centerIndex}: [${indicesToLoad.join(", ")}]`);
26996
27219
  indicesToLoad.forEach((idx) => loadingVideosRef.current.add(idx));
26997
- const loadPromises = indicesToLoad.map(async (index) => {
26998
- try {
26999
- let video = null;
27000
- if (!video) {
27001
- const operationalDate = date || getOperationalDate();
27002
- const shiftStr = effectiveShift;
27003
- video = await s3ClipsService.getClipByIndex(
27220
+ const operationalDate = date || getOperationalDate();
27221
+ const shiftStr = effectiveShift;
27222
+ console.log(`[ensureVideosLoaded] Batch fetching ${indicesToLoad.length} videos in parallel`);
27223
+ try {
27224
+ const batchRequests = indicesToLoad.map((index) => ({
27225
+ category: effectiveFilter,
27226
+ index,
27227
+ includeMetadata: false
27228
+ // No metadata during bulk preloading
27229
+ }));
27230
+ const videos = await s3ClipsService.batchFetchVideos(
27231
+ workspaceId,
27232
+ operationalDate,
27233
+ shiftStr,
27234
+ batchRequests
27235
+ );
27236
+ if (videos.length > 0 && isMountedRef.current) {
27237
+ videos.forEach((video, idx) => {
27238
+ if (video) {
27239
+ setAllVideos((prev) => {
27240
+ const exists = prev.some((v) => v.id === video.id);
27241
+ if (!exists) {
27242
+ return [...prev, video];
27243
+ }
27244
+ return prev;
27245
+ });
27246
+ const originalIndex = indicesToLoad[idx];
27247
+ loadedIndices.add(originalIndex);
27248
+ preloadVideoUrl(video.src);
27249
+ }
27250
+ });
27251
+ console.log(`[ensureVideosLoaded] Successfully loaded ${videos.length} videos in batch`);
27252
+ }
27253
+ } catch (error2) {
27254
+ console.error("[ensureVideosLoaded] Batch fetch failed:", error2);
27255
+ const loadPromises = indicesToLoad.map(async (index) => {
27256
+ try {
27257
+ const video = await s3ClipsService.getClipByIndex(
27004
27258
  workspaceId,
27005
27259
  operationalDate,
27006
27260
  shiftStr,
27007
27261
  effectiveFilter,
27008
27262
  index,
27009
27263
  true,
27010
- // includeCycleTime - OK for preloading
27264
+ // includeCycleTime
27011
27265
  false
27012
- // includeMetadata - NO metadata during bulk preloading to prevent flooding
27266
+ // includeMetadata
27013
27267
  );
27268
+ if (video && isMountedRef.current) {
27269
+ setAllVideos((prev) => {
27270
+ const exists = prev.some((v) => v.id === video.id);
27271
+ if (!exists) {
27272
+ return [...prev, video];
27273
+ }
27274
+ return prev;
27275
+ });
27276
+ loadedIndices.add(index);
27277
+ preloadVideoUrl(video.src);
27278
+ }
27279
+ } catch (err) {
27280
+ console.warn(`[ensureVideosLoaded] Failed to load video at index ${index}:`, err);
27014
27281
  }
27015
- if (video && isMountedRef.current) {
27016
- setAllVideos((prev) => {
27017
- const exists = prev.some((v) => v.id === video.id);
27018
- if (!exists) {
27019
- return [...prev, video];
27020
- }
27021
- return prev;
27022
- });
27023
- loadedIndices.add(index);
27024
- preloadVideoUrl(video.src);
27025
- }
27026
- } catch (error2) {
27027
- console.warn(`[ensureVideosLoaded] Failed to load video at index ${index}:`, error2);
27028
- } finally {
27029
- loadingVideosRef.current.delete(index);
27030
- }
27031
- });
27032
- Promise.all(loadPromises).catch((err) => {
27033
- console.warn("[ensureVideosLoaded] Some videos failed to preload:", err);
27034
- });
27282
+ });
27283
+ await Promise.all(loadPromises);
27284
+ } finally {
27285
+ indicesToLoad.forEach((idx) => loadingVideosRef.current.delete(idx));
27286
+ }
27035
27287
  }, [s3ClipsService, workspaceId, clipCounts, sopCategories, date, effectiveShift]);
27036
27288
  const loadFirstVideoForCategory = useCallback(async (category) => {
27037
27289
  if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
@@ -27994,7 +28246,7 @@ var WorkspaceGridItem = React19__default.memo(({
27994
28246
  isVeryLowEfficiency && !isInactive && /* @__PURE__ */ jsx("div", { className: "absolute -top-10 left-1/2 -translate-x-1/2 z-30", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
27995
28247
  /* @__PURE__ */ jsx("div", { className: "absolute -inset-1 bg-red-400/50 rounded-full blur-sm animate-pulse" }),
27996
28248
  /* @__PURE__ */ jsx("div", { className: "absolute -inset-0.5 bg-red-500/30 rounded-full blur-md animate-ping [animation-duration:1.5s]" }),
27997
- /* @__PURE__ */ jsx("div", { className: "bg-[#E34329] w-9 h-9 rounded-full flex items-center justify-center text-white font-bold text-lg shadow-lg ring-2 ring-red-400/40 border border-red-400/80 animate-pulse", children: "!" })
28249
+ /* @__PURE__ */ jsx("div", { className: "bg-[#E34329] w-8 h-8 sm:w-9 sm:h-9 rounded-full flex items-center justify-center text-white font-bold text-base sm:text-lg shadow-lg ring-2 ring-red-400/40 border border-red-400/80 animate-pulse", children: "!" })
27998
28250
  ] }) }),
27999
28251
  /* @__PURE__ */ jsx(
28000
28252
  "button",
@@ -28003,14 +28255,14 @@ var WorkspaceGridItem = React19__default.memo(({
28003
28255
  className: `${styles2} ${colorClass} ${isBottleneck ? "ring-2 ring-red-500/70" : ""} ${isVeryLowEfficiency ? "ring-2 ring-red-500/50" : ""} ${isInactive ? "bg-gray-200" : ""} shadow-lg`,
28004
28256
  "aria-label": isInactive ? `Inactive workspace ${workspaceNumber}` : `View details for workspace ${workspaceNumber}`,
28005
28257
  title: isInactive ? `Inactive: ${getWorkspaceDisplayName(data.workspace_name, data.line_id)}` : getWorkspaceDisplayName(data.workspace_name, data.line_id),
28006
- children: /* @__PURE__ */ jsx("div", { className: `font-semibold tracking-wide text-[min(4vw,2rem)] uppercase ${isInactive ? "text-gray-400" : "text-white"} drop-shadow-sm`, children: workspaceNumber })
28258
+ children: /* @__PURE__ */ jsx("div", { className: `font-semibold tracking-wide text-lg sm:text-xl md:text-[min(4vw,2rem)] uppercase ${isInactive ? "text-gray-400" : "text-white"} drop-shadow-sm`, children: workspaceNumber })
28007
28259
  }
28008
28260
  ),
28009
28261
  arrow && !isInactive && /* @__PURE__ */ jsx(
28010
28262
  "div",
28011
28263
  {
28012
28264
  className: `absolute left-1/2 -translate-x-1/2 ${arrowPosition}
28013
- text-[min(3.5vw,2.25rem)] font-bold tracking-tight ${arrowColor} drop-shadow-sm`,
28265
+ text-base sm:text-lg md:text-[min(3.5vw,2.25rem)] font-bold tracking-tight ${arrowColor} drop-shadow-sm`,
28014
28266
  style: { bottom: "-2.5rem", lineHeight: 1, display: "flex", alignItems: "center", justifyContent: "center" },
28015
28267
  children: arrow
28016
28268
  }
@@ -28040,11 +28292,11 @@ var WorkspaceGrid = React19__default.memo(({
28040
28292
  }, [workspaces.length]);
28041
28293
  const { VideoGridView: VideoGridViewComponent } = useRegistry();
28042
28294
  return /* @__PURE__ */ jsxs("div", { className: `relative w-full h-full overflow-hidden ${className}`, children: [
28043
- /* @__PURE__ */ jsxs("div", { className: "absolute top-0 left-2 sm:left-4 right-2 sm:right-8 z-20", children: [
28044
- /* @__PURE__ */ jsx("div", { className: "flex flex-row items-center justify-between py-1 sm:py-1.5 gap-2", children: /* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsx(Legend6, {}) }) }),
28045
- /* @__PURE__ */ jsx("div", { className: "sm:hidden mt-1", children: /* @__PURE__ */ jsx(Legend6, {}) })
28295
+ /* @__PURE__ */ jsxs("div", { className: "absolute top-0 left-4 sm:left-4 right-4 sm:right-8 z-20", children: [
28296
+ /* @__PURE__ */ jsx("div", { className: "flex flex-row items-center justify-between py-2 sm:py-1.5 gap-2", children: /* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsx(Legend6, {}) }) }),
28297
+ /* @__PURE__ */ jsx("div", { className: "sm:hidden mt-2", children: /* @__PURE__ */ jsx(Legend6, {}) })
28046
28298
  ] }),
28047
- /* @__PURE__ */ jsx("div", { className: "absolute top-10 sm:top-16 left-0 right-0 bottom-0", children: /* @__PURE__ */ jsx(
28299
+ /* @__PURE__ */ jsx("div", { className: "absolute top-12 sm:top-16 left-0 right-0 bottom-0", children: /* @__PURE__ */ jsx(
28048
28300
  VideoGridViewComponent,
28049
28301
  {
28050
28302
  workspaces,
@@ -28259,8 +28511,8 @@ var KPICard = ({
28259
28511
  const cardClasses = clsx(
28260
28512
  // Base classes
28261
28513
  "rounded-lg transition-all duration-200",
28262
- // Sizing based on compact mode - extra compact on mobile
28263
- "p-1.5 sm:p-3 md:p-4",
28514
+ // Sizing based on compact mode - better padding on mobile
28515
+ "p-2.5 sm:p-3 md:p-4",
28264
28516
  // Variant-specific styling
28265
28517
  {
28266
28518
  "bg-white/50 backdrop-blur-sm border border-gray-200/60 shadow-sm hover:shadow-md dark:bg-gray-800/50 dark:border-gray-700/60": style.variant === "default",
@@ -28268,8 +28520,8 @@ var KPICard = ({
28268
28520
  "bg-blue-50 border border-blue-200 dark:bg-blue-900/20 dark:border-blue-800/30": style.variant === "filled",
28269
28521
  "bg-gray-50/50 dark:bg-gray-800/30": style.variant === "subtle"
28270
28522
  },
28271
- // Width for src matching - compact on mobile, flexible on small screens
28272
- !className?.includes("w-") && "w-[120px] sm:w-[180px] md:w-[220px]",
28523
+ // Width for src matching - better mobile width, flexible on small screens
28524
+ !className?.includes("w-") && "w-[110px] sm:w-[180px] md:w-[220px]",
28273
28525
  // Interactive styling if onClick is provided
28274
28526
  onClick && "cursor-pointer hover:scale-[1.01] active:scale-[0.99]",
28275
28527
  // Loading state
@@ -28288,14 +28540,14 @@ var KPICard = ({
28288
28540
  children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
28289
28541
  /* @__PURE__ */ jsx("span", { className: clsx(
28290
28542
  "font-medium text-gray-500 dark:text-gray-400",
28291
- "text-[9px] sm:text-xs md:text-sm",
28292
- "mb-0.5 sm:mb-1 md:mb-2",
28293
- "uppercase tracking-wider"
28543
+ "text-[10px] sm:text-xs md:text-sm",
28544
+ "mb-1 sm:mb-1 md:mb-2",
28545
+ "uppercase tracking-wide sm:tracking-wider"
28294
28546
  ), children: title }),
28295
28547
  /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-0.5 sm:gap-2 flex-wrap", children: [
28296
28548
  /* @__PURE__ */ jsx("span", { className: clsx(
28297
28549
  "font-bold text-gray-900 dark:text-gray-50",
28298
- "text-sm sm:text-xl md:text-2xl"
28550
+ "text-base sm:text-xl md:text-2xl"
28299
28551
  ), children: isLoading ? "\u2014" : formattedValue }),
28300
28552
  suffix && !isLoading && /* @__PURE__ */ jsx("span", { className: clsx(
28301
28553
  "font-medium text-gray-600 dark:text-gray-300",
@@ -28470,35 +28722,46 @@ var KPISection = memo(({
28470
28722
  const outputDifference = kpis.outputProgress.current - kpis.outputProgress.idealOutput;
28471
28723
  const outputIsOnTarget = outputDifference >= 0;
28472
28724
  if (useSrcLayout) {
28473
- return /* @__PURE__ */ jsxs("div", { className: `flex gap-1 sm:gap-3 overflow-x-auto sm:overflow-visible pb-1 sm:pb-0 ${className || ""}`, children: [
28474
- /* @__PURE__ */ jsx(
28475
- KPICard,
28476
- {
28477
- title: "Underperforming",
28478
- value: "2/3",
28479
- change: 0
28480
- }
28481
- ),
28482
- /* @__PURE__ */ jsx(
28483
- KPICard,
28484
- {
28485
- title: "Efficiency",
28486
- value: kpis.efficiency.value,
28487
- change: kpis.efficiency.change,
28488
- suffix: "%"
28489
- }
28490
- ),
28491
- /* @__PURE__ */ jsx(
28492
- KPICard,
28493
- {
28494
- title: "Output Progress",
28495
- value: `${kpis.outputProgress.current}/${kpis.outputProgress.target}`,
28496
- change: kpis.outputProgress.change,
28497
- outputDifference,
28498
- showOutputDetails: true
28499
- }
28500
- )
28501
- ] });
28725
+ return /* @__PURE__ */ jsxs(
28726
+ "div",
28727
+ {
28728
+ className: `flex gap-2 sm:gap-3 overflow-x-auto sm:overflow-visible pb-2 sm:pb-0 ${className || ""}`,
28729
+ style: {
28730
+ scrollbarWidth: "none",
28731
+ msOverflowStyle: "none",
28732
+ WebkitScrollbar: { display: "none" }
28733
+ },
28734
+ children: [
28735
+ /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx(
28736
+ KPICard,
28737
+ {
28738
+ title: "Underperforming",
28739
+ value: "2/3",
28740
+ change: 0
28741
+ }
28742
+ ) }),
28743
+ /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx(
28744
+ KPICard,
28745
+ {
28746
+ title: "Efficiency",
28747
+ value: kpis.efficiency.value,
28748
+ change: kpis.efficiency.change,
28749
+ suffix: "%"
28750
+ }
28751
+ ) }),
28752
+ /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx(
28753
+ KPICard,
28754
+ {
28755
+ title: "Output Progress",
28756
+ value: `${kpis.outputProgress.current}/${kpis.outputProgress.target}`,
28757
+ change: kpis.outputProgress.change,
28758
+ outputDifference,
28759
+ showOutputDetails: true
28760
+ }
28761
+ ) })
28762
+ ]
28763
+ }
28764
+ );
28502
28765
  }
28503
28766
  const kpiCardData = [
28504
28767
  {
@@ -28631,6 +28894,19 @@ var WorkspaceHealthCard = ({
28631
28894
  const formatTimeAgo = (timeString) => {
28632
28895
  return timeString.replace("about ", "").replace(" ago", "");
28633
28896
  };
28897
+ const formatDowntime = (uptimeDetails) => {
28898
+ if (!uptimeDetails) return "";
28899
+ const downtimeMinutes = Math.max(0, uptimeDetails.expectedMinutes - uptimeDetails.actualMinutes);
28900
+ if (downtimeMinutes === 0) return "No downtime";
28901
+ if (downtimeMinutes < 1) return "< 1 min downtime";
28902
+ if (downtimeMinutes < 60) return `${downtimeMinutes} min downtime`;
28903
+ const hours = Math.floor(downtimeMinutes / 60);
28904
+ const minutes = downtimeMinutes % 60;
28905
+ if (minutes === 0) {
28906
+ return `${hours} hr downtime`;
28907
+ }
28908
+ return `${hours} hr ${minutes} min downtime`;
28909
+ };
28634
28910
  return /* @__PURE__ */ jsx(
28635
28911
  Card2,
28636
28912
  {
@@ -28664,13 +28940,32 @@ var WorkspaceHealthCard = ({
28664
28940
  /* @__PURE__ */ jsx("span", { children: config.statusText })
28665
28941
  ] })
28666
28942
  ] }),
28667
- /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
28668
- /* @__PURE__ */ jsx(Clock, { className: "h-3.5 w-3.5 text-gray-400" }),
28669
- /* @__PURE__ */ jsxs("span", { className: "text-sm text-gray-600 dark:text-gray-400 whitespace-nowrap", children: [
28670
- "Last seen: ",
28671
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: formatTimeAgo(workspace.timeSinceLastUpdate) })
28672
- ] })
28673
- ] }) }) })
28943
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
28944
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
28945
+ /* @__PURE__ */ jsx(Clock, { className: "h-3.5 w-3.5 text-gray-400" }),
28946
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-gray-600 dark:text-gray-400 whitespace-nowrap", children: [
28947
+ "Last seen: ",
28948
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: formatTimeAgo(workspace.timeSinceLastUpdate) })
28949
+ ] })
28950
+ ] }),
28951
+ workspace.uptimePercentage !== void 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
28952
+ /* @__PURE__ */ jsx(Activity, { className: "h-3.5 w-3.5 text-gray-400" }),
28953
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-gray-600 dark:text-gray-400 whitespace-nowrap", children: [
28954
+ "Uptime today: ",
28955
+ /* @__PURE__ */ jsxs("span", { className: clsx(
28956
+ "font-medium",
28957
+ workspace.uptimePercentage >= 97 ? "text-green-600 dark:text-green-400" : workspace.uptimePercentage >= 90 ? "text-yellow-600 dark:text-yellow-400" : "text-red-600 dark:text-red-400"
28958
+ ), children: [
28959
+ workspace.uptimePercentage.toFixed(1),
28960
+ "%"
28961
+ ] })
28962
+ ] })
28963
+ ] }),
28964
+ workspace.uptimeDetails && workspace.uptimeDetails.expectedMinutes > workspace.uptimeDetails.actualMinutes && workspace.uptimePercentage !== void 0 && /* @__PURE__ */ jsx("div", { className: "flex", children: /* @__PURE__ */ jsx("span", { className: clsx(
28965
+ "inline-flex items-center px-2 py-0.5 rounded text-xs font-medium",
28966
+ workspace.uptimePercentage >= 97 ? "bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400" : workspace.uptimePercentage >= 90 ? "bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400" : "bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400"
28967
+ ), children: formatDowntime(workspace.uptimeDetails) }) })
28968
+ ] })
28674
28969
  ] })
28675
28970
  }
28676
28971
  );
@@ -28741,6 +29036,20 @@ var CompactWorkspaceHealthCard = ({
28741
29036
  ] })
28742
29037
  ] }),
28743
29038
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
29039
+ workspace.uptimePercentage !== void 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
29040
+ /* @__PURE__ */ jsxs("p", { className: clsx(
29041
+ "text-xs font-medium",
29042
+ workspace.uptimePercentage >= 97 ? "text-green-600 dark:text-green-400" : workspace.uptimePercentage >= 90 ? "text-yellow-600 dark:text-yellow-400" : "text-red-600 dark:text-red-400"
29043
+ ), children: [
29044
+ workspace.uptimePercentage.toFixed(1),
29045
+ "%"
29046
+ ] }),
29047
+ workspace.uptimeDetails && workspace.uptimeDetails.expectedMinutes > workspace.uptimeDetails.actualMinutes && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 dark:text-gray-400", children: "\u2022" }),
29048
+ workspace.uptimeDetails && workspace.uptimeDetails.expectedMinutes > workspace.uptimeDetails.actualMinutes && /* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: [
29049
+ Math.max(0, workspace.uptimeDetails.expectedMinutes - workspace.uptimeDetails.actualMinutes),
29050
+ "m down"
29051
+ ] })
29052
+ ] }),
28744
29053
  /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: workspace.timeSinceLastUpdate }),
28745
29054
  /* @__PURE__ */ jsx("div", { className: clsx("h-2 w-2 rounded-full", config.dot) })
28746
29055
  ] })
@@ -28964,18 +29273,18 @@ var DashboardHeader = memo(({ lineTitle, className = "", headerControls }) => {
28964
29273
  };
28965
29274
  return /* @__PURE__ */ jsxs("div", { className: `flex flex-row items-center justify-between w-full ${className}`, children: [
28966
29275
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
28967
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 sm:gap-2 md:gap-3", children: [
28968
- /* @__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 }),
28969
- /* @__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" })
29276
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 sm:gap-2 md:gap-3", children: [
29277
+ /* @__PURE__ */ jsx("h1", { className: "text-lg sm:text-xl md:text-2xl lg:text-3xl font-bold text-gray-800 tracking-tight leading-none", children: lineTitle }),
29278
+ /* @__PURE__ */ jsx("div", { className: "h-1.5 w-1.5 sm:h-1.5 sm:w-1.5 md:h-2 md:w-2 rounded-full bg-green-500 animate-pulse ring-2 sm:ring-2 ring-green-500/30 ring-offset-1" })
28970
29279
  ] }),
28971
- /* @__PURE__ */ jsxs("div", { className: "mt-2 inline-flex items-center gap-3", children: [
28972
- /* @__PURE__ */ jsxs("div", { className: "text-sm font-medium text-gray-600", children: [
29280
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 inline-flex items-center gap-2 sm:gap-3", children: [
29281
+ /* @__PURE__ */ jsxs("div", { className: "text-xs sm:text-sm font-medium text-gray-600", children: [
28973
29282
  /* @__PURE__ */ jsx(ISTTimer2, {}),
28974
29283
  " IST"
28975
29284
  ] }),
28976
29285
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1", children: [
28977
29286
  /* @__PURE__ */ jsx("div", { className: "text-gray-600", children: getShiftIcon() }),
28978
- /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
29287
+ /* @__PURE__ */ jsxs("span", { className: "text-xs sm:text-sm font-medium text-gray-600", children: [
28979
29288
  getShiftName(),
28980
29289
  " Shift"
28981
29290
  ] })
@@ -28986,9 +29295,9 @@ var DashboardHeader = memo(({ lineTitle, className = "", headerControls }) => {
28986
29295
  ] });
28987
29296
  });
28988
29297
  DashboardHeader.displayName = "DashboardHeader";
28989
- 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: [
28990
- /* @__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" }) }),
28991
- /* @__PURE__ */ jsx("span", { children: message })
29298
+ 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-5 sm:p-4 shadow-md", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3 sm:space-x-2 text-gray-500", children: [
29299
+ /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-6 w-6 sm:h-5 sm: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" }) }),
29300
+ /* @__PURE__ */ jsx("span", { className: "text-base sm:text-sm", children: message })
28992
29301
  ] }) }) }));
28993
29302
  NoWorkspaceData.displayName = "NoWorkspaceData";
28994
29303
  var WorkspaceMonthlyDataFetcher = ({
@@ -29113,10 +29422,10 @@ var HamburgerButton = ({
29113
29422
  "button",
29114
29423
  {
29115
29424
  type: "button",
29116
- className: `md:hidden p-2 rounded-md text-gray-500 hover:text-gray-600 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 ${className}`,
29425
+ className: `md:hidden p-2.5 rounded-lg text-gray-600 hover:text-gray-900 hover:bg-gray-100 active:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors ${className}`,
29117
29426
  onClick,
29118
29427
  "aria-label": ariaLabel,
29119
- children: /* @__PURE__ */ jsx(Bars3Icon, { className: "w-6 h-6" })
29428
+ children: /* @__PURE__ */ jsx(Bars3Icon, { className: "w-7 h-7" })
29120
29429
  }
29121
29430
  );
29122
29431
  };
@@ -29647,28 +29956,189 @@ var SideNavBar = memo(({
29647
29956
  }
29648
29957
  ) })
29649
29958
  ] });
29959
+ const MobileNavigationContent = () => {
29960
+ const isActive = (path) => {
29961
+ if (path === "/" && pathname === "/") return true;
29962
+ if (path !== "/" && pathname.startsWith(path)) return true;
29963
+ return false;
29964
+ };
29965
+ const getMobileButtonClass = (path) => {
29966
+ const active = isActive(path);
29967
+ return `w-full flex items-center gap-3 px-5 py-3.5 rounded-lg transition-colors active:scale-[0.98] ${active ? "bg-blue-50 text-blue-700" : "text-gray-700 hover:bg-gray-100 active:bg-gray-200"}`;
29968
+ };
29969
+ const getIconClass = (path) => {
29970
+ const active = isActive(path);
29971
+ return `w-7 h-7 ${active ? "text-blue-600" : "text-gray-600"}`;
29972
+ };
29973
+ const handleMobileNavClick = (handler) => {
29974
+ return () => {
29975
+ handler();
29976
+ onMobileMenuClose?.();
29977
+ };
29978
+ };
29979
+ return /* @__PURE__ */ jsxs("nav", { className: "px-5 py-6", children: [
29980
+ /* @__PURE__ */ jsxs(
29981
+ "button",
29982
+ {
29983
+ onClick: handleMobileNavClick(handleHomeClick),
29984
+ className: getMobileButtonClass("/"),
29985
+ "aria-label": "Home",
29986
+ children: [
29987
+ /* @__PURE__ */ jsx(HomeIcon, { className: getIconClass("/") }),
29988
+ /* @__PURE__ */ jsx("span", { className: "text-base font-medium", children: "Home" })
29989
+ ]
29990
+ }
29991
+ ),
29992
+ /* @__PURE__ */ jsxs("div", { className: "mt-6 space-y-2", children: [
29993
+ /* @__PURE__ */ jsxs(
29994
+ "button",
29995
+ {
29996
+ onClick: handleMobileNavClick(handleLeaderboardClick),
29997
+ className: getMobileButtonClass("/leaderboard"),
29998
+ "aria-label": "Leaderboard",
29999
+ children: [
30000
+ /* @__PURE__ */ jsx(TrophyIcon, { className: getIconClass("/leaderboard") }),
30001
+ /* @__PURE__ */ jsx("span", { className: "text-base font-medium", children: "Leaderboard" })
30002
+ ]
30003
+ }
30004
+ ),
30005
+ /* @__PURE__ */ jsxs(
30006
+ "button",
30007
+ {
30008
+ onClick: handleMobileNavClick(handleKPIsClick),
30009
+ className: getMobileButtonClass("/kpis"),
30010
+ "aria-label": "Lines",
30011
+ children: [
30012
+ /* @__PURE__ */ jsx(ChartBarIcon, { className: getIconClass("/kpis") }),
30013
+ /* @__PURE__ */ jsx("span", { className: "text-base font-medium", children: "Lines" })
30014
+ ]
30015
+ }
30016
+ ),
30017
+ /* @__PURE__ */ jsxs(
30018
+ "button",
30019
+ {
30020
+ onClick: handleMobileNavClick(handleTargetsClick),
30021
+ className: getMobileButtonClass("/targets"),
30022
+ "aria-label": "Targets",
30023
+ children: [
30024
+ /* @__PURE__ */ jsx(AdjustmentsHorizontalIcon, { className: getIconClass("/targets") }),
30025
+ /* @__PURE__ */ jsx("span", { className: "text-base font-medium", children: "Targets" })
30026
+ ]
30027
+ }
30028
+ ),
30029
+ /* @__PURE__ */ jsxs(
30030
+ "button",
30031
+ {
30032
+ onClick: handleMobileNavClick(handleShiftsClick),
30033
+ className: getMobileButtonClass("/shifts"),
30034
+ "aria-label": "Shift Management",
30035
+ children: [
30036
+ /* @__PURE__ */ jsx(ClockIcon, { className: getIconClass("/shifts") }),
30037
+ /* @__PURE__ */ jsx("span", { className: "text-base font-medium", children: "Shifts" })
30038
+ ]
30039
+ }
30040
+ ),
30041
+ skuEnabled && /* @__PURE__ */ jsxs(
30042
+ "button",
30043
+ {
30044
+ onClick: handleMobileNavClick(handleSKUsClick),
30045
+ className: getMobileButtonClass("/skus"),
30046
+ "aria-label": "SKU Management",
30047
+ children: [
30048
+ /* @__PURE__ */ jsx(CubeIcon, { className: getIconClass("/skus") }),
30049
+ /* @__PURE__ */ jsx("span", { className: "text-base font-medium", children: "SKUs" })
30050
+ ]
30051
+ }
30052
+ ),
30053
+ /* @__PURE__ */ jsxs(
30054
+ "button",
30055
+ {
30056
+ onClick: handleMobileNavClick(handleAIAgentClick),
30057
+ className: getMobileButtonClass("/ai-agent"),
30058
+ "aria-label": "AI Manufacturing Expert",
30059
+ children: [
30060
+ /* @__PURE__ */ jsx(SparklesIcon, { className: getIconClass("/ai-agent") }),
30061
+ /* @__PURE__ */ jsx("span", { className: "text-base font-medium", children: "Axel AI" })
30062
+ ]
30063
+ }
30064
+ ),
30065
+ /* @__PURE__ */ jsxs(
30066
+ "button",
30067
+ {
30068
+ onClick: handleMobileNavClick(handleHelpClick),
30069
+ className: getMobileButtonClass("/help"),
30070
+ "aria-label": "Help & Support",
30071
+ children: [
30072
+ /* @__PURE__ */ jsx(QuestionMarkCircleIcon, { className: getIconClass("/help") }),
30073
+ /* @__PURE__ */ jsx("span", { className: "text-base font-medium", children: "Help" })
30074
+ ]
30075
+ }
30076
+ ),
30077
+ /* @__PURE__ */ jsxs(
30078
+ "button",
30079
+ {
30080
+ onClick: handleMobileNavClick(handleHealthClick),
30081
+ className: getMobileButtonClass("/health"),
30082
+ "aria-label": "System Health",
30083
+ children: [
30084
+ /* @__PURE__ */ jsx(HeartIcon, { className: getIconClass("/health") }),
30085
+ /* @__PURE__ */ jsx("span", { className: "text-base font-medium", children: "System Health" })
30086
+ ]
30087
+ }
30088
+ )
30089
+ ] }),
30090
+ /* @__PURE__ */ jsx("div", { className: "mt-8 pt-6 border-t border-gray-200", children: /* @__PURE__ */ jsxs(
30091
+ "button",
30092
+ {
30093
+ onClick: handleMobileNavClick(handleProfileClick),
30094
+ className: getMobileButtonClass("/profile"),
30095
+ "aria-label": "Profile & Settings",
30096
+ children: [
30097
+ /* @__PURE__ */ jsx(UserCircleIcon, { className: getIconClass("/profile") }),
30098
+ /* @__PURE__ */ jsx("span", { className: "text-base font-medium", children: "Profile" })
30099
+ ]
30100
+ }
30101
+ ) })
30102
+ ] });
30103
+ };
29650
30104
  return /* @__PURE__ */ jsxs(Fragment, { children: [
29651
30105
  /* @__PURE__ */ jsx("aside", { className: `hidden md:flex w-20 h-screen bg-white shadow-lg border-r border-gray-100 flex-col items-center fixed ${className}`, children: /* @__PURE__ */ jsx(NavigationContent, {}) }),
29652
- isMobileMenuOpen && /* @__PURE__ */ jsxs(Fragment, { children: [
30106
+ /* @__PURE__ */ jsxs(Fragment, { children: [
29653
30107
  /* @__PURE__ */ jsx(
29654
30108
  "div",
29655
30109
  {
29656
- className: "md:hidden fixed inset-0 bg-black bg-opacity-50 z-40",
30110
+ className: `md:hidden fixed inset-0 bg-black/60 backdrop-blur-sm z-40 transition-opacity duration-300 ease-in-out ${isMobileMenuOpen ? "opacity-100 pointer-events-auto" : "opacity-0 pointer-events-none"}`,
29657
30111
  onClick: onMobileMenuClose,
29658
30112
  "aria-hidden": "true"
29659
30113
  }
29660
30114
  ),
29661
- /* @__PURE__ */ jsxs("aside", { className: "md:hidden fixed inset-y-0 left-0 w-20 bg-white shadow-lg border-r border-gray-100 flex flex-col items-center z-50", children: [
29662
- /* @__PURE__ */ jsx("div", { className: "absolute top-4 right-4", children: /* @__PURE__ */ jsx(
29663
- "button",
29664
- {
29665
- onClick: onMobileMenuClose,
29666
- className: "p-2 rounded-md text-gray-400 hover:text-gray-600 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500",
29667
- "aria-label": "Close menu",
29668
- children: /* @__PURE__ */ jsx(XMarkIcon, { className: "w-5 h-5" })
29669
- }
29670
- ) }),
29671
- /* @__PURE__ */ jsx(NavigationContent, {})
30115
+ /* @__PURE__ */ jsxs("aside", { className: `md:hidden fixed inset-y-0 left-0 w-72 xs:w-80 bg-white shadow-2xl flex flex-col z-50 transform transition-transform duration-300 ease-in-out ${isMobileMenuOpen ? "translate-x-0" : "-translate-x-full"}`, children: [
30116
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-5 py-4 border-b border-gray-200 bg-gradient-to-r from-blue-50 to-white", children: [
30117
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx(
30118
+ "img",
30119
+ {
30120
+ src: "/optifye-logo.png",
30121
+ alt: "Optifye",
30122
+ className: "w-11 h-11 object-contain",
30123
+ onError: (e) => {
30124
+ e.currentTarget.style.display = "none";
30125
+ if (e.currentTarget.parentElement) {
30126
+ e.currentTarget.parentElement.innerHTML = '<span class="text-blue-600 font-bold text-xl">Optifye</span>';
30127
+ }
30128
+ }
30129
+ }
30130
+ ) }),
30131
+ /* @__PURE__ */ jsx(
30132
+ "button",
30133
+ {
30134
+ onClick: onMobileMenuClose,
30135
+ className: "p-2.5 rounded-lg text-gray-600 hover:text-gray-900 hover:bg-gray-100 active:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all active:scale-95",
30136
+ "aria-label": "Close menu",
30137
+ children: /* @__PURE__ */ jsx(XMarkIcon, { className: "w-7 h-7" })
30138
+ }
30139
+ )
30140
+ ] }),
30141
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsx(MobileNavigationContent, {}) })
29672
30142
  ] })
29673
30143
  ] })
29674
30144
  ] });
@@ -29760,17 +30230,39 @@ var MainLayout = ({
29760
30230
  logo
29761
30231
  }) => {
29762
30232
  const router = useRouter();
30233
+ const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
30234
+ const handleMobileMenuOpen = () => setIsMobileMenuOpen(true);
30235
+ const handleMobileMenuClose = () => setIsMobileMenuOpen(false);
29763
30236
  return /* @__PURE__ */ jsxs("div", { className: `min-h-screen ${className}`, children: [
30237
+ /* @__PURE__ */ jsx("header", { className: "md:hidden bg-white border-b border-gray-200 shadow-sm px-5 py-3.5 flex items-center justify-between sticky top-0 z-40", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
30238
+ /* @__PURE__ */ jsx(HamburgerButton, { onClick: handleMobileMenuOpen }),
30239
+ /* @__PURE__ */ jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsx(
30240
+ "img",
30241
+ {
30242
+ src: "/optifye-logo.png",
30243
+ alt: "Optifye",
30244
+ className: "h-9 w-9 object-contain",
30245
+ onError: (e) => {
30246
+ e.currentTarget.style.display = "none";
30247
+ if (e.currentTarget.parentElement) {
30248
+ e.currentTarget.parentElement.innerHTML = '<span class="text-blue-600 font-bold text-lg">Optifye</span>';
30249
+ }
30250
+ }
30251
+ }
30252
+ ) })
30253
+ ] }) }),
29764
30254
  /* @__PURE__ */ jsx(
29765
30255
  SideNavBar,
29766
30256
  {
29767
30257
  navItems,
29768
30258
  currentPathname: router.pathname,
29769
30259
  currentQuery: router.query,
29770
- logo
30260
+ logo,
30261
+ isMobileMenuOpen,
30262
+ onMobileMenuClose: handleMobileMenuClose
29771
30263
  }
29772
30264
  ),
29773
- /* @__PURE__ */ jsx("main", { className: "ml-20 bg-gray-50 min-h-screen", children })
30265
+ /* @__PURE__ */ jsx("main", { className: "md:ml-20 bg-gray-50 min-h-screen transition-all duration-300", children: /* @__PURE__ */ jsx("div", { className: "h-full", children }) })
29774
30266
  ] });
29775
30267
  };
29776
30268
  var Header = ({
@@ -32780,7 +33272,7 @@ function HomeView({
32780
33272
  return null;
32781
33273
  }
32782
33274
  return /* @__PURE__ */ jsxs(Select, { onValueChange: handleLineChange, defaultValue: selectedLineId, children: [
32783
- /* @__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" }) }),
33275
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "w-full sm:w-[200px] bg-white border border-gray-200 shadow-sm rounded-md h-11 sm:h-9 text-sm", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select a line" }) }),
32784
33276
  /* @__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)) })
32785
33277
  ] });
32786
33278
  }, [availableLineIds, handleLineChange, selectedLineId, lineNames, factoryViewId, allLineIds.length]);
@@ -32792,7 +33284,7 @@ function HomeView({
32792
33284
  if (errorMessage || displayNamesError) {
32793
33285
  return /* @__PURE__ */ jsx("div", { className: "flex h-screen items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-white p-6 shadow-lg", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3 text-red-500", children: [
32794
33286
  /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
32795
- /* @__PURE__ */ jsxs("span", { className: "text-lg font-medium", children: [
33287
+ /* @__PURE__ */ jsxs("span", { className: "text-base sm:text-lg font-medium", children: [
32796
33288
  "Error: ",
32797
33289
  errorMessage || displayNamesError?.message
32798
33290
  ] })
@@ -32806,7 +33298,7 @@ function HomeView({
32806
33298
  animate: { opacity: 1 },
32807
33299
  children: /* @__PURE__ */ jsxs("div", { className: "relative flex flex-1", children: [
32808
33300
  /* @__PURE__ */ jsxs("main", { className: "flex flex-1 flex-col", children: [
32809
- /* @__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(
33301
+ /* @__PURE__ */ jsx("div", { className: "relative sm:sticky sm:top-0 z-30 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-4 sm:px-6 lg:px-8 py-3 sm:py-2.5", children: /* @__PURE__ */ jsx(
32810
33302
  DashboardHeader,
32811
33303
  {
32812
33304
  lineTitle,
@@ -32815,8 +33307,8 @@ function HomeView({
32815
33307
  }
32816
33308
  ) }) }),
32817
33309
  /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto sm:overflow-hidden relative", children: [
32818
- lineSelectorComponent && /* @__PURE__ */ jsx("div", { className: "absolute right-3 top-2 sm:right-6 sm:top-3 z-30", children: lineSelectorComponent }),
32819
- /* @__PURE__ */ jsx("div", { className: "h-full sm:h-full min-h-[calc(100vh-80px)] sm:min-h-0", children: memoizedWorkspaceMetrics.length > 0 ? /* @__PURE__ */ jsx(
33310
+ lineSelectorComponent && /* @__PURE__ */ jsx("div", { className: "absolute right-4 top-3 sm:right-6 sm:top-3 z-30", children: lineSelectorComponent }),
33311
+ /* @__PURE__ */ jsx("div", { className: "h-full sm:h-full min-h-[calc(100vh-120px)] sm:min-h-0", children: memoizedWorkspaceMetrics.length > 0 ? /* @__PURE__ */ jsx(
32820
33312
  motion.div,
32821
33313
  {
32822
33314
  initial: { opacity: 0, scale: 0.98 },
@@ -38326,8 +38818,8 @@ var WorkspaceHealthView = ({
38326
38818
  }
38327
38819
  };
38328
38820
  const getUptimeColor = (percentage) => {
38329
- if (percentage >= 99) return "text-green-600 dark:text-green-400";
38330
- if (percentage >= 95) return "text-yellow-600 dark:text-yellow-400";
38821
+ if (percentage >= 97) return "text-green-600 dark:text-green-400";
38822
+ if (percentage >= 90) return "text-yellow-600 dark:text-yellow-400";
38331
38823
  return "text-red-600 dark:text-red-400";
38332
38824
  };
38333
38825
  if (loading && !summary) {
@@ -38415,20 +38907,21 @@ var WorkspaceHealthView = ({
38415
38907
  className: "grid grid-cols-2 sm:grid-cols-2 md:grid-cols-5 gap-2 sm:gap-3 lg:gap-4",
38416
38908
  children: [
38417
38909
  /* @__PURE__ */ jsxs(Card2, { className: "col-span-2 sm:col-span-2 md:col-span-2 bg-white", children: [
38418
- /* @__PURE__ */ jsx(CardHeader2, { className: "pb-3", children: /* @__PURE__ */ jsx(CardTitle2, { className: "text-sm font-medium text-gray-500 dark:text-gray-400", children: "Overall System Status" }) }),
38910
+ /* @__PURE__ */ jsx(CardHeader2, { className: "pb-3", children: /* @__PURE__ */ jsx(CardTitle2, { className: "text-sm font-medium text-gray-500 dark:text-gray-400", children: "Overall System Uptime Today" }) }),
38419
38911
  /* @__PURE__ */ jsxs(CardContent2, { children: [
38420
38912
  /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2", children: [
38421
38913
  /* @__PURE__ */ jsxs("span", { className: clsx("text-3xl font-bold", getUptimeColor(summary.uptimePercentage)), children: [
38422
38914
  summary.uptimePercentage.toFixed(1),
38423
38915
  "%"
38424
38916
  ] }),
38425
- summary.uptimePercentage >= 99 ? /* @__PURE__ */ jsx(TrendingUp, { className: "h-5 w-5 text-green-500" }) : /* @__PURE__ */ jsx(TrendingDown, { className: "h-5 w-5 text-red-500" })
38917
+ summary.uptimePercentage >= 97 ? /* @__PURE__ */ jsx(TrendingUp, { className: "h-5 w-5 text-green-500" }) : summary.uptimePercentage >= 90 ? /* @__PURE__ */ jsx(Activity, { className: "h-5 w-5 text-yellow-500" }) : /* @__PURE__ */ jsx(TrendingDown, { className: "h-5 w-5 text-red-500" })
38426
38918
  ] }),
38427
- /* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: [
38919
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: "Average uptime across all workspaces" }),
38920
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: [
38428
38921
  summary.healthyWorkspaces,
38429
38922
  " of ",
38430
38923
  summary.totalWorkspaces,
38431
- " workspaces healthy"
38924
+ " workspaces online"
38432
38925
  ] })
38433
38926
  ] })
38434
38927
  ] }),