@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.css +73 -23
- package/dist/index.d.mts +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +625 -132
- package/dist/index.mjs +626 -133
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1905,7 +1905,29 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
1905
1905
|
throw error;
|
|
1906
1906
|
}
|
|
1907
1907
|
const processedData = (data || []).map((item) => this.processHealthStatus(item));
|
|
1908
|
-
let
|
|
1908
|
+
let uptimeMap = /* @__PURE__ */ new Map();
|
|
1909
|
+
if (options.companyId || data && data.length > 0) {
|
|
1910
|
+
const companyId = options.companyId || data[0]?.company_id;
|
|
1911
|
+
if (companyId) {
|
|
1912
|
+
try {
|
|
1913
|
+
uptimeMap = await this.calculateWorkspaceUptime(companyId);
|
|
1914
|
+
} catch (error2) {
|
|
1915
|
+
console.error("Error calculating uptime:", error2);
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
const dataWithUptime = processedData.map((workspace) => {
|
|
1920
|
+
const uptimeDetails = uptimeMap.get(workspace.workspace_id);
|
|
1921
|
+
if (uptimeDetails) {
|
|
1922
|
+
return {
|
|
1923
|
+
...workspace,
|
|
1924
|
+
uptimePercentage: uptimeDetails.percentage,
|
|
1925
|
+
uptimeDetails
|
|
1926
|
+
};
|
|
1927
|
+
}
|
|
1928
|
+
return workspace;
|
|
1929
|
+
});
|
|
1930
|
+
let filteredData = dataWithUptime;
|
|
1909
1931
|
try {
|
|
1910
1932
|
const { data: enabledWorkspaces, error: workspaceError } = await supabase.from("workspaces").select("workspace_id, display_name").eq("enable", true);
|
|
1911
1933
|
if (!workspaceError && enabledWorkspaces && enabledWorkspaces.length > 0) {
|
|
@@ -1981,13 +2003,31 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
1981
2003
|
const healthyWorkspaces = workspaces.filter((w) => w.status === "healthy").length;
|
|
1982
2004
|
const unhealthyWorkspaces = workspaces.filter((w) => w.status === "unhealthy").length;
|
|
1983
2005
|
const warningWorkspaces = workspaces.filter((w) => w.status === "warning").length;
|
|
1984
|
-
|
|
2006
|
+
let uptimePercentage = 0;
|
|
2007
|
+
let totalDowntimeMinutes = 0;
|
|
2008
|
+
if (totalWorkspaces > 0) {
|
|
2009
|
+
const workspacesWithUptime = workspaces.filter((w) => w.uptimePercentage !== void 0 && w.uptimeDetails !== void 0);
|
|
2010
|
+
if (workspacesWithUptime.length > 0) {
|
|
2011
|
+
const totalUptime = workspacesWithUptime.reduce((sum, w) => sum + (w.uptimePercentage || 0), 0);
|
|
2012
|
+
uptimePercentage = totalUptime / workspacesWithUptime.length;
|
|
2013
|
+
totalDowntimeMinutes = workspacesWithUptime.reduce((sum, w) => {
|
|
2014
|
+
if (w.uptimeDetails) {
|
|
2015
|
+
const downtime = Math.max(0, w.uptimeDetails.expectedMinutes - w.uptimeDetails.actualMinutes);
|
|
2016
|
+
return sum + downtime;
|
|
2017
|
+
}
|
|
2018
|
+
return sum;
|
|
2019
|
+
}, 0);
|
|
2020
|
+
} else {
|
|
2021
|
+
uptimePercentage = healthyWorkspaces / totalWorkspaces * 100;
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
1985
2024
|
return {
|
|
1986
2025
|
totalWorkspaces,
|
|
1987
2026
|
healthyWorkspaces,
|
|
1988
2027
|
unhealthyWorkspaces,
|
|
1989
2028
|
warningWorkspaces,
|
|
1990
2029
|
uptimePercentage,
|
|
2030
|
+
totalDowntimeMinutes,
|
|
1991
2031
|
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
1992
2032
|
};
|
|
1993
2033
|
}
|
|
@@ -2067,6 +2107,155 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2067
2107
|
clearCache() {
|
|
2068
2108
|
this.cache.clear();
|
|
2069
2109
|
}
|
|
2110
|
+
async calculateWorkspaceUptime(companyId) {
|
|
2111
|
+
const supabase = _getSupabaseInstance();
|
|
2112
|
+
if (!supabase) throw new Error("Supabase client not initialized");
|
|
2113
|
+
const dashboardConfig = _getDashboardConfigInstance();
|
|
2114
|
+
const timezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
|
|
2115
|
+
const shiftConfig = dashboardConfig?.shiftConfig;
|
|
2116
|
+
const currentShiftInfo = getCurrentShift(timezone, shiftConfig);
|
|
2117
|
+
const currentDate = currentShiftInfo.date;
|
|
2118
|
+
const currentShiftId = currentShiftInfo.shiftId;
|
|
2119
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
2120
|
+
const currentHour = now2.getHours();
|
|
2121
|
+
const currentMinute = now2.getMinutes();
|
|
2122
|
+
let shiftStartHour;
|
|
2123
|
+
let shiftEndHour;
|
|
2124
|
+
if (currentShiftId === 0) {
|
|
2125
|
+
shiftStartHour = 9;
|
|
2126
|
+
shiftEndHour = 18;
|
|
2127
|
+
} else {
|
|
2128
|
+
shiftStartHour = 20;
|
|
2129
|
+
shiftEndHour = 3;
|
|
2130
|
+
}
|
|
2131
|
+
let elapsedMinutes = 0;
|
|
2132
|
+
if (currentShiftId === 0) {
|
|
2133
|
+
if (currentHour >= shiftStartHour && currentHour < shiftEndHour) {
|
|
2134
|
+
elapsedMinutes = (currentHour - shiftStartHour) * 60 + currentMinute;
|
|
2135
|
+
} else if (currentHour >= shiftEndHour) {
|
|
2136
|
+
elapsedMinutes = (shiftEndHour - shiftStartHour) * 60;
|
|
2137
|
+
}
|
|
2138
|
+
} else {
|
|
2139
|
+
if (currentHour >= shiftStartHour) {
|
|
2140
|
+
elapsedMinutes = (currentHour - shiftStartHour) * 60 + currentMinute;
|
|
2141
|
+
} else if (currentHour < shiftEndHour) {
|
|
2142
|
+
elapsedMinutes = (24 - shiftStartHour + currentHour) * 60 + currentMinute;
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
const tableName = `performance_metrics_${companyId.replace(/-/g, "_")}`;
|
|
2146
|
+
const query = `
|
|
2147
|
+
WITH workspace_uptime AS (
|
|
2148
|
+
SELECT
|
|
2149
|
+
workspace_id,
|
|
2150
|
+
workspace_display_name,
|
|
2151
|
+
idle_time_hourly,
|
|
2152
|
+
output_hourly,
|
|
2153
|
+
shift_start,
|
|
2154
|
+
shift_end
|
|
2155
|
+
FROM ${tableName}
|
|
2156
|
+
WHERE date = $1::date
|
|
2157
|
+
AND shift_id = $2
|
|
2158
|
+
),
|
|
2159
|
+
calculated_uptime AS (
|
|
2160
|
+
SELECT
|
|
2161
|
+
workspace_id,
|
|
2162
|
+
workspace_display_name,
|
|
2163
|
+
-- Calculate actual minutes from hourly data
|
|
2164
|
+
(
|
|
2165
|
+
SELECT COALESCE(SUM(
|
|
2166
|
+
CASE
|
|
2167
|
+
WHEN jsonb_array_length(idle_time_hourly->key::text) >= 58 THEN 60
|
|
2168
|
+
WHEN jsonb_array_length(idle_time_hourly->key::text) > 0 THEN jsonb_array_length(idle_time_hourly->key::text)
|
|
2169
|
+
ELSE 0
|
|
2170
|
+
END
|
|
2171
|
+
), 0)
|
|
2172
|
+
FROM jsonb_object_keys(idle_time_hourly) AS key
|
|
2173
|
+
WHERE key::int >= $3 AND key::int < $4
|
|
2174
|
+
) +
|
|
2175
|
+
-- Add current hour's data if applicable
|
|
2176
|
+
CASE
|
|
2177
|
+
WHEN $4::int >= $3 AND $4::int < $5 THEN
|
|
2178
|
+
LEAST($6::int,
|
|
2179
|
+
COALESCE(jsonb_array_length(idle_time_hourly->$4::text), 0))
|
|
2180
|
+
ELSE 0
|
|
2181
|
+
END as actual_minutes
|
|
2182
|
+
FROM workspace_uptime
|
|
2183
|
+
)
|
|
2184
|
+
SELECT
|
|
2185
|
+
workspace_id,
|
|
2186
|
+
workspace_display_name,
|
|
2187
|
+
actual_minutes,
|
|
2188
|
+
$7::int as expected_minutes,
|
|
2189
|
+
ROUND(
|
|
2190
|
+
CASE
|
|
2191
|
+
WHEN $7::int > 0 THEN (actual_minutes::numeric / $7::numeric) * 100
|
|
2192
|
+
ELSE 100
|
|
2193
|
+
END, 1
|
|
2194
|
+
) as uptime_percentage
|
|
2195
|
+
FROM calculated_uptime
|
|
2196
|
+
`;
|
|
2197
|
+
try {
|
|
2198
|
+
const { data, error } = await supabase.rpc("sql_query", {
|
|
2199
|
+
query_text: query,
|
|
2200
|
+
params: [
|
|
2201
|
+
currentDate,
|
|
2202
|
+
currentShiftId,
|
|
2203
|
+
shiftStartHour,
|
|
2204
|
+
currentHour,
|
|
2205
|
+
shiftEndHour,
|
|
2206
|
+
currentMinute,
|
|
2207
|
+
elapsedMinutes
|
|
2208
|
+
]
|
|
2209
|
+
}).single();
|
|
2210
|
+
if (error) {
|
|
2211
|
+
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);
|
|
2212
|
+
if (queryError) {
|
|
2213
|
+
console.error("Error fetching performance metrics:", queryError);
|
|
2214
|
+
return /* @__PURE__ */ new Map();
|
|
2215
|
+
}
|
|
2216
|
+
const uptimeMap2 = /* @__PURE__ */ new Map();
|
|
2217
|
+
for (const record of queryData || []) {
|
|
2218
|
+
let actualMinutes = 0;
|
|
2219
|
+
const idleTimeHourly = record.idle_time_hourly || {};
|
|
2220
|
+
if (idleTimeHourly && typeof idleTimeHourly === "object") {
|
|
2221
|
+
for (const [hour, dataArray] of Object.entries(idleTimeHourly)) {
|
|
2222
|
+
const hourNum = parseInt(hour);
|
|
2223
|
+
if (hourNum >= shiftStartHour && hourNum < currentHour) {
|
|
2224
|
+
const arrayLength = Array.isArray(dataArray) ? dataArray.length : 0;
|
|
2225
|
+
actualMinutes += arrayLength >= 58 ? 60 : arrayLength;
|
|
2226
|
+
} else if (hourNum === currentHour && currentHour >= shiftStartHour) {
|
|
2227
|
+
const arrayLength = Array.isArray(dataArray) ? dataArray.length : 0;
|
|
2228
|
+
actualMinutes += Math.min(currentMinute, arrayLength);
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
const percentage = elapsedMinutes > 0 ? Math.round(actualMinutes / elapsedMinutes * 1e3) / 10 : 100;
|
|
2233
|
+
uptimeMap2.set(record.workspace_id, {
|
|
2234
|
+
expectedMinutes: elapsedMinutes,
|
|
2235
|
+
actualMinutes,
|
|
2236
|
+
percentage,
|
|
2237
|
+
lastCalculated: (/* @__PURE__ */ new Date()).toISOString()
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
return uptimeMap2;
|
|
2241
|
+
}
|
|
2242
|
+
const uptimeMap = /* @__PURE__ */ new Map();
|
|
2243
|
+
if (Array.isArray(data)) {
|
|
2244
|
+
for (const record of data) {
|
|
2245
|
+
uptimeMap.set(record.workspace_id, {
|
|
2246
|
+
expectedMinutes: record.expected_minutes,
|
|
2247
|
+
actualMinutes: record.actual_minutes,
|
|
2248
|
+
percentage: record.uptime_percentage,
|
|
2249
|
+
lastCalculated: (/* @__PURE__ */ new Date()).toISOString()
|
|
2250
|
+
});
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
return uptimeMap;
|
|
2254
|
+
} catch (error) {
|
|
2255
|
+
console.error("Error calculating workspace uptime:", error);
|
|
2256
|
+
return /* @__PURE__ */ new Map();
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2070
2259
|
};
|
|
2071
2260
|
var workspaceHealthService = WorkspaceHealthService.getInstance();
|
|
2072
2261
|
|
|
@@ -4152,6 +4341,23 @@ var S3ClipsAPIClient = class {
|
|
|
4152
4341
|
};
|
|
4153
4342
|
});
|
|
4154
4343
|
}
|
|
4344
|
+
/**
|
|
4345
|
+
* Batch fetch multiple videos in parallel
|
|
4346
|
+
*/
|
|
4347
|
+
async batchFetchVideos(workspaceId, date, shiftId, requests) {
|
|
4348
|
+
const batchKey = `batch:${workspaceId}:${date}:${shiftId}:${requests.length}`;
|
|
4349
|
+
return this.deduplicate(batchKey, async () => {
|
|
4350
|
+
const response = await this.fetchWithAuth("/api/clips/batch", {
|
|
4351
|
+
workspaceId,
|
|
4352
|
+
date,
|
|
4353
|
+
shift: shiftId.toString(),
|
|
4354
|
+
requests,
|
|
4355
|
+
sopCategories: this.sopCategories
|
|
4356
|
+
});
|
|
4357
|
+
console.log(`[S3ClipsAPIClient] Batch fetched ${response.videos.length} videos in ${response.performance.duration}ms`);
|
|
4358
|
+
return response.videos;
|
|
4359
|
+
});
|
|
4360
|
+
}
|
|
4155
4361
|
/**
|
|
4156
4362
|
* Convert S3 URI to CloudFront URL
|
|
4157
4363
|
* In the API client, URLs are already signed from the server
|
|
@@ -4435,6 +4641,23 @@ var S3ClipsService = class {
|
|
|
4435
4641
|
);
|
|
4436
4642
|
return result.videos;
|
|
4437
4643
|
}
|
|
4644
|
+
/**
|
|
4645
|
+
* Batch fetch multiple videos in parallel
|
|
4646
|
+
*/
|
|
4647
|
+
async batchFetchVideos(workspaceId, date, shiftId, requests) {
|
|
4648
|
+
try {
|
|
4649
|
+
const results = await this.apiClient.batchFetchVideos(
|
|
4650
|
+
workspaceId,
|
|
4651
|
+
date,
|
|
4652
|
+
shiftId,
|
|
4653
|
+
requests
|
|
4654
|
+
);
|
|
4655
|
+
return results.map((r2) => r2.video).filter((v) => v !== null);
|
|
4656
|
+
} catch (error) {
|
|
4657
|
+
console.error("[S3ClipsService] Error batch fetching videos:", error);
|
|
4658
|
+
return [];
|
|
4659
|
+
}
|
|
4660
|
+
}
|
|
4438
4661
|
/**
|
|
4439
4662
|
* Get videos page using pagination API
|
|
4440
4663
|
*/
|
|
@@ -19691,7 +19914,7 @@ var OptifyeLogoLoader = ({
|
|
|
19691
19914
|
className: `${sizeClasses[size]} h-auto animate-pulse select-none pointer-events-none`
|
|
19692
19915
|
}
|
|
19693
19916
|
),
|
|
19694
|
-
message && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 text-gray-600 text-sm font-medium text-center", children: message })
|
|
19917
|
+
message && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 text-gray-600 text-base sm:text-sm font-medium text-center", children: message })
|
|
19695
19918
|
]
|
|
19696
19919
|
}
|
|
19697
19920
|
);
|
|
@@ -21602,8 +21825,8 @@ var VideoCard = React19__namespace.default.memo(({
|
|
|
21602
21825
|
] }) }),
|
|
21603
21826
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full h-full overflow-hidden bg-black", children: [
|
|
21604
21827
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black z-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse flex flex-col items-center", children: [
|
|
21605
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Camera, { className:
|
|
21606
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className:
|
|
21828
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Camera, { className: `w-5 h-5 sm:${compact ? "w-4 h-4" : "w-6 h-6"} text-gray-500` }),
|
|
21829
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-[11px] sm:${compact ? "text-[10px]" : "text-xs"} text-gray-500 mt-1`, children: "Loading..." })
|
|
21607
21830
|
] }) }),
|
|
21608
21831
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 z-10", children: [
|
|
21609
21832
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -21638,10 +21861,10 @@ var VideoCard = React19__namespace.default.memo(({
|
|
|
21638
21861
|
}
|
|
21639
21862
|
) })
|
|
21640
21863
|
] }),
|
|
21641
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `absolute bottom-0 left-0 right-0 bg-black bg-opacity-60
|
|
21864
|
+
/* @__PURE__ */ jsxRuntime.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: [
|
|
21642
21865
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
21643
21866
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Camera, { size: compact ? 10 : 12, className: "text-white" }),
|
|
21644
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-white
|
|
21867
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-white text-[11px] sm:${compact ? "text-[10px]" : "text-xs"} font-medium tracking-wide`, children: displayName })
|
|
21645
21868
|
] }),
|
|
21646
21869
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center ${compact ? "gap-1" : "gap-1.5"}`, children: [
|
|
21647
21870
|
trendInfo && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -21653,7 +21876,7 @@ var VideoCard = React19__namespace.default.memo(({
|
|
|
21653
21876
|
}
|
|
21654
21877
|
),
|
|
21655
21878
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `${compact ? "w-1 h-1" : "w-1.5 h-1.5"} rounded-full bg-green-500` }),
|
|
21656
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-white
|
|
21879
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-white text-[11px] sm:${compact ? "text-[10px]" : "text-xs"}`, children: "Live" })
|
|
21657
21880
|
] })
|
|
21658
21881
|
] })
|
|
21659
21882
|
]
|
|
@@ -21863,10 +22086,10 @@ var VideoGridView = React19__namespace.default.memo(({
|
|
|
21863
22086
|
view_type: "video_grid"
|
|
21864
22087
|
});
|
|
21865
22088
|
}, []);
|
|
21866
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `relative overflow-hidden h-full w-full ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "h-full w-full p-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
22089
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `relative overflow-hidden h-full w-full ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "h-full w-full p-3 sm:p-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
21867
22090
|
"div",
|
|
21868
22091
|
{
|
|
21869
|
-
className: "grid h-full w-full gap-2",
|
|
22092
|
+
className: "grid h-full w-full gap-3 sm:gap-2",
|
|
21870
22093
|
style: {
|
|
21871
22094
|
gridTemplateColumns: `repeat(${gridCols}, 1fr)`,
|
|
21872
22095
|
gridTemplateRows: `repeat(${gridRows}, 1fr)`,
|
|
@@ -22651,15 +22874,15 @@ var BreakNotificationPopup = ({
|
|
|
22651
22874
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2 h-2 bg-amber-500 rounded-full animate-pulse flex-shrink-0 mt-2" }),
|
|
22652
22875
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
22653
22876
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-1", children: [
|
|
22654
|
-
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "font-semibold text-sm text-gray-900", children: breakItem.remarks || "Break" }),
|
|
22655
|
-
(activeBreaks.length > 1 || lineNames[breakItem.lineId]) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500 mt-0.5", children: lineNames[breakItem.lineId] || `Line ${breakItem.lineId.substring(0, 8)}` })
|
|
22877
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "font-semibold text-base sm:text-sm text-gray-900", children: breakItem.remarks || "Break" }),
|
|
22878
|
+
(activeBreaks.length > 1 || lineNames[breakItem.lineId]) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm sm:text-xs text-gray-500 mt-0.5", children: lineNames[breakItem.lineId] || `Line ${breakItem.lineId.substring(0, 8)}` })
|
|
22656
22879
|
] }),
|
|
22657
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-gray-600 font-medium", children: [
|
|
22880
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm sm:text-xs text-gray-600 font-medium", children: [
|
|
22658
22881
|
breakItem.startTime,
|
|
22659
22882
|
" - ",
|
|
22660
22883
|
breakItem.endTime
|
|
22661
22884
|
] }) }),
|
|
22662
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-gray-500", children: [
|
|
22885
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm sm:text-xs text-gray-500", children: [
|
|
22663
22886
|
formatTime3(breakItem.elapsedMinutes),
|
|
22664
22887
|
" / ",
|
|
22665
22888
|
formatTime3(breakItem.duration)
|
|
@@ -23377,7 +23600,7 @@ var TimeDisplay = ({ className, variant = "default" }) => {
|
|
|
23377
23600
|
className: `flex items-center space-x-1.5 bg-white/60 backdrop-blur-sm px-2 py-0.5 rounded-md shadow-xs ${className || ""}`,
|
|
23378
23601
|
children: [
|
|
23379
23602
|
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.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" }) }),
|
|
23380
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[11px] font-medium text-gray-800 tabular-nums tracking-tight", children: [
|
|
23603
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs sm:text-[11px] font-medium text-gray-800 tabular-nums tracking-tight", children: [
|
|
23381
23604
|
time2,
|
|
23382
23605
|
" ",
|
|
23383
23606
|
timeSuffix
|
|
@@ -27024,44 +27247,73 @@ var BottlenecksContent = ({
|
|
|
27024
27247
|
if (indicesToLoad.length === 0) return;
|
|
27025
27248
|
console.log(`[ensureVideosLoaded] Preloading ${indicesToLoad.length} videos around index ${centerIndex}: [${indicesToLoad.join(", ")}]`);
|
|
27026
27249
|
indicesToLoad.forEach((idx) => loadingVideosRef.current.add(idx));
|
|
27027
|
-
const
|
|
27028
|
-
|
|
27029
|
-
|
|
27030
|
-
|
|
27031
|
-
|
|
27032
|
-
|
|
27033
|
-
|
|
27250
|
+
const operationalDate = date || getOperationalDate();
|
|
27251
|
+
const shiftStr = effectiveShift;
|
|
27252
|
+
console.log(`[ensureVideosLoaded] Batch fetching ${indicesToLoad.length} videos in parallel`);
|
|
27253
|
+
try {
|
|
27254
|
+
const batchRequests = indicesToLoad.map((index) => ({
|
|
27255
|
+
category: effectiveFilter,
|
|
27256
|
+
index,
|
|
27257
|
+
includeMetadata: false
|
|
27258
|
+
// No metadata during bulk preloading
|
|
27259
|
+
}));
|
|
27260
|
+
const videos = await s3ClipsService.batchFetchVideos(
|
|
27261
|
+
workspaceId,
|
|
27262
|
+
operationalDate,
|
|
27263
|
+
shiftStr,
|
|
27264
|
+
batchRequests
|
|
27265
|
+
);
|
|
27266
|
+
if (videos.length > 0 && isMountedRef.current) {
|
|
27267
|
+
videos.forEach((video, idx) => {
|
|
27268
|
+
if (video) {
|
|
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
|
+
const originalIndex = indicesToLoad[idx];
|
|
27277
|
+
loadedIndices.add(originalIndex);
|
|
27278
|
+
preloadVideoUrl(video.src);
|
|
27279
|
+
}
|
|
27280
|
+
});
|
|
27281
|
+
console.log(`[ensureVideosLoaded] Successfully loaded ${videos.length} videos in batch`);
|
|
27282
|
+
}
|
|
27283
|
+
} catch (error2) {
|
|
27284
|
+
console.error("[ensureVideosLoaded] Batch fetch failed:", error2);
|
|
27285
|
+
const loadPromises = indicesToLoad.map(async (index) => {
|
|
27286
|
+
try {
|
|
27287
|
+
const video = await s3ClipsService.getClipByIndex(
|
|
27034
27288
|
workspaceId,
|
|
27035
27289
|
operationalDate,
|
|
27036
27290
|
shiftStr,
|
|
27037
27291
|
effectiveFilter,
|
|
27038
27292
|
index,
|
|
27039
27293
|
true,
|
|
27040
|
-
// includeCycleTime
|
|
27294
|
+
// includeCycleTime
|
|
27041
27295
|
false
|
|
27042
|
-
// includeMetadata
|
|
27296
|
+
// includeMetadata
|
|
27043
27297
|
);
|
|
27298
|
+
if (video && isMountedRef.current) {
|
|
27299
|
+
setAllVideos((prev) => {
|
|
27300
|
+
const exists = prev.some((v) => v.id === video.id);
|
|
27301
|
+
if (!exists) {
|
|
27302
|
+
return [...prev, video];
|
|
27303
|
+
}
|
|
27304
|
+
return prev;
|
|
27305
|
+
});
|
|
27306
|
+
loadedIndices.add(index);
|
|
27307
|
+
preloadVideoUrl(video.src);
|
|
27308
|
+
}
|
|
27309
|
+
} catch (err) {
|
|
27310
|
+
console.warn(`[ensureVideosLoaded] Failed to load video at index ${index}:`, err);
|
|
27044
27311
|
}
|
|
27045
|
-
|
|
27046
|
-
|
|
27047
|
-
|
|
27048
|
-
|
|
27049
|
-
|
|
27050
|
-
}
|
|
27051
|
-
return prev;
|
|
27052
|
-
});
|
|
27053
|
-
loadedIndices.add(index);
|
|
27054
|
-
preloadVideoUrl(video.src);
|
|
27055
|
-
}
|
|
27056
|
-
} catch (error2) {
|
|
27057
|
-
console.warn(`[ensureVideosLoaded] Failed to load video at index ${index}:`, error2);
|
|
27058
|
-
} finally {
|
|
27059
|
-
loadingVideosRef.current.delete(index);
|
|
27060
|
-
}
|
|
27061
|
-
});
|
|
27062
|
-
Promise.all(loadPromises).catch((err) => {
|
|
27063
|
-
console.warn("[ensureVideosLoaded] Some videos failed to preload:", err);
|
|
27064
|
-
});
|
|
27312
|
+
});
|
|
27313
|
+
await Promise.all(loadPromises);
|
|
27314
|
+
} finally {
|
|
27315
|
+
indicesToLoad.forEach((idx) => loadingVideosRef.current.delete(idx));
|
|
27316
|
+
}
|
|
27065
27317
|
}, [s3ClipsService, workspaceId, clipCounts, sopCategories, date, effectiveShift]);
|
|
27066
27318
|
const loadFirstVideoForCategory = React19.useCallback(async (category) => {
|
|
27067
27319
|
if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
|
|
@@ -28024,7 +28276,7 @@ var WorkspaceGridItem = React19__namespace.default.memo(({
|
|
|
28024
28276
|
isVeryLowEfficiency && !isInactive && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-10 left-1/2 -translate-x-1/2 z-30", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
28025
28277
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -inset-1 bg-red-400/50 rounded-full blur-sm animate-pulse" }),
|
|
28026
28278
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -inset-0.5 bg-red-500/30 rounded-full blur-md animate-ping [animation-duration:1.5s]" }),
|
|
28027
|
-
/* @__PURE__ */ jsxRuntime.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: "!" })
|
|
28279
|
+
/* @__PURE__ */ jsxRuntime.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: "!" })
|
|
28028
28280
|
] }) }),
|
|
28029
28281
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
28030
28282
|
"button",
|
|
@@ -28033,14 +28285,14 @@ var WorkspaceGridItem = React19__namespace.default.memo(({
|
|
|
28033
28285
|
className: `${styles2} ${colorClass} ${isBottleneck ? "ring-2 ring-red-500/70" : ""} ${isVeryLowEfficiency ? "ring-2 ring-red-500/50" : ""} ${isInactive ? "bg-gray-200" : ""} shadow-lg`,
|
|
28034
28286
|
"aria-label": isInactive ? `Inactive workspace ${workspaceNumber}` : `View details for workspace ${workspaceNumber}`,
|
|
28035
28287
|
title: isInactive ? `Inactive: ${getWorkspaceDisplayName(data.workspace_name, data.line_id)}` : getWorkspaceDisplayName(data.workspace_name, data.line_id),
|
|
28036
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: `font-semibold tracking-wide text-[min(4vw,2rem)] uppercase ${isInactive ? "text-gray-400" : "text-white"} drop-shadow-sm`, children: workspaceNumber })
|
|
28288
|
+
children: /* @__PURE__ */ jsxRuntime.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 })
|
|
28037
28289
|
}
|
|
28038
28290
|
),
|
|
28039
28291
|
arrow && !isInactive && /* @__PURE__ */ jsxRuntime.jsx(
|
|
28040
28292
|
"div",
|
|
28041
28293
|
{
|
|
28042
28294
|
className: `absolute left-1/2 -translate-x-1/2 ${arrowPosition}
|
|
28043
|
-
text-[min(3.5vw,2.25rem)] font-bold tracking-tight ${arrowColor} drop-shadow-sm`,
|
|
28295
|
+
text-base sm:text-lg md:text-[min(3.5vw,2.25rem)] font-bold tracking-tight ${arrowColor} drop-shadow-sm`,
|
|
28044
28296
|
style: { bottom: "-2.5rem", lineHeight: 1, display: "flex", alignItems: "center", justifyContent: "center" },
|
|
28045
28297
|
children: arrow
|
|
28046
28298
|
}
|
|
@@ -28070,11 +28322,11 @@ var WorkspaceGrid = React19__namespace.default.memo(({
|
|
|
28070
28322
|
}, [workspaces.length]);
|
|
28071
28323
|
const { VideoGridView: VideoGridViewComponent } = useRegistry();
|
|
28072
28324
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `relative w-full h-full overflow-hidden ${className}`, children: [
|
|
28073
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-0 left-
|
|
28074
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-row items-center justify-between py-
|
|
28075
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sm:hidden mt-
|
|
28325
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-0 left-4 sm:left-4 right-4 sm:right-8 z-20", children: [
|
|
28326
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-row items-center justify-between py-2 sm:py-1.5 gap-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.jsx(Legend6, {}) }) }),
|
|
28327
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sm:hidden mt-2", children: /* @__PURE__ */ jsxRuntime.jsx(Legend6, {}) })
|
|
28076
28328
|
] }),
|
|
28077
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-
|
|
28329
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-12 sm:top-16 left-0 right-0 bottom-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
28078
28330
|
VideoGridViewComponent,
|
|
28079
28331
|
{
|
|
28080
28332
|
workspaces,
|
|
@@ -28289,8 +28541,8 @@ var KPICard = ({
|
|
|
28289
28541
|
const cardClasses = clsx(
|
|
28290
28542
|
// Base classes
|
|
28291
28543
|
"rounded-lg transition-all duration-200",
|
|
28292
|
-
// Sizing based on compact mode -
|
|
28293
|
-
"p-
|
|
28544
|
+
// Sizing based on compact mode - better padding on mobile
|
|
28545
|
+
"p-2.5 sm:p-3 md:p-4",
|
|
28294
28546
|
// Variant-specific styling
|
|
28295
28547
|
{
|
|
28296
28548
|
"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",
|
|
@@ -28298,8 +28550,8 @@ var KPICard = ({
|
|
|
28298
28550
|
"bg-blue-50 border border-blue-200 dark:bg-blue-900/20 dark:border-blue-800/30": style.variant === "filled",
|
|
28299
28551
|
"bg-gray-50/50 dark:bg-gray-800/30": style.variant === "subtle"
|
|
28300
28552
|
},
|
|
28301
|
-
// Width for src matching -
|
|
28302
|
-
!className?.includes("w-") && "w-[
|
|
28553
|
+
// Width for src matching - better mobile width, flexible on small screens
|
|
28554
|
+
!className?.includes("w-") && "w-[110px] sm:w-[180px] md:w-[220px]",
|
|
28303
28555
|
// Interactive styling if onClick is provided
|
|
28304
28556
|
onClick && "cursor-pointer hover:scale-[1.01] active:scale-[0.99]",
|
|
28305
28557
|
// Loading state
|
|
@@ -28318,14 +28570,14 @@ var KPICard = ({
|
|
|
28318
28570
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
28319
28571
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx(
|
|
28320
28572
|
"font-medium text-gray-500 dark:text-gray-400",
|
|
28321
|
-
"text-[
|
|
28322
|
-
"mb-
|
|
28323
|
-
"uppercase tracking-wider"
|
|
28573
|
+
"text-[10px] sm:text-xs md:text-sm",
|
|
28574
|
+
"mb-1 sm:mb-1 md:mb-2",
|
|
28575
|
+
"uppercase tracking-wide sm:tracking-wider"
|
|
28324
28576
|
), children: title }),
|
|
28325
28577
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-0.5 sm:gap-2 flex-wrap", children: [
|
|
28326
28578
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx(
|
|
28327
28579
|
"font-bold text-gray-900 dark:text-gray-50",
|
|
28328
|
-
"text-
|
|
28580
|
+
"text-base sm:text-xl md:text-2xl"
|
|
28329
28581
|
), children: isLoading ? "\u2014" : formattedValue }),
|
|
28330
28582
|
suffix && !isLoading && /* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx(
|
|
28331
28583
|
"font-medium text-gray-600 dark:text-gray-300",
|
|
@@ -28500,35 +28752,46 @@ var KPISection = React19.memo(({
|
|
|
28500
28752
|
const outputDifference = kpis.outputProgress.current - kpis.outputProgress.idealOutput;
|
|
28501
28753
|
const outputIsOnTarget = outputDifference >= 0;
|
|
28502
28754
|
if (useSrcLayout) {
|
|
28503
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
28504
|
-
|
|
28505
|
-
|
|
28506
|
-
{
|
|
28507
|
-
|
|
28508
|
-
|
|
28509
|
-
|
|
28510
|
-
|
|
28511
|
-
|
|
28512
|
-
|
|
28513
|
-
|
|
28514
|
-
|
|
28515
|
-
|
|
28516
|
-
|
|
28517
|
-
|
|
28518
|
-
|
|
28519
|
-
|
|
28520
|
-
|
|
28521
|
-
|
|
28522
|
-
|
|
28523
|
-
|
|
28524
|
-
|
|
28525
|
-
|
|
28526
|
-
|
|
28527
|
-
|
|
28528
|
-
|
|
28529
|
-
|
|
28530
|
-
|
|
28531
|
-
|
|
28755
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
28756
|
+
"div",
|
|
28757
|
+
{
|
|
28758
|
+
className: `flex gap-2 sm:gap-3 overflow-x-auto sm:overflow-visible pb-2 sm:pb-0 ${className || ""}`,
|
|
28759
|
+
style: {
|
|
28760
|
+
scrollbarWidth: "none",
|
|
28761
|
+
msOverflowStyle: "none",
|
|
28762
|
+
WebkitScrollbar: { display: "none" }
|
|
28763
|
+
},
|
|
28764
|
+
children: [
|
|
28765
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
28766
|
+
KPICard,
|
|
28767
|
+
{
|
|
28768
|
+
title: "Underperforming",
|
|
28769
|
+
value: "2/3",
|
|
28770
|
+
change: 0
|
|
28771
|
+
}
|
|
28772
|
+
) }),
|
|
28773
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
28774
|
+
KPICard,
|
|
28775
|
+
{
|
|
28776
|
+
title: "Efficiency",
|
|
28777
|
+
value: kpis.efficiency.value,
|
|
28778
|
+
change: kpis.efficiency.change,
|
|
28779
|
+
suffix: "%"
|
|
28780
|
+
}
|
|
28781
|
+
) }),
|
|
28782
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
28783
|
+
KPICard,
|
|
28784
|
+
{
|
|
28785
|
+
title: "Output Progress",
|
|
28786
|
+
value: `${kpis.outputProgress.current}/${kpis.outputProgress.target}`,
|
|
28787
|
+
change: kpis.outputProgress.change,
|
|
28788
|
+
outputDifference,
|
|
28789
|
+
showOutputDetails: true
|
|
28790
|
+
}
|
|
28791
|
+
) })
|
|
28792
|
+
]
|
|
28793
|
+
}
|
|
28794
|
+
);
|
|
28532
28795
|
}
|
|
28533
28796
|
const kpiCardData = [
|
|
28534
28797
|
{
|
|
@@ -28661,6 +28924,19 @@ var WorkspaceHealthCard = ({
|
|
|
28661
28924
|
const formatTimeAgo = (timeString) => {
|
|
28662
28925
|
return timeString.replace("about ", "").replace(" ago", "");
|
|
28663
28926
|
};
|
|
28927
|
+
const formatDowntime = (uptimeDetails) => {
|
|
28928
|
+
if (!uptimeDetails) return "";
|
|
28929
|
+
const downtimeMinutes = Math.max(0, uptimeDetails.expectedMinutes - uptimeDetails.actualMinutes);
|
|
28930
|
+
if (downtimeMinutes === 0) return "No downtime";
|
|
28931
|
+
if (downtimeMinutes < 1) return "< 1 min downtime";
|
|
28932
|
+
if (downtimeMinutes < 60) return `${downtimeMinutes} min downtime`;
|
|
28933
|
+
const hours = Math.floor(downtimeMinutes / 60);
|
|
28934
|
+
const minutes = downtimeMinutes % 60;
|
|
28935
|
+
if (minutes === 0) {
|
|
28936
|
+
return `${hours} hr downtime`;
|
|
28937
|
+
}
|
|
28938
|
+
return `${hours} hr ${minutes} min downtime`;
|
|
28939
|
+
};
|
|
28664
28940
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
28665
28941
|
Card2,
|
|
28666
28942
|
{
|
|
@@ -28694,13 +28970,32 @@ var WorkspaceHealthCard = ({
|
|
|
28694
28970
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: config.statusText })
|
|
28695
28971
|
] })
|
|
28696
28972
|
] }),
|
|
28697
|
-
/* @__PURE__ */ jsxRuntime.
|
|
28698
|
-
/* @__PURE__ */ jsxRuntime.
|
|
28699
|
-
|
|
28700
|
-
"
|
|
28701
|
-
|
|
28702
|
-
|
|
28703
|
-
|
|
28973
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
28974
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
28975
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-3.5 w-3.5 text-gray-400" }),
|
|
28976
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-gray-600 dark:text-gray-400 whitespace-nowrap", children: [
|
|
28977
|
+
"Last seen: ",
|
|
28978
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: formatTimeAgo(workspace.timeSinceLastUpdate) })
|
|
28979
|
+
] })
|
|
28980
|
+
] }),
|
|
28981
|
+
workspace.uptimePercentage !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
28982
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Activity, { className: "h-3.5 w-3.5 text-gray-400" }),
|
|
28983
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-gray-600 dark:text-gray-400 whitespace-nowrap", children: [
|
|
28984
|
+
"Uptime today: ",
|
|
28985
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: clsx(
|
|
28986
|
+
"font-medium",
|
|
28987
|
+
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"
|
|
28988
|
+
), children: [
|
|
28989
|
+
workspace.uptimePercentage.toFixed(1),
|
|
28990
|
+
"%"
|
|
28991
|
+
] })
|
|
28992
|
+
] })
|
|
28993
|
+
] }),
|
|
28994
|
+
workspace.uptimeDetails && workspace.uptimeDetails.expectedMinutes > workspace.uptimeDetails.actualMinutes && workspace.uptimePercentage !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx(
|
|
28995
|
+
"inline-flex items-center px-2 py-0.5 rounded text-xs font-medium",
|
|
28996
|
+
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"
|
|
28997
|
+
), children: formatDowntime(workspace.uptimeDetails) }) })
|
|
28998
|
+
] })
|
|
28704
28999
|
] })
|
|
28705
29000
|
}
|
|
28706
29001
|
);
|
|
@@ -28771,6 +29066,20 @@ var CompactWorkspaceHealthCard = ({
|
|
|
28771
29066
|
] })
|
|
28772
29067
|
] }),
|
|
28773
29068
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
29069
|
+
workspace.uptimePercentage !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
29070
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: clsx(
|
|
29071
|
+
"text-xs font-medium",
|
|
29072
|
+
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"
|
|
29073
|
+
), children: [
|
|
29074
|
+
workspace.uptimePercentage.toFixed(1),
|
|
29075
|
+
"%"
|
|
29076
|
+
] }),
|
|
29077
|
+
workspace.uptimeDetails && workspace.uptimeDetails.expectedMinutes > workspace.uptimeDetails.actualMinutes && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-400 dark:text-gray-400", children: "\u2022" }),
|
|
29078
|
+
workspace.uptimeDetails && workspace.uptimeDetails.expectedMinutes > workspace.uptimeDetails.actualMinutes && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: [
|
|
29079
|
+
Math.max(0, workspace.uptimeDetails.expectedMinutes - workspace.uptimeDetails.actualMinutes),
|
|
29080
|
+
"m down"
|
|
29081
|
+
] })
|
|
29082
|
+
] }),
|
|
28774
29083
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: workspace.timeSinceLastUpdate }),
|
|
28775
29084
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("h-2 w-2 rounded-full", config.dot) })
|
|
28776
29085
|
] })
|
|
@@ -28994,18 +29303,18 @@ var DashboardHeader = React19.memo(({ lineTitle, className = "", headerControls
|
|
|
28994
29303
|
};
|
|
28995
29304
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-row items-center justify-between w-full ${className}`, children: [
|
|
28996
29305
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
28997
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-
|
|
28998
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-
|
|
28999
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1 w-1 sm:h-1.5 sm:w-1.5 md:h-2 md:w-2 rounded-full bg-green-500 animate-pulse ring-
|
|
29306
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 sm:gap-2 md:gap-3", children: [
|
|
29307
|
+
/* @__PURE__ */ jsxRuntime.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 }),
|
|
29308
|
+
/* @__PURE__ */ jsxRuntime.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" })
|
|
29000
29309
|
] }),
|
|
29001
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 inline-flex items-center gap-3", children: [
|
|
29002
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm font-medium text-gray-600", children: [
|
|
29310
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 inline-flex items-center gap-2 sm:gap-3", children: [
|
|
29311
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs sm:text-sm font-medium text-gray-600", children: [
|
|
29003
29312
|
/* @__PURE__ */ jsxRuntime.jsx(ISTTimer2, {}),
|
|
29004
29313
|
" IST"
|
|
29005
29314
|
] }),
|
|
29006
29315
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1", children: [
|
|
29007
29316
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children: getShiftIcon() }),
|
|
29008
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
|
|
29317
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs sm:text-sm font-medium text-gray-600", children: [
|
|
29009
29318
|
getShiftName(),
|
|
29010
29319
|
" Shift"
|
|
29011
29320
|
] })
|
|
@@ -29016,9 +29325,9 @@ var DashboardHeader = React19.memo(({ lineTitle, className = "", headerControls
|
|
|
29016
29325
|
] });
|
|
29017
29326
|
});
|
|
29018
29327
|
DashboardHeader.displayName = "DashboardHeader";
|
|
29019
|
-
var NoWorkspaceData = React19.memo(({ message = "No workspace data available", className = "" }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex h-full items-center justify-center ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg bg-white p-4 shadow-md", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-2 text-gray-500", children: [
|
|
29020
|
-
/* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", clipRule: "evenodd" }) }),
|
|
29021
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: message })
|
|
29328
|
+
var NoWorkspaceData = React19.memo(({ message = "No workspace data available", className = "" }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex h-full items-center justify-center ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg bg-white p-5 sm:p-4 shadow-md", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-3 sm:space-x-2 text-gray-500", children: [
|
|
29329
|
+
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", clipRule: "evenodd" }) }),
|
|
29330
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base sm:text-sm", children: message })
|
|
29022
29331
|
] }) }) }));
|
|
29023
29332
|
NoWorkspaceData.displayName = "NoWorkspaceData";
|
|
29024
29333
|
var WorkspaceMonthlyDataFetcher = ({
|
|
@@ -29143,10 +29452,10 @@ var HamburgerButton = ({
|
|
|
29143
29452
|
"button",
|
|
29144
29453
|
{
|
|
29145
29454
|
type: "button",
|
|
29146
|
-
className: `md:hidden p-2 rounded-
|
|
29455
|
+
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}`,
|
|
29147
29456
|
onClick,
|
|
29148
29457
|
"aria-label": ariaLabel,
|
|
29149
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(outline.Bars3Icon, { className: "w-
|
|
29458
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(outline.Bars3Icon, { className: "w-7 h-7" })
|
|
29150
29459
|
}
|
|
29151
29460
|
);
|
|
29152
29461
|
};
|
|
@@ -29677,28 +29986,189 @@ var SideNavBar = React19.memo(({
|
|
|
29677
29986
|
}
|
|
29678
29987
|
) })
|
|
29679
29988
|
] });
|
|
29989
|
+
const MobileNavigationContent = () => {
|
|
29990
|
+
const isActive = (path) => {
|
|
29991
|
+
if (path === "/" && pathname === "/") return true;
|
|
29992
|
+
if (path !== "/" && pathname.startsWith(path)) return true;
|
|
29993
|
+
return false;
|
|
29994
|
+
};
|
|
29995
|
+
const getMobileButtonClass = (path) => {
|
|
29996
|
+
const active = isActive(path);
|
|
29997
|
+
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"}`;
|
|
29998
|
+
};
|
|
29999
|
+
const getIconClass = (path) => {
|
|
30000
|
+
const active = isActive(path);
|
|
30001
|
+
return `w-7 h-7 ${active ? "text-blue-600" : "text-gray-600"}`;
|
|
30002
|
+
};
|
|
30003
|
+
const handleMobileNavClick = (handler) => {
|
|
30004
|
+
return () => {
|
|
30005
|
+
handler();
|
|
30006
|
+
onMobileMenuClose?.();
|
|
30007
|
+
};
|
|
30008
|
+
};
|
|
30009
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("nav", { className: "px-5 py-6", children: [
|
|
30010
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
30011
|
+
"button",
|
|
30012
|
+
{
|
|
30013
|
+
onClick: handleMobileNavClick(handleHomeClick),
|
|
30014
|
+
className: getMobileButtonClass("/"),
|
|
30015
|
+
"aria-label": "Home",
|
|
30016
|
+
children: [
|
|
30017
|
+
/* @__PURE__ */ jsxRuntime.jsx(outline.HomeIcon, { className: getIconClass("/") }),
|
|
30018
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-medium", children: "Home" })
|
|
30019
|
+
]
|
|
30020
|
+
}
|
|
30021
|
+
),
|
|
30022
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 space-y-2", children: [
|
|
30023
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
30024
|
+
"button",
|
|
30025
|
+
{
|
|
30026
|
+
onClick: handleMobileNavClick(handleLeaderboardClick),
|
|
30027
|
+
className: getMobileButtonClass("/leaderboard"),
|
|
30028
|
+
"aria-label": "Leaderboard",
|
|
30029
|
+
children: [
|
|
30030
|
+
/* @__PURE__ */ jsxRuntime.jsx(outline.TrophyIcon, { className: getIconClass("/leaderboard") }),
|
|
30031
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-medium", children: "Leaderboard" })
|
|
30032
|
+
]
|
|
30033
|
+
}
|
|
30034
|
+
),
|
|
30035
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
30036
|
+
"button",
|
|
30037
|
+
{
|
|
30038
|
+
onClick: handleMobileNavClick(handleKPIsClick),
|
|
30039
|
+
className: getMobileButtonClass("/kpis"),
|
|
30040
|
+
"aria-label": "Lines",
|
|
30041
|
+
children: [
|
|
30042
|
+
/* @__PURE__ */ jsxRuntime.jsx(outline.ChartBarIcon, { className: getIconClass("/kpis") }),
|
|
30043
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-medium", children: "Lines" })
|
|
30044
|
+
]
|
|
30045
|
+
}
|
|
30046
|
+
),
|
|
30047
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
30048
|
+
"button",
|
|
30049
|
+
{
|
|
30050
|
+
onClick: handleMobileNavClick(handleTargetsClick),
|
|
30051
|
+
className: getMobileButtonClass("/targets"),
|
|
30052
|
+
"aria-label": "Targets",
|
|
30053
|
+
children: [
|
|
30054
|
+
/* @__PURE__ */ jsxRuntime.jsx(outline.AdjustmentsHorizontalIcon, { className: getIconClass("/targets") }),
|
|
30055
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-medium", children: "Targets" })
|
|
30056
|
+
]
|
|
30057
|
+
}
|
|
30058
|
+
),
|
|
30059
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
30060
|
+
"button",
|
|
30061
|
+
{
|
|
30062
|
+
onClick: handleMobileNavClick(handleShiftsClick),
|
|
30063
|
+
className: getMobileButtonClass("/shifts"),
|
|
30064
|
+
"aria-label": "Shift Management",
|
|
30065
|
+
children: [
|
|
30066
|
+
/* @__PURE__ */ jsxRuntime.jsx(outline.ClockIcon, { className: getIconClass("/shifts") }),
|
|
30067
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-medium", children: "Shifts" })
|
|
30068
|
+
]
|
|
30069
|
+
}
|
|
30070
|
+
),
|
|
30071
|
+
skuEnabled && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
30072
|
+
"button",
|
|
30073
|
+
{
|
|
30074
|
+
onClick: handleMobileNavClick(handleSKUsClick),
|
|
30075
|
+
className: getMobileButtonClass("/skus"),
|
|
30076
|
+
"aria-label": "SKU Management",
|
|
30077
|
+
children: [
|
|
30078
|
+
/* @__PURE__ */ jsxRuntime.jsx(outline.CubeIcon, { className: getIconClass("/skus") }),
|
|
30079
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-medium", children: "SKUs" })
|
|
30080
|
+
]
|
|
30081
|
+
}
|
|
30082
|
+
),
|
|
30083
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
30084
|
+
"button",
|
|
30085
|
+
{
|
|
30086
|
+
onClick: handleMobileNavClick(handleAIAgentClick),
|
|
30087
|
+
className: getMobileButtonClass("/ai-agent"),
|
|
30088
|
+
"aria-label": "AI Manufacturing Expert",
|
|
30089
|
+
children: [
|
|
30090
|
+
/* @__PURE__ */ jsxRuntime.jsx(outline.SparklesIcon, { className: getIconClass("/ai-agent") }),
|
|
30091
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-medium", children: "Axel AI" })
|
|
30092
|
+
]
|
|
30093
|
+
}
|
|
30094
|
+
),
|
|
30095
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
30096
|
+
"button",
|
|
30097
|
+
{
|
|
30098
|
+
onClick: handleMobileNavClick(handleHelpClick),
|
|
30099
|
+
className: getMobileButtonClass("/help"),
|
|
30100
|
+
"aria-label": "Help & Support",
|
|
30101
|
+
children: [
|
|
30102
|
+
/* @__PURE__ */ jsxRuntime.jsx(outline.QuestionMarkCircleIcon, { className: getIconClass("/help") }),
|
|
30103
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-medium", children: "Help" })
|
|
30104
|
+
]
|
|
30105
|
+
}
|
|
30106
|
+
),
|
|
30107
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
30108
|
+
"button",
|
|
30109
|
+
{
|
|
30110
|
+
onClick: handleMobileNavClick(handleHealthClick),
|
|
30111
|
+
className: getMobileButtonClass("/health"),
|
|
30112
|
+
"aria-label": "System Health",
|
|
30113
|
+
children: [
|
|
30114
|
+
/* @__PURE__ */ jsxRuntime.jsx(outline.HeartIcon, { className: getIconClass("/health") }),
|
|
30115
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-medium", children: "System Health" })
|
|
30116
|
+
]
|
|
30117
|
+
}
|
|
30118
|
+
)
|
|
30119
|
+
] }),
|
|
30120
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-8 pt-6 border-t border-gray-200", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
30121
|
+
"button",
|
|
30122
|
+
{
|
|
30123
|
+
onClick: handleMobileNavClick(handleProfileClick),
|
|
30124
|
+
className: getMobileButtonClass("/profile"),
|
|
30125
|
+
"aria-label": "Profile & Settings",
|
|
30126
|
+
children: [
|
|
30127
|
+
/* @__PURE__ */ jsxRuntime.jsx(outline.UserCircleIcon, { className: getIconClass("/profile") }),
|
|
30128
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-medium", children: "Profile" })
|
|
30129
|
+
]
|
|
30130
|
+
}
|
|
30131
|
+
) })
|
|
30132
|
+
] });
|
|
30133
|
+
};
|
|
29680
30134
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
29681
30135
|
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(NavigationContent, {}) }),
|
|
29682
|
-
|
|
30136
|
+
/* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
29683
30137
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
29684
30138
|
"div",
|
|
29685
30139
|
{
|
|
29686
|
-
className:
|
|
30140
|
+
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"}`,
|
|
29687
30141
|
onClick: onMobileMenuClose,
|
|
29688
30142
|
"aria-hidden": "true"
|
|
29689
30143
|
}
|
|
29690
30144
|
),
|
|
29691
|
-
/* @__PURE__ */ jsxRuntime.jsxs("aside", { className:
|
|
29692
|
-
/* @__PURE__ */ jsxRuntime.
|
|
29693
|
-
"
|
|
29694
|
-
|
|
29695
|
-
|
|
29696
|
-
|
|
29697
|
-
|
|
29698
|
-
|
|
29699
|
-
|
|
29700
|
-
|
|
29701
|
-
|
|
30145
|
+
/* @__PURE__ */ jsxRuntime.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: [
|
|
30146
|
+
/* @__PURE__ */ jsxRuntime.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: [
|
|
30147
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
30148
|
+
"img",
|
|
30149
|
+
{
|
|
30150
|
+
src: "/optifye-logo.png",
|
|
30151
|
+
alt: "Optifye",
|
|
30152
|
+
className: "w-11 h-11 object-contain",
|
|
30153
|
+
onError: (e) => {
|
|
30154
|
+
e.currentTarget.style.display = "none";
|
|
30155
|
+
if (e.currentTarget.parentElement) {
|
|
30156
|
+
e.currentTarget.parentElement.innerHTML = '<span class="text-blue-600 font-bold text-xl">Optifye</span>';
|
|
30157
|
+
}
|
|
30158
|
+
}
|
|
30159
|
+
}
|
|
30160
|
+
) }),
|
|
30161
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
30162
|
+
"button",
|
|
30163
|
+
{
|
|
30164
|
+
onClick: onMobileMenuClose,
|
|
30165
|
+
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",
|
|
30166
|
+
"aria-label": "Close menu",
|
|
30167
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(outline.XMarkIcon, { className: "w-7 h-7" })
|
|
30168
|
+
}
|
|
30169
|
+
)
|
|
30170
|
+
] }),
|
|
30171
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(MobileNavigationContent, {}) })
|
|
29702
30172
|
] })
|
|
29703
30173
|
] })
|
|
29704
30174
|
] });
|
|
@@ -29790,17 +30260,39 @@ var MainLayout = ({
|
|
|
29790
30260
|
logo
|
|
29791
30261
|
}) => {
|
|
29792
30262
|
const router$1 = router.useRouter();
|
|
30263
|
+
const [isMobileMenuOpen, setIsMobileMenuOpen] = React19.useState(false);
|
|
30264
|
+
const handleMobileMenuOpen = () => setIsMobileMenuOpen(true);
|
|
30265
|
+
const handleMobileMenuClose = () => setIsMobileMenuOpen(false);
|
|
29793
30266
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `min-h-screen ${className}`, children: [
|
|
30267
|
+
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
30268
|
+
/* @__PURE__ */ jsxRuntime.jsx(HamburgerButton, { onClick: handleMobileMenuOpen }),
|
|
30269
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
30270
|
+
"img",
|
|
30271
|
+
{
|
|
30272
|
+
src: "/optifye-logo.png",
|
|
30273
|
+
alt: "Optifye",
|
|
30274
|
+
className: "h-9 w-9 object-contain",
|
|
30275
|
+
onError: (e) => {
|
|
30276
|
+
e.currentTarget.style.display = "none";
|
|
30277
|
+
if (e.currentTarget.parentElement) {
|
|
30278
|
+
e.currentTarget.parentElement.innerHTML = '<span class="text-blue-600 font-bold text-lg">Optifye</span>';
|
|
30279
|
+
}
|
|
30280
|
+
}
|
|
30281
|
+
}
|
|
30282
|
+
) })
|
|
30283
|
+
] }) }),
|
|
29794
30284
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
29795
30285
|
SideNavBar,
|
|
29796
30286
|
{
|
|
29797
30287
|
navItems,
|
|
29798
30288
|
currentPathname: router$1.pathname,
|
|
29799
30289
|
currentQuery: router$1.query,
|
|
29800
|
-
logo
|
|
30290
|
+
logo,
|
|
30291
|
+
isMobileMenuOpen,
|
|
30292
|
+
onMobileMenuClose: handleMobileMenuClose
|
|
29801
30293
|
}
|
|
29802
30294
|
),
|
|
29803
|
-
/* @__PURE__ */ jsxRuntime.jsx("main", { className: "ml-20 bg-gray-50 min-h-screen", children })
|
|
30295
|
+
/* @__PURE__ */ jsxRuntime.jsx("main", { className: "md:ml-20 bg-gray-50 min-h-screen transition-all duration-300", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full", children }) })
|
|
29804
30296
|
] });
|
|
29805
30297
|
};
|
|
29806
30298
|
var Header = ({
|
|
@@ -32810,7 +33302,7 @@ function HomeView({
|
|
|
32810
33302
|
return null;
|
|
32811
33303
|
}
|
|
32812
33304
|
return /* @__PURE__ */ jsxRuntime.jsxs(Select, { onValueChange: handleLineChange, defaultValue: selectedLineId, children: [
|
|
32813
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "w-full sm:w-[200px] bg-white border border-gray-200 shadow-sm rounded-md h-9 text-sm", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Select a line" }) }),
|
|
33305
|
+
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Select a line" }) }),
|
|
32814
33306
|
/* @__PURE__ */ jsxRuntime.jsx(SelectContent, { className: "z-50 bg-white shadow-lg border border-gray-200 rounded-md", children: availableLineIds.map((id3) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: id3, children: lineNames[id3] || (id3 === factoryViewId ? "All Lines" : `Line ${id3.substring(0, 4)}`) }, id3)) })
|
|
32815
33307
|
] });
|
|
32816
33308
|
}, [availableLineIds, handleLineChange, selectedLineId, lineNames, factoryViewId, allLineIds.length]);
|
|
@@ -32822,7 +33314,7 @@ function HomeView({
|
|
|
32822
33314
|
if (errorMessage || displayNamesError) {
|
|
32823
33315
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-screen items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg bg-white p-6 shadow-lg", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-3 text-red-500", children: [
|
|
32824
33316
|
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
|
|
32825
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-lg font-medium", children: [
|
|
33317
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-base sm:text-lg font-medium", children: [
|
|
32826
33318
|
"Error: ",
|
|
32827
33319
|
errorMessage || displayNamesError?.message
|
|
32828
33320
|
] })
|
|
@@ -32836,7 +33328,7 @@ function HomeView({
|
|
|
32836
33328
|
animate: { opacity: 1 },
|
|
32837
33329
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-1", children: [
|
|
32838
33330
|
/* @__PURE__ */ jsxRuntime.jsxs("main", { className: "flex flex-1 flex-col", children: [
|
|
32839
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-30
|
|
33331
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative sm:sticky sm:top-0 z-30 bg-white shadow-sm border-b border-gray-200/80", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col sm:flex-row sm:items-center sm:justify-between px-4 sm:px-6 lg:px-8 py-3 sm:py-2.5", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
32840
33332
|
DashboardHeader,
|
|
32841
33333
|
{
|
|
32842
33334
|
lineTitle,
|
|
@@ -32845,8 +33337,8 @@ function HomeView({
|
|
|
32845
33337
|
}
|
|
32846
33338
|
) }) }),
|
|
32847
33339
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto sm:overflow-hidden relative", children: [
|
|
32848
|
-
lineSelectorComponent && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-
|
|
32849
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full sm:h-full min-h-[calc(100vh-
|
|
33340
|
+
lineSelectorComponent && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-4 top-3 sm:right-6 sm:top-3 z-30", children: lineSelectorComponent }),
|
|
33341
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full sm:h-full min-h-[calc(100vh-120px)] sm:min-h-0", children: memoizedWorkspaceMetrics.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
32850
33342
|
motion.div,
|
|
32851
33343
|
{
|
|
32852
33344
|
initial: { opacity: 0, scale: 0.98 },
|
|
@@ -38356,8 +38848,8 @@ var WorkspaceHealthView = ({
|
|
|
38356
38848
|
}
|
|
38357
38849
|
};
|
|
38358
38850
|
const getUptimeColor = (percentage) => {
|
|
38359
|
-
if (percentage >=
|
|
38360
|
-
if (percentage >=
|
|
38851
|
+
if (percentage >= 97) return "text-green-600 dark:text-green-400";
|
|
38852
|
+
if (percentage >= 90) return "text-yellow-600 dark:text-yellow-400";
|
|
38361
38853
|
return "text-red-600 dark:text-red-400";
|
|
38362
38854
|
};
|
|
38363
38855
|
if (loading && !summary) {
|
|
@@ -38445,20 +38937,21 @@ var WorkspaceHealthView = ({
|
|
|
38445
38937
|
className: "grid grid-cols-2 sm:grid-cols-2 md:grid-cols-5 gap-2 sm:gap-3 lg:gap-4",
|
|
38446
38938
|
children: [
|
|
38447
38939
|
/* @__PURE__ */ jsxRuntime.jsxs(Card2, { className: "col-span-2 sm:col-span-2 md:col-span-2 bg-white", children: [
|
|
38448
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-3", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-sm font-medium text-gray-500 dark:text-gray-400", children: "Overall System
|
|
38940
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-3", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-sm font-medium text-gray-500 dark:text-gray-400", children: "Overall System Uptime Today" }) }),
|
|
38449
38941
|
/* @__PURE__ */ jsxRuntime.jsxs(CardContent2, { children: [
|
|
38450
38942
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2", children: [
|
|
38451
38943
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: clsx("text-3xl font-bold", getUptimeColor(summary.uptimePercentage)), children: [
|
|
38452
38944
|
summary.uptimePercentage.toFixed(1),
|
|
38453
38945
|
"%"
|
|
38454
38946
|
] }),
|
|
38455
|
-
summary.uptimePercentage >=
|
|
38947
|
+
summary.uptimePercentage >= 97 ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingUp, { className: "h-5 w-5 text-green-500" }) : summary.uptimePercentage >= 90 ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Activity, { className: "h-5 w-5 text-yellow-500" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingDown, { className: "h-5 w-5 text-red-500" })
|
|
38456
38948
|
] }),
|
|
38457
|
-
/* @__PURE__ */ jsxRuntime.
|
|
38949
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: "Average uptime across all workspaces" }),
|
|
38950
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: [
|
|
38458
38951
|
summary.healthyWorkspaces,
|
|
38459
38952
|
" of ",
|
|
38460
38953
|
summary.totalWorkspaces,
|
|
38461
|
-
" workspaces
|
|
38954
|
+
" workspaces online"
|
|
38462
38955
|
] })
|
|
38463
38956
|
] })
|
|
38464
38957
|
] }),
|