@optifye/dashboard-core 6.9.12 → 6.9.13
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 +61 -12
- package/dist/index.d.mts +52 -1
- package/dist/index.d.ts +52 -1
- package/dist/index.js +1227 -545
- package/dist/index.mjs +1229 -548
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2,8 +2,8 @@ import * as React23 from 'react';
|
|
|
2
2
|
import React23__default, { createContext, useRef, useCallback, useState, useMemo, useEffect, forwardRef, useImperativeHandle, useLayoutEffect, memo, useContext, useId, Children, isValidElement, useInsertionEffect, Fragment as Fragment$1, createElement, Component } from 'react';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import { useRouter } from 'next/router';
|
|
5
|
-
import { toZonedTime, formatInTimeZone } from 'date-fns-tz';
|
|
6
|
-
import { subDays, format, parseISO, isValid, formatDistanceToNow, isFuture, isToday } from 'date-fns';
|
|
5
|
+
import { toZonedTime, formatInTimeZone, fromZonedTime } from 'date-fns-tz';
|
|
6
|
+
import { subDays, format, parseISO, isValid, addMinutes, differenceInMinutes, formatDistanceToNow, isFuture, isToday } from 'date-fns';
|
|
7
7
|
import mixpanel from 'mixpanel-browser';
|
|
8
8
|
import { EventEmitter } from 'events';
|
|
9
9
|
import { createClient, REALTIME_SUBSCRIBE_STATES } from '@supabase/supabase-js';
|
|
@@ -2134,6 +2134,88 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2134
2134
|
setCache(key, data) {
|
|
2135
2135
|
this.cache.set(key, { data, timestamp: Date.now() });
|
|
2136
2136
|
}
|
|
2137
|
+
getShiftTiming(timezone, shiftConfig) {
|
|
2138
|
+
const { shiftId, date } = getCurrentShift(timezone, shiftConfig);
|
|
2139
|
+
const dayShiftId = shiftConfig?.dayShift?.id ?? 0;
|
|
2140
|
+
const isDayShift = shiftId === dayShiftId;
|
|
2141
|
+
const defaultDayStart = "06:00";
|
|
2142
|
+
const defaultDayEnd = "18:00";
|
|
2143
|
+
const defaultNightStart = "18:00";
|
|
2144
|
+
const defaultNightEnd = "06:00";
|
|
2145
|
+
const shiftStartStr = isDayShift ? shiftConfig?.dayShift?.startTime || defaultDayStart : shiftConfig?.nightShift?.startTime || defaultNightStart;
|
|
2146
|
+
const shiftEndStr = isDayShift ? shiftConfig?.dayShift?.endTime || defaultDayEnd : shiftConfig?.nightShift?.endTime || defaultNightEnd;
|
|
2147
|
+
const shiftLabel = isDayShift ? "Day Shift" : "Night Shift";
|
|
2148
|
+
const parseTime = (value) => {
|
|
2149
|
+
const [hourPart = "0", minutePart = "0"] = value.split(":");
|
|
2150
|
+
const hour = Number.parseInt(hourPart, 10);
|
|
2151
|
+
const minute = Number.parseInt(minutePart, 10);
|
|
2152
|
+
return {
|
|
2153
|
+
hour: Number.isFinite(hour) ? hour : 0,
|
|
2154
|
+
minute: Number.isFinite(minute) ? minute : 0
|
|
2155
|
+
};
|
|
2156
|
+
};
|
|
2157
|
+
const getShiftDurationMinutes = (start, end) => {
|
|
2158
|
+
const startParsed = parseTime(start);
|
|
2159
|
+
const endParsed = parseTime(end);
|
|
2160
|
+
const startTotal = startParsed.hour * 60 + startParsed.minute;
|
|
2161
|
+
const endTotal = endParsed.hour * 60 + endParsed.minute;
|
|
2162
|
+
let duration = endTotal - startTotal;
|
|
2163
|
+
if (duration <= 0) {
|
|
2164
|
+
duration += 24 * 60;
|
|
2165
|
+
}
|
|
2166
|
+
return duration;
|
|
2167
|
+
};
|
|
2168
|
+
const shiftStartDate = fromZonedTime(`${date}T${shiftStartStr}:00`, timezone);
|
|
2169
|
+
const totalMinutes = getShiftDurationMinutes(shiftStartStr, shiftEndStr);
|
|
2170
|
+
const shiftEndDate = addMinutes(shiftStartDate, totalMinutes);
|
|
2171
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
2172
|
+
let completedMinutes = differenceInMinutes(now2 < shiftEndDate ? now2 : shiftEndDate, shiftStartDate);
|
|
2173
|
+
if (completedMinutes < 0) completedMinutes = 0;
|
|
2174
|
+
if (completedMinutes > totalMinutes) completedMinutes = totalMinutes;
|
|
2175
|
+
const pendingMinutes = Math.max(0, totalMinutes - completedMinutes);
|
|
2176
|
+
return {
|
|
2177
|
+
shiftId,
|
|
2178
|
+
date,
|
|
2179
|
+
shiftLabel,
|
|
2180
|
+
shiftStartDate,
|
|
2181
|
+
shiftEndDate,
|
|
2182
|
+
totalMinutes,
|
|
2183
|
+
completedMinutes,
|
|
2184
|
+
pendingMinutes
|
|
2185
|
+
};
|
|
2186
|
+
}
|
|
2187
|
+
normalizeHourBucket(bucket) {
|
|
2188
|
+
if (Array.isArray(bucket)) return bucket;
|
|
2189
|
+
if (bucket && Array.isArray(bucket.values)) return bucket.values;
|
|
2190
|
+
return void 0;
|
|
2191
|
+
}
|
|
2192
|
+
normalizeOutputHourly(outputHourlyRaw) {
|
|
2193
|
+
return outputHourlyRaw && typeof outputHourlyRaw === "object" ? Object.fromEntries(
|
|
2194
|
+
Object.entries(outputHourlyRaw).map(([key, value]) => [key, this.normalizeHourBucket(value) || []])
|
|
2195
|
+
) : {};
|
|
2196
|
+
}
|
|
2197
|
+
interpretUptimeValue(value) {
|
|
2198
|
+
if (value === null || value === void 0) return "down";
|
|
2199
|
+
if (typeof value === "string") {
|
|
2200
|
+
return value.trim().toLowerCase() === "x" ? "down" : "up";
|
|
2201
|
+
}
|
|
2202
|
+
return "up";
|
|
2203
|
+
}
|
|
2204
|
+
deriveStatusForMinute(minuteOffset, minuteDate, outputHourly, outputArray, timezone) {
|
|
2205
|
+
const hourKey = formatInTimeZone(minuteDate, timezone, "H");
|
|
2206
|
+
const minuteKey = Number.parseInt(formatInTimeZone(minuteDate, timezone, "m"), 10);
|
|
2207
|
+
const hourBucket = outputHourly[hourKey];
|
|
2208
|
+
if (Array.isArray(hourBucket)) {
|
|
2209
|
+
const value = hourBucket[minuteKey];
|
|
2210
|
+
if (value !== void 0) {
|
|
2211
|
+
return this.interpretUptimeValue(value);
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
if (minuteOffset < outputArray.length) {
|
|
2215
|
+
return this.interpretUptimeValue(outputArray[minuteOffset]);
|
|
2216
|
+
}
|
|
2217
|
+
return "down";
|
|
2218
|
+
}
|
|
2137
2219
|
async getWorkspaceHealthStatus(options = {}) {
|
|
2138
2220
|
const supabase = _getSupabaseInstance();
|
|
2139
2221
|
if (!supabase) throw new Error("Supabase client not initialized");
|
|
@@ -2150,15 +2232,13 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2150
2232
|
throw error;
|
|
2151
2233
|
}
|
|
2152
2234
|
const processedData = (data || []).map((item) => this.processHealthStatus(item));
|
|
2235
|
+
const companyId = options.companyId || data?.[0]?.company_id;
|
|
2153
2236
|
let uptimeMap = /* @__PURE__ */ new Map();
|
|
2154
|
-
if (
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
} catch (error2) {
|
|
2160
|
-
console.error("Error calculating uptime:", error2);
|
|
2161
|
-
}
|
|
2237
|
+
if (companyId) {
|
|
2238
|
+
try {
|
|
2239
|
+
uptimeMap = await this.calculateWorkspaceUptime(companyId);
|
|
2240
|
+
} catch (error2) {
|
|
2241
|
+
console.error("Error calculating uptime:", error2);
|
|
2162
2242
|
}
|
|
2163
2243
|
}
|
|
2164
2244
|
const dataWithUptime = processedData.map((workspace) => {
|
|
@@ -2174,16 +2254,29 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2174
2254
|
});
|
|
2175
2255
|
let filteredData = dataWithUptime;
|
|
2176
2256
|
try {
|
|
2177
|
-
const
|
|
2257
|
+
const enabledQuery = supabase.from("workspaces").select("workspace_id, display_name, line_id").eq("enable", true);
|
|
2258
|
+
if (options.lineId) {
|
|
2259
|
+
enabledQuery.eq("line_id", options.lineId);
|
|
2260
|
+
}
|
|
2261
|
+
const { data: enabledWorkspaces, error: workspaceError } = await enabledQuery;
|
|
2178
2262
|
if (!workspaceError && enabledWorkspaces && enabledWorkspaces.length > 0) {
|
|
2179
|
-
const
|
|
2263
|
+
const enabledByLineAndId = /* @__PURE__ */ new Set();
|
|
2264
|
+
const enabledByLineAndName = /* @__PURE__ */ new Set();
|
|
2180
2265
|
enabledWorkspaces.forEach((w) => {
|
|
2181
|
-
|
|
2182
|
-
|
|
2266
|
+
const lineKey = w.line_id ? String(w.line_id) : "";
|
|
2267
|
+
const idKey = w.workspace_id ? String(w.workspace_id) : "";
|
|
2268
|
+
const nameKey = w.display_name ? String(w.display_name) : "";
|
|
2269
|
+
if (lineKey && idKey) enabledByLineAndId.add(`${lineKey}::${idKey}`);
|
|
2270
|
+
if (lineKey && nameKey) enabledByLineAndName.add(`${lineKey}::${nameKey}`);
|
|
2183
2271
|
});
|
|
2184
2272
|
filteredData = filteredData.filter((item) => {
|
|
2185
|
-
const
|
|
2186
|
-
|
|
2273
|
+
const lineKey = item.line_id ? String(item.line_id) : "";
|
|
2274
|
+
if (!lineKey) return false;
|
|
2275
|
+
const idKey = item.workspace_id ? `${lineKey}::${item.workspace_id}` : "";
|
|
2276
|
+
const nameKey = item.workspace_display_name ? `${lineKey}::${item.workspace_display_name}` : "";
|
|
2277
|
+
if (idKey && enabledByLineAndId.has(idKey)) return true;
|
|
2278
|
+
if (nameKey && enabledByLineAndName.has(nameKey)) return true;
|
|
2279
|
+
return false;
|
|
2187
2280
|
});
|
|
2188
2281
|
} else if (!workspaceError && enabledWorkspaces && enabledWorkspaces.length === 0) {
|
|
2189
2282
|
return [];
|
|
@@ -2221,6 +2314,127 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2221
2314
|
}
|
|
2222
2315
|
return filteredData;
|
|
2223
2316
|
}
|
|
2317
|
+
async getWorkspaceUptimeTimeline(workspaceId, companyId) {
|
|
2318
|
+
if (!workspaceId) {
|
|
2319
|
+
throw new Error("workspaceId is required to fetch uptime timeline");
|
|
2320
|
+
}
|
|
2321
|
+
if (!companyId) {
|
|
2322
|
+
throw new Error("companyId is required to fetch uptime timeline");
|
|
2323
|
+
}
|
|
2324
|
+
const supabase = _getSupabaseInstance();
|
|
2325
|
+
if (!supabase) throw new Error("Supabase client not initialized");
|
|
2326
|
+
const dashboardConfig = _getDashboardConfigInstance();
|
|
2327
|
+
const timezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
|
|
2328
|
+
const shiftConfig = dashboardConfig?.shiftConfig;
|
|
2329
|
+
const {
|
|
2330
|
+
shiftId,
|
|
2331
|
+
shiftLabel,
|
|
2332
|
+
shiftStartDate,
|
|
2333
|
+
shiftEndDate,
|
|
2334
|
+
totalMinutes,
|
|
2335
|
+
completedMinutes,
|
|
2336
|
+
pendingMinutes,
|
|
2337
|
+
date
|
|
2338
|
+
} = this.getShiftTiming(timezone, shiftConfig);
|
|
2339
|
+
const tableName = `performance_metrics_${companyId.replace(/-/g, "_")}`;
|
|
2340
|
+
const { data, error } = await supabase.from(tableName).select("workspace_id, output_hourly, output_array").eq("workspace_id", workspaceId).eq("date", date).eq("shift_id", shiftId).limit(1);
|
|
2341
|
+
if (error) {
|
|
2342
|
+
console.error("Error fetching uptime timeline metrics:", error);
|
|
2343
|
+
throw error;
|
|
2344
|
+
}
|
|
2345
|
+
const record = Array.isArray(data) && data.length > 0 ? data[0] : null;
|
|
2346
|
+
const outputHourly = this.normalizeOutputHourly(record?.output_hourly || {});
|
|
2347
|
+
const outputArray = Array.isArray(record?.output_array) ? record.output_array : [];
|
|
2348
|
+
const points = [];
|
|
2349
|
+
let uptimeMinutes = 0;
|
|
2350
|
+
let downtimeMinutes = 0;
|
|
2351
|
+
const MIN_DOWNTIME_MINUTES = 2;
|
|
2352
|
+
for (let minuteIndex = 0; minuteIndex < totalMinutes; minuteIndex++) {
|
|
2353
|
+
const minuteDate = addMinutes(shiftStartDate, minuteIndex);
|
|
2354
|
+
const timestamp = formatInTimeZone(minuteDate, timezone, "yyyy-MM-dd'T'HH:mm:ssXXX");
|
|
2355
|
+
let status;
|
|
2356
|
+
if (minuteIndex < completedMinutes) {
|
|
2357
|
+
status = this.deriveStatusForMinute(
|
|
2358
|
+
minuteIndex,
|
|
2359
|
+
minuteDate,
|
|
2360
|
+
outputHourly,
|
|
2361
|
+
outputArray,
|
|
2362
|
+
timezone
|
|
2363
|
+
);
|
|
2364
|
+
if (status === "up") {
|
|
2365
|
+
uptimeMinutes += 1;
|
|
2366
|
+
} else {
|
|
2367
|
+
downtimeMinutes += 1;
|
|
2368
|
+
}
|
|
2369
|
+
} else {
|
|
2370
|
+
status = "pending";
|
|
2371
|
+
}
|
|
2372
|
+
points.push({
|
|
2373
|
+
minuteIndex,
|
|
2374
|
+
timestamp,
|
|
2375
|
+
status
|
|
2376
|
+
});
|
|
2377
|
+
}
|
|
2378
|
+
const downtimeSegments = [];
|
|
2379
|
+
let currentSegmentStart = null;
|
|
2380
|
+
const pushSegment = (startIndex, endIndex) => {
|
|
2381
|
+
if (endIndex <= startIndex) return;
|
|
2382
|
+
const segmentStartDate = addMinutes(shiftStartDate, startIndex);
|
|
2383
|
+
const segmentEndDate = addMinutes(shiftStartDate, endIndex);
|
|
2384
|
+
downtimeSegments.push({
|
|
2385
|
+
startMinuteIndex: startIndex,
|
|
2386
|
+
endMinuteIndex: endIndex,
|
|
2387
|
+
startTime: formatInTimeZone(segmentStartDate, timezone, "yyyy-MM-dd'T'HH:mm:ssXXX"),
|
|
2388
|
+
endTime: formatInTimeZone(segmentEndDate, timezone, "yyyy-MM-dd'T'HH:mm:ssXXX"),
|
|
2389
|
+
durationMinutes: endIndex - startIndex
|
|
2390
|
+
});
|
|
2391
|
+
};
|
|
2392
|
+
for (let i = 0; i < completedMinutes; i++) {
|
|
2393
|
+
const point = points[i];
|
|
2394
|
+
if (point.status === "down") {
|
|
2395
|
+
if (currentSegmentStart === null) {
|
|
2396
|
+
currentSegmentStart = i;
|
|
2397
|
+
}
|
|
2398
|
+
} else if (currentSegmentStart !== null) {
|
|
2399
|
+
pushSegment(currentSegmentStart, i);
|
|
2400
|
+
currentSegmentStart = null;
|
|
2401
|
+
}
|
|
2402
|
+
}
|
|
2403
|
+
if (currentSegmentStart !== null) {
|
|
2404
|
+
pushSegment(currentSegmentStart, completedMinutes);
|
|
2405
|
+
}
|
|
2406
|
+
const filteredSegments = [];
|
|
2407
|
+
downtimeSegments.forEach((segment) => {
|
|
2408
|
+
if (segment.durationMinutes >= MIN_DOWNTIME_MINUTES) {
|
|
2409
|
+
filteredSegments.push(segment);
|
|
2410
|
+
} else {
|
|
2411
|
+
for (let i = segment.startMinuteIndex; i < segment.endMinuteIndex; i++) {
|
|
2412
|
+
if (points[i] && points[i].status === "down") {
|
|
2413
|
+
points[i].status = "up";
|
|
2414
|
+
downtimeMinutes = Math.max(0, downtimeMinutes - 1);
|
|
2415
|
+
uptimeMinutes += 1;
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
});
|
|
2420
|
+
const completedWindow = Math.max(1, uptimeMinutes + downtimeMinutes);
|
|
2421
|
+
const uptimePercentage = completedMinutes > 0 ? Number((uptimeMinutes / completedWindow * 100).toFixed(1)) : 100;
|
|
2422
|
+
return {
|
|
2423
|
+
shiftId,
|
|
2424
|
+
shiftLabel,
|
|
2425
|
+
shiftStart: formatInTimeZone(shiftStartDate, timezone, "yyyy-MM-dd'T'HH:mm:ssXXX"),
|
|
2426
|
+
shiftEnd: formatInTimeZone(shiftEndDate, timezone, "yyyy-MM-dd'T'HH:mm:ssXXX"),
|
|
2427
|
+
totalMinutes,
|
|
2428
|
+
completedMinutes,
|
|
2429
|
+
uptimeMinutes,
|
|
2430
|
+
downtimeMinutes,
|
|
2431
|
+
pendingMinutes,
|
|
2432
|
+
uptimePercentage,
|
|
2433
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2434
|
+
points,
|
|
2435
|
+
downtimeSegments: filteredSegments
|
|
2436
|
+
};
|
|
2437
|
+
}
|
|
2224
2438
|
async getWorkspaceHealthById(workspaceId) {
|
|
2225
2439
|
const cacheKey = `health-${workspaceId}`;
|
|
2226
2440
|
const cached = this.getFromCache(cacheKey);
|
|
@@ -2358,145 +2572,63 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2358
2572
|
const dashboardConfig = _getDashboardConfigInstance();
|
|
2359
2573
|
const timezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
|
|
2360
2574
|
const shiftConfig = dashboardConfig?.shiftConfig;
|
|
2361
|
-
const
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
const dayShiftStart = shiftConfig?.dayShift?.startTime || "08:00";
|
|
2368
|
-
const dayShiftEnd = shiftConfig?.dayShift?.endTime || "19:30";
|
|
2369
|
-
const nightShiftStart = shiftConfig?.nightShift?.startTime || "19:30";
|
|
2370
|
-
const nightShiftEnd = shiftConfig?.nightShift?.endTime || "06:00";
|
|
2371
|
-
const parseShiftTime = (timeStr) => {
|
|
2372
|
-
const [hour, minute] = timeStr.split(":").map(Number);
|
|
2373
|
-
return { hour, minute };
|
|
2374
|
-
};
|
|
2375
|
-
let shiftStart, shiftEnd;
|
|
2376
|
-
if (currentShiftId === 0) {
|
|
2377
|
-
shiftStart = parseShiftTime(dayShiftStart);
|
|
2378
|
-
shiftEnd = parseShiftTime(dayShiftEnd);
|
|
2379
|
-
} else {
|
|
2380
|
-
shiftStart = parseShiftTime(nightShiftStart);
|
|
2381
|
-
shiftEnd = parseShiftTime(nightShiftEnd);
|
|
2382
|
-
}
|
|
2383
|
-
let elapsedMinutes = 0;
|
|
2384
|
-
if (currentShiftId === 0) {
|
|
2385
|
-
const shiftStartTotalMinutes = shiftStart.hour * 60 + shiftStart.minute;
|
|
2386
|
-
const currentTotalMinutes = currentHour * 60 + currentMinute;
|
|
2387
|
-
const shiftEndTotalMinutes = shiftEnd.hour * 60 + shiftEnd.minute;
|
|
2388
|
-
if (currentTotalMinutes >= shiftStartTotalMinutes && currentTotalMinutes < shiftEndTotalMinutes) {
|
|
2389
|
-
elapsedMinutes = currentTotalMinutes - shiftStartTotalMinutes;
|
|
2390
|
-
} else if (currentTotalMinutes >= shiftEndTotalMinutes) {
|
|
2391
|
-
elapsedMinutes = shiftEndTotalMinutes - shiftStartTotalMinutes;
|
|
2392
|
-
}
|
|
2393
|
-
} else {
|
|
2394
|
-
const shiftStartTotalMinutes = shiftStart.hour * 60 + shiftStart.minute;
|
|
2395
|
-
const currentTotalMinutes = currentHour * 60 + currentMinute;
|
|
2396
|
-
const shiftEndTotalMinutes = shiftEnd.hour * 60 + shiftEnd.minute;
|
|
2397
|
-
if (currentHour >= shiftStart.hour || currentHour < shiftEnd.hour) {
|
|
2398
|
-
if (currentHour >= shiftStart.hour) {
|
|
2399
|
-
elapsedMinutes = currentTotalMinutes - shiftStartTotalMinutes;
|
|
2400
|
-
} else {
|
|
2401
|
-
elapsedMinutes = 24 * 60 - shiftStartTotalMinutes + currentTotalMinutes;
|
|
2402
|
-
}
|
|
2403
|
-
if (currentHour >= shiftEnd.hour && currentTotalMinutes >= shiftEndTotalMinutes) {
|
|
2404
|
-
const totalShiftMinutes = 24 * 60 - shiftStartTotalMinutes + shiftEndTotalMinutes;
|
|
2405
|
-
elapsedMinutes = Math.min(elapsedMinutes, totalShiftMinutes);
|
|
2406
|
-
}
|
|
2407
|
-
}
|
|
2408
|
-
}
|
|
2575
|
+
const {
|
|
2576
|
+
shiftId,
|
|
2577
|
+
date,
|
|
2578
|
+
shiftStartDate,
|
|
2579
|
+
completedMinutes
|
|
2580
|
+
} = this.getShiftTiming(timezone, shiftConfig);
|
|
2409
2581
|
const tableName = `performance_metrics_${companyId.replace(/-/g, "_")}`;
|
|
2410
2582
|
try {
|
|
2411
|
-
const { data: queryData, error } = await supabase.from(tableName).select("workspace_id, workspace_display_name, output_hourly").eq("date",
|
|
2583
|
+
const { data: queryData, error } = await supabase.from(tableName).select("workspace_id, workspace_display_name, output_hourly, output_array").eq("date", date).eq("shift_id", shiftId);
|
|
2412
2584
|
if (error) {
|
|
2413
2585
|
console.error("Error fetching performance metrics:", error);
|
|
2414
2586
|
return /* @__PURE__ */ new Map();
|
|
2415
2587
|
}
|
|
2416
2588
|
const uptimeMap = /* @__PURE__ */ new Map();
|
|
2417
2589
|
for (const record of queryData || []) {
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
} else if (hourIndex < hoursElapsed - 1) {
|
|
2436
|
-
const currentHourData = outputHourly[actualHour.toString()] || [];
|
|
2437
|
-
const nextHour = (actualHour + 1) % 24;
|
|
2438
|
-
const nextHourData = outputHourly[nextHour.toString()] || [];
|
|
2439
|
-
hourData = [
|
|
2440
|
-
...Array.isArray(currentHourData) ? currentHourData.slice(shiftStart.minute) : [],
|
|
2441
|
-
...Array.isArray(nextHourData) ? nextHourData.slice(0, shiftStart.minute) : []
|
|
2442
|
-
];
|
|
2443
|
-
} else {
|
|
2444
|
-
const isLastHourPartial = hourIndex === hoursElapsed - 1 && elapsedMinutes % 60 > 0;
|
|
2445
|
-
if (isLastHourPartial) {
|
|
2446
|
-
minutesInThisHour = elapsedMinutes % 60;
|
|
2447
|
-
const currentHourData = outputHourly[actualHour.toString()] || [];
|
|
2448
|
-
if (shiftStart.minute > 0) {
|
|
2449
|
-
const nextHour = (actualHour + 1) % 24;
|
|
2450
|
-
const nextHourData = outputHourly[nextHour.toString()] || [];
|
|
2451
|
-
const firstPart = Array.isArray(currentHourData) ? currentHourData.slice(shiftStart.minute) : [];
|
|
2452
|
-
const secondPart = Array.isArray(nextHourData) ? nextHourData.slice(0, Math.min(shiftStart.minute, minutesInThisHour)) : [];
|
|
2453
|
-
hourData = [...firstPart, ...secondPart].slice(0, minutesInThisHour);
|
|
2454
|
-
} else {
|
|
2455
|
-
hourData = Array.isArray(currentHourData) ? currentHourData.slice(0, minutesInThisHour) : [];
|
|
2456
|
-
}
|
|
2457
|
-
} else {
|
|
2458
|
-
const currentHourData = outputHourly[actualHour.toString()] || [];
|
|
2459
|
-
const nextHour = (actualHour + 1) % 24;
|
|
2460
|
-
const nextHourData = outputHourly[nextHour.toString()] || [];
|
|
2461
|
-
hourData = [
|
|
2462
|
-
...Array.isArray(currentHourData) ? currentHourData.slice(shiftStart.minute) : [],
|
|
2463
|
-
...Array.isArray(nextHourData) ? nextHourData.slice(0, shiftStart.minute) : []
|
|
2464
|
-
];
|
|
2465
|
-
}
|
|
2466
|
-
}
|
|
2590
|
+
const outputHourly = this.normalizeOutputHourly(record.output_hourly || {});
|
|
2591
|
+
const outputArray = Array.isArray(record.output_array) ? record.output_array : [];
|
|
2592
|
+
let uptimeMinutes = 0;
|
|
2593
|
+
let downtimeMinutes = 0;
|
|
2594
|
+
const MIN_DOWNTIME_MINUTES = 2;
|
|
2595
|
+
let currentDownRun = 0;
|
|
2596
|
+
for (let minuteIndex = 0; minuteIndex < completedMinutes; minuteIndex++) {
|
|
2597
|
+
const minuteDate = addMinutes(shiftStartDate, minuteIndex);
|
|
2598
|
+
const status = this.deriveStatusForMinute(
|
|
2599
|
+
minuteIndex,
|
|
2600
|
+
minuteDate,
|
|
2601
|
+
outputHourly,
|
|
2602
|
+
outputArray,
|
|
2603
|
+
timezone
|
|
2604
|
+
);
|
|
2605
|
+
if (status === "down") {
|
|
2606
|
+
currentDownRun += 1;
|
|
2467
2607
|
} else {
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
hourData = Array.isArray(hourData) ? hourData.slice(0, minutesInThisHour) : [];
|
|
2608
|
+
if (currentDownRun > 0) {
|
|
2609
|
+
if (currentDownRun >= MIN_DOWNTIME_MINUTES) {
|
|
2610
|
+
downtimeMinutes += currentDownRun;
|
|
2611
|
+
} else {
|
|
2612
|
+
uptimeMinutes += currentDownRun;
|
|
2474
2613
|
}
|
|
2614
|
+
currentDownRun = 0;
|
|
2475
2615
|
}
|
|
2616
|
+
uptimeMinutes += 1;
|
|
2476
2617
|
}
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
actualMinutes += minutesInThisHour;
|
|
2482
|
-
} else {
|
|
2483
|
-
const uptimeCount = hourData.filter((val) => val !== "x").length;
|
|
2484
|
-
actualMinutes += Math.min(uptimeCount, minutesInThisHour);
|
|
2485
|
-
}
|
|
2618
|
+
}
|
|
2619
|
+
if (currentDownRun > 0) {
|
|
2620
|
+
if (currentDownRun >= MIN_DOWNTIME_MINUTES) {
|
|
2621
|
+
downtimeMinutes += currentDownRun;
|
|
2486
2622
|
} else {
|
|
2487
|
-
|
|
2488
|
-
if (arrayLength >= Math.min(58, minutesInThisHour - 2)) {
|
|
2489
|
-
actualMinutes += minutesInThisHour;
|
|
2490
|
-
} else {
|
|
2491
|
-
actualMinutes += Math.min(arrayLength, minutesInThisHour);
|
|
2492
|
-
}
|
|
2623
|
+
uptimeMinutes += currentDownRun;
|
|
2493
2624
|
}
|
|
2494
|
-
|
|
2625
|
+
currentDownRun = 0;
|
|
2495
2626
|
}
|
|
2496
|
-
const
|
|
2627
|
+
const completedWindow = uptimeMinutes + downtimeMinutes;
|
|
2628
|
+
const percentage = completedWindow > 0 ? Number((uptimeMinutes / completedWindow * 100).toFixed(1)) : 100;
|
|
2497
2629
|
uptimeMap.set(record.workspace_id, {
|
|
2498
|
-
expectedMinutes:
|
|
2499
|
-
actualMinutes,
|
|
2630
|
+
expectedMinutes: completedMinutes,
|
|
2631
|
+
actualMinutes: uptimeMinutes,
|
|
2500
2632
|
percentage,
|
|
2501
2633
|
lastCalculated: (/* @__PURE__ */ new Date()).toISOString()
|
|
2502
2634
|
});
|
|
@@ -10868,6 +11000,65 @@ var useWorkspaceHealthStatus = (workspaceId) => {
|
|
|
10868
11000
|
refetch: fetchHealthStatus
|
|
10869
11001
|
};
|
|
10870
11002
|
};
|
|
11003
|
+
var useWorkspaceUptimeTimeline = (options) => {
|
|
11004
|
+
const {
|
|
11005
|
+
workspaceId,
|
|
11006
|
+
companyId,
|
|
11007
|
+
enabled = true,
|
|
11008
|
+
refreshInterval
|
|
11009
|
+
} = options;
|
|
11010
|
+
const [timeline, setTimeline] = useState(null);
|
|
11011
|
+
const [loading, setLoading] = useState(false);
|
|
11012
|
+
const [error, setError] = useState(null);
|
|
11013
|
+
const isFetchingRef = useRef(false);
|
|
11014
|
+
const intervalRef = useRef(null);
|
|
11015
|
+
const fetchTimeline = useCallback(async () => {
|
|
11016
|
+
if (!enabled) return;
|
|
11017
|
+
if (!workspaceId || !companyId) {
|
|
11018
|
+
setTimeline(null);
|
|
11019
|
+
return;
|
|
11020
|
+
}
|
|
11021
|
+
if (isFetchingRef.current) return;
|
|
11022
|
+
try {
|
|
11023
|
+
isFetchingRef.current = true;
|
|
11024
|
+
setLoading(true);
|
|
11025
|
+
setError(null);
|
|
11026
|
+
const data = await workspaceHealthService.getWorkspaceUptimeTimeline(
|
|
11027
|
+
workspaceId,
|
|
11028
|
+
companyId
|
|
11029
|
+
);
|
|
11030
|
+
setTimeline(data);
|
|
11031
|
+
} catch (err) {
|
|
11032
|
+
console.error("[useWorkspaceUptimeTimeline] Failed to fetch timeline:", err);
|
|
11033
|
+
setError({ message: err?.message || "Failed to load uptime timeline", code: err?.code || "FETCH_ERROR" });
|
|
11034
|
+
} finally {
|
|
11035
|
+
setLoading(false);
|
|
11036
|
+
isFetchingRef.current = false;
|
|
11037
|
+
}
|
|
11038
|
+
}, [enabled, workspaceId, companyId]);
|
|
11039
|
+
useEffect(() => {
|
|
11040
|
+
fetchTimeline();
|
|
11041
|
+
}, [fetchTimeline]);
|
|
11042
|
+
useEffect(() => {
|
|
11043
|
+
if (!refreshInterval || refreshInterval <= 0 || !enabled) {
|
|
11044
|
+
return;
|
|
11045
|
+
}
|
|
11046
|
+
intervalRef.current = setInterval(() => {
|
|
11047
|
+
fetchTimeline();
|
|
11048
|
+
}, refreshInterval);
|
|
11049
|
+
return () => {
|
|
11050
|
+
if (intervalRef.current) {
|
|
11051
|
+
clearInterval(intervalRef.current);
|
|
11052
|
+
}
|
|
11053
|
+
};
|
|
11054
|
+
}, [refreshInterval, enabled, fetchTimeline]);
|
|
11055
|
+
return {
|
|
11056
|
+
timeline,
|
|
11057
|
+
loading,
|
|
11058
|
+
error,
|
|
11059
|
+
refetch: fetchTimeline
|
|
11060
|
+
};
|
|
11061
|
+
};
|
|
10871
11062
|
function useDateFormatter() {
|
|
10872
11063
|
const { defaultTimezone, defaultLocale, dateFormatOptions, timeFormatOptions, dateTimeFormatOptions } = useDateTimeConfig();
|
|
10873
11064
|
const formatDate = useCallback(
|
|
@@ -10883,7 +11074,7 @@ function useDateFormatter() {
|
|
|
10883
11074
|
},
|
|
10884
11075
|
[defaultTimezone, defaultLocale, dateFormatOptions]
|
|
10885
11076
|
);
|
|
10886
|
-
const
|
|
11077
|
+
const formatTime5 = useCallback(
|
|
10887
11078
|
(date, formatString) => {
|
|
10888
11079
|
const dateObj = typeof date === "string" ? parseISO(date) : date;
|
|
10889
11080
|
if (!isValid(dateObj)) return "Invalid Time";
|
|
@@ -10914,7 +11105,7 @@ function useDateFormatter() {
|
|
|
10914
11105
|
}, []);
|
|
10915
11106
|
return {
|
|
10916
11107
|
formatDate,
|
|
10917
|
-
formatTime:
|
|
11108
|
+
formatTime: formatTime5,
|
|
10918
11109
|
formatDateTime,
|
|
10919
11110
|
getNow,
|
|
10920
11111
|
timezone: defaultTimezone || "UTC",
|
|
@@ -23900,7 +24091,7 @@ var HourlyOutputChartComponent = ({
|
|
|
23900
24091
|
endHour = Math.floor(endDecimalHour) % 24;
|
|
23901
24092
|
endMinute = Math.round(endDecimalHour % 1 * 60);
|
|
23902
24093
|
}
|
|
23903
|
-
const
|
|
24094
|
+
const formatTime5 = (h, m) => {
|
|
23904
24095
|
const period = h >= 12 ? "PM" : "AM";
|
|
23905
24096
|
const hour12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
|
|
23906
24097
|
if (m === 0) {
|
|
@@ -23908,9 +24099,9 @@ var HourlyOutputChartComponent = ({
|
|
|
23908
24099
|
}
|
|
23909
24100
|
return `${hour12}:${m.toString().padStart(2, "0")}${period}`;
|
|
23910
24101
|
};
|
|
23911
|
-
return `${
|
|
24102
|
+
return `${formatTime5(startHour, startMinute)}-${formatTime5(endHour, endMinute)}`;
|
|
23912
24103
|
}, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
|
|
23913
|
-
const
|
|
24104
|
+
const formatTimeRange2 = React23__default.useCallback((hourIndex) => {
|
|
23914
24105
|
const isLastHour = hourIndex === SHIFT_DURATION - 1;
|
|
23915
24106
|
const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
|
|
23916
24107
|
const startHour = Math.floor(startDecimalHour) % 24;
|
|
@@ -23924,12 +24115,12 @@ var HourlyOutputChartComponent = ({
|
|
|
23924
24115
|
endHour = Math.floor(endDecimalHour) % 24;
|
|
23925
24116
|
endMinute = Math.round(endDecimalHour % 1 * 60);
|
|
23926
24117
|
}
|
|
23927
|
-
const
|
|
24118
|
+
const formatTime5 = (h, m) => {
|
|
23928
24119
|
const period = h >= 12 ? "PM" : "AM";
|
|
23929
24120
|
const hour12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
|
|
23930
24121
|
return `${hour12}:${m.toString().padStart(2, "0")} ${period}`;
|
|
23931
24122
|
};
|
|
23932
|
-
return `${
|
|
24123
|
+
return `${formatTime5(startHour, startMinute)} - ${formatTime5(endHour, endMinute)}`;
|
|
23933
24124
|
}, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
|
|
23934
24125
|
const chartData = React23__default.useMemo(() => {
|
|
23935
24126
|
return Array.from({ length: SHIFT_DURATION }, (_, i) => {
|
|
@@ -23990,7 +24181,7 @@ var HourlyOutputChartComponent = ({
|
|
|
23990
24181
|
idleMinutes = idleArray.filter((val) => val === "1" || val === 1).length;
|
|
23991
24182
|
return {
|
|
23992
24183
|
hour: formatHour(i),
|
|
23993
|
-
timeRange:
|
|
24184
|
+
timeRange: formatTimeRange2(i),
|
|
23994
24185
|
output: animatedData[i] || 0,
|
|
23995
24186
|
originalOutput: data[i] || 0,
|
|
23996
24187
|
// Keep original data for labels
|
|
@@ -23999,7 +24190,7 @@ var HourlyOutputChartComponent = ({
|
|
|
23999
24190
|
idleArray
|
|
24000
24191
|
};
|
|
24001
24192
|
});
|
|
24002
|
-
}, [animatedData, data, pphThreshold, idleTimeHourly, shiftStartTime.hour, shiftStartTime.minute, shiftEndTime, formatHour,
|
|
24193
|
+
}, [animatedData, data, pphThreshold, idleTimeHourly, shiftStartTime.hour, shiftStartTime.minute, shiftEndTime, formatHour, formatTimeRange2, SHIFT_DURATION]);
|
|
24003
24194
|
const IdleBar = React23__default.useMemo(() => {
|
|
24004
24195
|
if (!idleBarState.visible) return null;
|
|
24005
24196
|
return /* @__PURE__ */ jsx(
|
|
@@ -25100,7 +25291,7 @@ var SOPComplianceChart = ({
|
|
|
25100
25291
|
}
|
|
25101
25292
|
};
|
|
25102
25293
|
}, [data, animateToNewData, mockData]);
|
|
25103
|
-
const
|
|
25294
|
+
const formatTime5 = (minuteIndex) => {
|
|
25104
25295
|
const totalMinutes = shiftStartHour * 60 + minuteIndex;
|
|
25105
25296
|
const hours = Math.floor(totalMinutes / 60) % 24;
|
|
25106
25297
|
const minutes = totalMinutes % 60;
|
|
@@ -25112,7 +25303,7 @@ var SOPComplianceChart = ({
|
|
|
25112
25303
|
const hasDataForMinute = index < animatedData.length - 10;
|
|
25113
25304
|
return {
|
|
25114
25305
|
minute: index,
|
|
25115
|
-
time:
|
|
25306
|
+
time: formatTime5(index),
|
|
25116
25307
|
compliance: hasDataForMinute ? animatedData[index] : null
|
|
25117
25308
|
};
|
|
25118
25309
|
});
|
|
@@ -25546,7 +25737,7 @@ var DateTimeDisplay = ({
|
|
|
25546
25737
|
const {
|
|
25547
25738
|
defaultTimezone
|
|
25548
25739
|
} = useDateTimeConfig();
|
|
25549
|
-
const { formatDate, formatTime:
|
|
25740
|
+
const { formatDate, formatTime: formatTime5 } = useDateFormatter();
|
|
25550
25741
|
const [now2, setNow] = useState(() => getCurrentTimeInZone(defaultTimezone || "UTC"));
|
|
25551
25742
|
useEffect(() => {
|
|
25552
25743
|
const timerId = setInterval(() => {
|
|
@@ -25558,7 +25749,7 @@ var DateTimeDisplay = ({
|
|
|
25558
25749
|
return null;
|
|
25559
25750
|
}
|
|
25560
25751
|
const formattedDate = showDate ? formatDate(now2) : "";
|
|
25561
|
-
const formattedTime = showTime ?
|
|
25752
|
+
const formattedTime = showTime ? formatTime5(now2) : "";
|
|
25562
25753
|
return /* @__PURE__ */ jsxs("div", { className: clsx_default("flex items-center space-x-2 text-sm text-gray-700 dark:text-gray-300", className), children: [
|
|
25563
25754
|
showDate && /* @__PURE__ */ jsx("span", { className: "date-display", "aria-label": `Current date: ${formattedDate}`, children: formattedDate }),
|
|
25564
25755
|
showDate && showTime && formattedDate && formattedTime && /* @__PURE__ */ jsx("span", { className: "separator", "aria-hidden": "true", children: "|" }),
|
|
@@ -25722,7 +25913,7 @@ var BreakNotificationPopup = ({
|
|
|
25722
25913
|
const handlePrevious = () => {
|
|
25723
25914
|
setCurrentIndex((prev) => (prev - 1 + visibleBreaks.length) % visibleBreaks.length);
|
|
25724
25915
|
};
|
|
25725
|
-
const
|
|
25916
|
+
const formatTime5 = (minutes) => {
|
|
25726
25917
|
const hours = Math.floor(minutes / 60);
|
|
25727
25918
|
const mins = minutes % 60;
|
|
25728
25919
|
if (hours > 0) {
|
|
@@ -25796,9 +25987,9 @@ var BreakNotificationPopup = ({
|
|
|
25796
25987
|
formatTo12Hour(currentBreak.endTime)
|
|
25797
25988
|
] }),
|
|
25798
25989
|
/* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 mb-2", children: [
|
|
25799
|
-
|
|
25990
|
+
formatTime5(currentBreak.elapsedMinutes),
|
|
25800
25991
|
" elapsed of ",
|
|
25801
|
-
|
|
25992
|
+
formatTime5(currentBreak.duration),
|
|
25802
25993
|
" total"
|
|
25803
25994
|
] }),
|
|
25804
25995
|
/* @__PURE__ */ jsx("div", { className: "w-full bg-gray-200 rounded-full h-1.5", children: /* @__PURE__ */ jsx(
|
|
@@ -31464,7 +31655,7 @@ function DiagnosisVideoModal({
|
|
|
31464
31655
|
}
|
|
31465
31656
|
loadClip();
|
|
31466
31657
|
}, [clipId, supabase, transformPlaylistUrls]);
|
|
31467
|
-
const
|
|
31658
|
+
const formatTime5 = (seconds) => {
|
|
31468
31659
|
const mins = Math.floor(seconds / 60);
|
|
31469
31660
|
const secs = Math.floor(seconds % 60);
|
|
31470
31661
|
return `${mins}:${secs.toString().padStart(2, "0")}`;
|
|
@@ -31656,9 +31847,9 @@ function DiagnosisVideoModal({
|
|
|
31656
31847
|
}
|
|
31657
31848
|
),
|
|
31658
31849
|
/* @__PURE__ */ jsxs("span", { className: "text-sm font-medium", children: [
|
|
31659
|
-
|
|
31850
|
+
formatTime5(currentTime),
|
|
31660
31851
|
" / ",
|
|
31661
|
-
|
|
31852
|
+
formatTime5(duration)
|
|
31662
31853
|
] }),
|
|
31663
31854
|
/* @__PURE__ */ jsx(
|
|
31664
31855
|
"input",
|
|
@@ -33478,45 +33669,35 @@ var LinePdfGenerator = ({
|
|
|
33478
33669
|
const doc = new jsPDF$1();
|
|
33479
33670
|
const pageHeight = doc.internal.pageSize.height;
|
|
33480
33671
|
const addHeaderPage1 = () => {
|
|
33481
|
-
doc.setFontSize(
|
|
33672
|
+
doc.setFontSize(14);
|
|
33482
33673
|
doc.setFont("helvetica", "bold");
|
|
33483
|
-
doc.setTextColor(
|
|
33674
|
+
doc.setTextColor(50, 50, 50);
|
|
33484
33675
|
doc.text("OPTIFYE.AI", 20, 15);
|
|
33485
|
-
doc.setFontSize(
|
|
33676
|
+
doc.setFontSize(9);
|
|
33486
33677
|
doc.setFont("helvetica", "normal");
|
|
33487
33678
|
doc.setTextColor(100, 100, 100);
|
|
33488
|
-
const
|
|
33489
|
-
const
|
|
33490
|
-
doc.text(
|
|
33491
|
-
doc.setDrawColor(
|
|
33492
|
-
doc.setLineWidth(0.
|
|
33679
|
+
const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: "Asia/Kolkata" })}`;
|
|
33680
|
+
const generatedTextWidth = doc.getStringUnitWidth(generatedText) * 9 / doc.internal.scaleFactor;
|
|
33681
|
+
doc.text(generatedText, doc.internal.pageSize.width - 20 - generatedTextWidth, 15);
|
|
33682
|
+
doc.setDrawColor(200, 200, 200);
|
|
33683
|
+
doc.setLineWidth(0.5);
|
|
33493
33684
|
doc.line(20, 20, 190, 20);
|
|
33494
33685
|
};
|
|
33495
33686
|
const addHeaderPage2 = () => {
|
|
33496
|
-
doc.setFontSize(
|
|
33687
|
+
doc.setFontSize(14);
|
|
33497
33688
|
doc.setFont("helvetica", "bold");
|
|
33498
|
-
doc.setTextColor(
|
|
33689
|
+
doc.setTextColor(50, 50, 50);
|
|
33499
33690
|
doc.text("OPTIFYE.AI", 20, 15);
|
|
33500
|
-
doc.setFontSize(
|
|
33691
|
+
doc.setFontSize(9);
|
|
33501
33692
|
doc.setFont("helvetica", "normal");
|
|
33502
33693
|
doc.setTextColor(100, 100, 100);
|
|
33503
|
-
const reportText = "REAL-TIME PERFORMANCE REPORT";
|
|
33504
|
-
const reportTextWidth = doc.getStringUnitWidth(reportText) * 10 / doc.internal.scaleFactor;
|
|
33505
|
-
doc.text(reportText, doc.internal.pageSize.width - 20 - reportTextWidth, 15);
|
|
33506
|
-
doc.text("Page 2", doc.internal.pageSize.width - 30, pageHeight - 15);
|
|
33507
|
-
doc.setDrawColor(220, 220, 220);
|
|
33508
|
-
doc.setLineWidth(0.3);
|
|
33509
|
-
doc.line(20, 20, 190, 20);
|
|
33510
|
-
return 35;
|
|
33511
|
-
};
|
|
33512
|
-
const addFooter = (pageNum) => {
|
|
33513
|
-
doc.setFontSize(9);
|
|
33514
|
-
doc.setTextColor(130, 130, 130);
|
|
33515
33694
|
const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: "Asia/Kolkata" })}`;
|
|
33516
|
-
doc.
|
|
33517
|
-
|
|
33518
|
-
|
|
33519
|
-
|
|
33695
|
+
const generatedTextWidth = doc.getStringUnitWidth(generatedText) * 9 / doc.internal.scaleFactor;
|
|
33696
|
+
doc.text(generatedText, doc.internal.pageSize.width - 20 - generatedTextWidth, 15);
|
|
33697
|
+
doc.setDrawColor(200, 200, 200);
|
|
33698
|
+
doc.setLineWidth(0.5);
|
|
33699
|
+
doc.line(20, 20, 190, 20);
|
|
33700
|
+
return 30;
|
|
33520
33701
|
};
|
|
33521
33702
|
addHeaderPage1();
|
|
33522
33703
|
doc.setFontSize(26);
|
|
@@ -33562,37 +33743,47 @@ var LinePdfGenerator = ({
|
|
|
33562
33743
|
doc.setDrawColor(200, 200, 200);
|
|
33563
33744
|
doc.setLineWidth(0.5);
|
|
33564
33745
|
doc.line(20, 53, 190, 53);
|
|
33565
|
-
|
|
33746
|
+
const perfOverviewStartY = 58;
|
|
33747
|
+
doc.setFillColor(245, 245, 245);
|
|
33748
|
+
doc.roundedRect(15, perfOverviewStartY, 180, 50, 3, 3, "F");
|
|
33749
|
+
doc.setFontSize(18);
|
|
33566
33750
|
doc.setFont("helvetica", "bold");
|
|
33567
|
-
doc.setTextColor(
|
|
33568
|
-
doc.text("Line Performance Overview", 20,
|
|
33751
|
+
doc.setTextColor(40, 40, 40);
|
|
33752
|
+
doc.text("Line Performance Overview", 20, 68);
|
|
33569
33753
|
doc.setTextColor(0, 0, 0);
|
|
33570
33754
|
const createKPIBox = (y) => {
|
|
33571
|
-
doc.setFillColor(
|
|
33572
|
-
doc.roundedRect(22, y - 7, 165, 12,
|
|
33755
|
+
doc.setFillColor(255, 255, 255);
|
|
33756
|
+
doc.roundedRect(22, y - 7, 165, 12, 2, 2, "F");
|
|
33757
|
+
doc.setDrawColor(230, 230, 230);
|
|
33758
|
+
doc.setLineWidth(0.2);
|
|
33759
|
+
doc.roundedRect(22, y - 7, 165, 12, 2, 2, "S");
|
|
33573
33760
|
};
|
|
33574
|
-
|
|
33575
|
-
|
|
33761
|
+
const kpiStartY = 80;
|
|
33762
|
+
const kpiSpacing = 10;
|
|
33763
|
+
createKPIBox(kpiStartY);
|
|
33764
|
+
doc.setFontSize(11);
|
|
33576
33765
|
doc.setFont("helvetica", "normal");
|
|
33577
|
-
doc.text("Output:", 25,
|
|
33766
|
+
doc.text("Output:", 25, kpiStartY);
|
|
33578
33767
|
doc.setFont("helvetica", "bold");
|
|
33579
|
-
doc.text(`${lineInfo.metrics.current_output} / ${lineInfo.metrics.line_threshold}`, 120,
|
|
33580
|
-
createKPIBox(
|
|
33768
|
+
doc.text(`${lineInfo.metrics.current_output} / ${lineInfo.metrics.line_threshold}`, 120, kpiStartY);
|
|
33769
|
+
createKPIBox(kpiStartY + kpiSpacing);
|
|
33581
33770
|
doc.setFont("helvetica", "normal");
|
|
33582
|
-
doc.text("Underperforming Workspaces:", 25,
|
|
33771
|
+
doc.text("Underperforming Workspaces:", 25, kpiStartY + kpiSpacing);
|
|
33583
33772
|
doc.setFont("helvetica", "bold");
|
|
33584
|
-
doc.text(`${lineInfo.metrics.underperforming_workspaces} / ${lineInfo.metrics.total_workspaces}`, 120,
|
|
33585
|
-
createKPIBox(
|
|
33773
|
+
doc.text(`${lineInfo.metrics.underperforming_workspaces} / ${lineInfo.metrics.total_workspaces}`, 120, kpiStartY + kpiSpacing);
|
|
33774
|
+
createKPIBox(kpiStartY + kpiSpacing * 2);
|
|
33586
33775
|
doc.setFont("helvetica", "normal");
|
|
33587
|
-
doc.text("Average Efficiency:", 25,
|
|
33776
|
+
doc.text("Average Efficiency:", 25, kpiStartY + kpiSpacing * 2);
|
|
33588
33777
|
doc.setFont("helvetica", "bold");
|
|
33589
|
-
doc.text(`${lineInfo.metrics.avg_efficiency.toFixed(1)}%`, 120,
|
|
33590
|
-
doc.setDrawColor(
|
|
33591
|
-
doc.
|
|
33592
|
-
doc.
|
|
33778
|
+
doc.text(`${lineInfo.metrics.avg_efficiency.toFixed(1)}%`, 120, kpiStartY + kpiSpacing * 2);
|
|
33779
|
+
doc.setDrawColor(180, 180, 180);
|
|
33780
|
+
doc.setLineWidth(0.8);
|
|
33781
|
+
doc.line(20, 118, 190, 118);
|
|
33782
|
+
const hourlyOverviewStartY = 123;
|
|
33783
|
+
doc.setFontSize(18);
|
|
33593
33784
|
doc.setFont("helvetica", "bold");
|
|
33594
|
-
doc.setTextColor(
|
|
33595
|
-
doc.text("Hourly Output Overview", 20,
|
|
33785
|
+
doc.setTextColor(40, 40, 40);
|
|
33786
|
+
doc.text("Hourly Output Overview", 20, 133);
|
|
33596
33787
|
doc.setTextColor(0, 0, 0);
|
|
33597
33788
|
const getHourlyTimeRanges = (startTimeStr, endTimeStr) => {
|
|
33598
33789
|
const [hours, minutes] = startTimeStr.split(":");
|
|
@@ -33629,7 +33820,7 @@ var LinePdfGenerator = ({
|
|
|
33629
33820
|
}
|
|
33630
33821
|
hourEndTime.setSeconds(0);
|
|
33631
33822
|
hourEndTime.setMilliseconds(0);
|
|
33632
|
-
const
|
|
33823
|
+
const formatTime5 = (date2) => {
|
|
33633
33824
|
return date2.toLocaleTimeString("en-IN", {
|
|
33634
33825
|
hour: "2-digit",
|
|
33635
33826
|
minute: "2-digit",
|
|
@@ -33637,7 +33828,7 @@ var LinePdfGenerator = ({
|
|
|
33637
33828
|
timeZone: "Asia/Kolkata"
|
|
33638
33829
|
});
|
|
33639
33830
|
};
|
|
33640
|
-
return `${
|
|
33831
|
+
return `${formatTime5(hourStartTime)} - ${formatTime5(hourEndTime)}`;
|
|
33641
33832
|
});
|
|
33642
33833
|
};
|
|
33643
33834
|
const hourlyTimeRanges = lineInfo.metrics.shift_start ? getHourlyTimeRanges(lineInfo.metrics.shift_start, lineInfo.metrics.shift_end) : [];
|
|
@@ -33784,86 +33975,94 @@ var LinePdfGenerator = ({
|
|
|
33784
33975
|
return Math.round(lineInfo.metrics.current_output / shiftDuration);
|
|
33785
33976
|
});
|
|
33786
33977
|
}
|
|
33978
|
+
const tableHeaderY = 143;
|
|
33979
|
+
const tableStartY = 151;
|
|
33980
|
+
const rowSpacing = 8;
|
|
33981
|
+
const bottomPadding = 8;
|
|
33982
|
+
const hourlyTableHeight = hourlyTimeRanges.length * rowSpacing;
|
|
33983
|
+
const backgroundHeight = tableStartY - hourlyOverviewStartY + hourlyTableHeight + bottomPadding;
|
|
33984
|
+
doc.setFillColor(245, 245, 245);
|
|
33985
|
+
doc.roundedRect(15, hourlyOverviewStartY, 180, backgroundHeight, 3, 3, "F");
|
|
33787
33986
|
doc.setFontSize(11);
|
|
33788
33987
|
doc.setFont("helvetica", "bold");
|
|
33789
|
-
doc.
|
|
33790
|
-
doc.
|
|
33791
|
-
doc.text("
|
|
33792
|
-
doc.text("
|
|
33793
|
-
doc.
|
|
33794
|
-
doc.
|
|
33795
|
-
doc.
|
|
33796
|
-
doc.setDrawColor(220, 220, 220);
|
|
33797
|
-
doc.line(20, 148, 190, 148);
|
|
33988
|
+
doc.text("Time Range", 25, tableHeaderY);
|
|
33989
|
+
doc.text("Output", 80, tableHeaderY);
|
|
33990
|
+
doc.text("Target", 125, tableHeaderY);
|
|
33991
|
+
doc.text("Status", 170, tableHeaderY);
|
|
33992
|
+
doc.setLineWidth(0.3);
|
|
33993
|
+
doc.setDrawColor(200, 200, 200);
|
|
33994
|
+
doc.line(20, 146, 190, 146);
|
|
33798
33995
|
doc.setFont("helvetica", "normal");
|
|
33799
|
-
let yPos =
|
|
33800
|
-
const
|
|
33996
|
+
let yPos = tableStartY;
|
|
33997
|
+
const lineDateForTable = new Date(lineInfo.date);
|
|
33998
|
+
const todayForTable = /* @__PURE__ */ new Date();
|
|
33999
|
+
todayForTable.setHours(0, 0, 0, 0);
|
|
34000
|
+
lineDateForTable.setHours(0, 0, 0, 0);
|
|
34001
|
+
const isTodayForTable = lineDateForTable.getTime() === todayForTable.getTime();
|
|
34002
|
+
let currentHour = 24;
|
|
34003
|
+
if (isTodayForTable) {
|
|
34004
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
34005
|
+
const currentTimeIST = new Date(now2.toLocaleString("en-US", { timeZone: "Asia/Kolkata" }));
|
|
34006
|
+
currentHour = currentTimeIST.getHours();
|
|
34007
|
+
}
|
|
33801
34008
|
hourlyTimeRanges.forEach((timeRange, index) => {
|
|
33802
|
-
|
|
33803
|
-
|
|
33804
|
-
|
|
33805
|
-
|
|
33806
|
-
const
|
|
33807
|
-
const
|
|
34009
|
+
const actualOutput = hourlyActualOutput[index] || 0;
|
|
34010
|
+
const [startHourStr] = (lineInfo.metrics.shift_start || "6:00").split(":");
|
|
34011
|
+
const startHour = parseInt(startHourStr);
|
|
34012
|
+
const hourNumber = (startHour + index) % 24;
|
|
34013
|
+
const dataCollected = !isTodayForTable || hourNumber < currentHour;
|
|
34014
|
+
const outputStr = dataCollected ? actualOutput.toString() : "TBD";
|
|
34015
|
+
const targetStr = targetOutputPerHour.toString();
|
|
33808
34016
|
doc.text(timeRange, 25, yPos);
|
|
33809
|
-
doc.text(
|
|
33810
|
-
doc.text(
|
|
33811
|
-
if (
|
|
33812
|
-
doc.
|
|
33813
|
-
doc.
|
|
33814
|
-
|
|
33815
|
-
|
|
33816
|
-
doc.
|
|
33817
|
-
doc.
|
|
34017
|
+
doc.text(outputStr, 80, yPos);
|
|
34018
|
+
doc.text(targetStr, 125, yPos);
|
|
34019
|
+
if (!dataCollected) {
|
|
34020
|
+
doc.setTextColor(100, 100, 100);
|
|
34021
|
+
doc.text("-", 170, yPos);
|
|
34022
|
+
} else if (actualOutput >= targetOutputPerHour) {
|
|
34023
|
+
doc.setTextColor(0, 171, 69);
|
|
34024
|
+
doc.setFont("ZapfDingbats", "normal");
|
|
34025
|
+
doc.text("4", 170, yPos);
|
|
34026
|
+
doc.setFont("helvetica", "normal");
|
|
33818
34027
|
} else {
|
|
33819
|
-
doc.
|
|
33820
|
-
doc.
|
|
33821
|
-
const crossX = 170;
|
|
33822
|
-
const crossY = yPos - 1;
|
|
33823
|
-
doc.line(crossX - 2, crossY - 2, crossX + 2, crossY + 2);
|
|
33824
|
-
doc.line(crossX - 2, crossY + 2, crossX + 2, crossY - 2);
|
|
34028
|
+
doc.setTextColor(227, 67, 41);
|
|
34029
|
+
doc.text("\xD7", 170, yPos);
|
|
33825
34030
|
}
|
|
33826
|
-
doc.
|
|
33827
|
-
doc.setLineWidth(0.2);
|
|
34031
|
+
doc.setTextColor(0, 0, 0);
|
|
33828
34032
|
yPos += rowSpacing;
|
|
33829
34033
|
});
|
|
33830
|
-
doc.roundedRect(20, 140, 170, yPos - 140 - 3, 1, 1, "S");
|
|
33831
|
-
addFooter(1);
|
|
33832
34034
|
doc.addPage();
|
|
33833
34035
|
yPos = addHeaderPage2();
|
|
33834
|
-
|
|
34036
|
+
const workspaceSectionStartY = yPos;
|
|
34037
|
+
const sortedWorkspaces = [...workspaceData].sort((a, b) => (a.efficiency || 0) - (b.efficiency || 0)).slice(0, 10);
|
|
34038
|
+
const wsRowCount = sortedWorkspaces.length > 0 ? sortedWorkspaces.length : 1;
|
|
34039
|
+
const wsTableHeight = 10 + 8 + 7 + wsRowCount * 8 + 8;
|
|
34040
|
+
doc.setFillColor(245, 245, 245);
|
|
34041
|
+
doc.roundedRect(15, workspaceSectionStartY, 180, wsTableHeight, 3, 3, "F");
|
|
34042
|
+
doc.setFontSize(18);
|
|
33835
34043
|
doc.setFont("helvetica", "bold");
|
|
33836
|
-
doc.setTextColor(
|
|
34044
|
+
doc.setTextColor(40, 40, 40);
|
|
33837
34045
|
doc.text("Poorest Performing Workspaces", 20, yPos);
|
|
33838
34046
|
doc.setTextColor(0, 0, 0);
|
|
33839
34047
|
yPos += 10;
|
|
33840
34048
|
doc.setFontSize(11);
|
|
33841
34049
|
doc.setFont("helvetica", "bold");
|
|
33842
|
-
doc.setFillColor(245, 245, 245);
|
|
33843
|
-
doc.roundedRect(20, yPos, 170, 8, 1, 1, "F");
|
|
33844
34050
|
yPos += 5;
|
|
33845
34051
|
doc.text("Workspace", 25, yPos);
|
|
33846
|
-
doc.text("Current/
|
|
34052
|
+
doc.text("Current/Target", 85, yPos);
|
|
33847
34053
|
doc.text("Efficiency", 145, yPos);
|
|
33848
34054
|
yPos += 3;
|
|
33849
|
-
doc.setLineWidth(0.
|
|
33850
|
-
doc.setDrawColor(
|
|
34055
|
+
doc.setLineWidth(0.3);
|
|
34056
|
+
doc.setDrawColor(200, 200, 200);
|
|
33851
34057
|
doc.line(20, yPos, 190, yPos);
|
|
33852
34058
|
doc.setFont("helvetica", "normal");
|
|
33853
|
-
const tableStartY = yPos;
|
|
33854
34059
|
yPos += 7;
|
|
33855
|
-
const sortedWorkspaces = [...workspaceData].sort((a, b) => (a.efficiency || 0) - (b.efficiency || 0)).slice(0, 10);
|
|
33856
34060
|
if (sortedWorkspaces.length === 0) {
|
|
33857
34061
|
doc.text("No workspace data available", 25, yPos);
|
|
33858
34062
|
yPos += 10;
|
|
33859
34063
|
} else {
|
|
33860
34064
|
sortedWorkspaces.forEach((ws, index) => {
|
|
33861
|
-
if (index % 2 === 0) {
|
|
33862
|
-
doc.setFillColor(252, 252, 252);
|
|
33863
|
-
doc.roundedRect(20, yPos - 5, 170, 8, 1, 1, "F");
|
|
33864
|
-
}
|
|
33865
34065
|
const workspaceName = getWorkspaceDisplayName(ws.workspace_name, lineInfo.line_id);
|
|
33866
|
-
const maxWidth = 55;
|
|
33867
34066
|
const truncatedName = workspaceName.length > 25 ? workspaceName.substring(0, 22) + "..." : workspaceName;
|
|
33868
34067
|
doc.text(truncatedName, 25, yPos);
|
|
33869
34068
|
doc.text(`${ws.action_count || 0} / ${ws.action_threshold || 0}`, 85, yPos);
|
|
@@ -33871,9 +34070,6 @@ var LinePdfGenerator = ({
|
|
|
33871
34070
|
yPos += 8;
|
|
33872
34071
|
});
|
|
33873
34072
|
}
|
|
33874
|
-
const wsTableHeight = yPos - tableStartY - 3;
|
|
33875
|
-
doc.roundedRect(20, tableStartY, 170, wsTableHeight, 1, 1, "S");
|
|
33876
|
-
addFooter(2);
|
|
33877
34073
|
doc.save(`${lineInfo.line_name}_${date.split(",")[0]}.pdf`);
|
|
33878
34074
|
} catch (error) {
|
|
33879
34075
|
console.error("PDF generation failed:", error);
|
|
@@ -35047,25 +35243,25 @@ var WorkspacePdfGenerator = ({ workspace, className }) => {
|
|
|
35047
35243
|
doc.setFont("helvetica", "bold");
|
|
35048
35244
|
doc.setTextColor(50, 50, 50);
|
|
35049
35245
|
doc.text("OPTIFYE.AI", 20, 15);
|
|
35050
|
-
doc.setFontSize(
|
|
35246
|
+
doc.setFontSize(9);
|
|
35051
35247
|
doc.setFont("helvetica", "normal");
|
|
35052
|
-
doc.setTextColor(
|
|
35053
|
-
const
|
|
35054
|
-
const
|
|
35055
|
-
doc.text(
|
|
35248
|
+
doc.setTextColor(100, 100, 100);
|
|
35249
|
+
const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: "Asia/Kolkata" })}`;
|
|
35250
|
+
const generatedTextWidth = doc.getStringUnitWidth(generatedText) * 9 / doc.internal.scaleFactor;
|
|
35251
|
+
doc.text(generatedText, doc.internal.pageSize.width - 20 - generatedTextWidth, 15);
|
|
35056
35252
|
doc.setDrawColor(200, 200, 200);
|
|
35057
35253
|
doc.setLineWidth(0.5);
|
|
35058
35254
|
doc.line(20, 20, 190, 20);
|
|
35059
35255
|
doc.setFillColor(250, 250, 250);
|
|
35060
|
-
doc.roundedRect(15, 25, 180,
|
|
35256
|
+
doc.roundedRect(15, 25, 180, 53, 3, 3, "F");
|
|
35061
35257
|
doc.setFontSize(32);
|
|
35062
35258
|
doc.setFont("helvetica", "bold");
|
|
35063
35259
|
doc.setTextColor(0, 0, 0);
|
|
35064
|
-
doc.text(lineName, 20,
|
|
35260
|
+
doc.text(lineName, 20, 39);
|
|
35065
35261
|
doc.setFontSize(22);
|
|
35066
35262
|
doc.setFont("helvetica", "normal");
|
|
35067
35263
|
doc.setTextColor(40, 40, 40);
|
|
35068
|
-
doc.text(getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id), 20,
|
|
35264
|
+
doc.text(getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id), 20, 51);
|
|
35069
35265
|
doc.setFontSize(13);
|
|
35070
35266
|
doc.setFont("helvetica", "normal");
|
|
35071
35267
|
doc.setTextColor(60, 60, 60);
|
|
@@ -35076,8 +35272,8 @@ var WorkspacePdfGenerator = ({ workspace, className }) => {
|
|
|
35076
35272
|
timeZone: "Asia/Kolkata"
|
|
35077
35273
|
});
|
|
35078
35274
|
const shiftType = "Day Shift";
|
|
35079
|
-
doc.text(`${date}`, 20,
|
|
35080
|
-
doc.text(`${shiftType}`, 20,
|
|
35275
|
+
doc.text(`${date}`, 20, 63);
|
|
35276
|
+
doc.text(`${shiftType}`, 20, 71);
|
|
35081
35277
|
const currentTime = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-IN", {
|
|
35082
35278
|
hour: "2-digit",
|
|
35083
35279
|
minute: "2-digit",
|
|
@@ -35090,11 +35286,11 @@ var WorkspacePdfGenerator = ({ workspace, className }) => {
|
|
|
35090
35286
|
});
|
|
35091
35287
|
doc.setFontSize(12);
|
|
35092
35288
|
doc.setTextColor(80, 80, 80);
|
|
35093
|
-
doc.text(`Report Period: ${shiftStartTime} - ${currentTime}`, 20,
|
|
35289
|
+
doc.text(`Report Period: ${shiftStartTime} - ${currentTime}`, 20, 79);
|
|
35094
35290
|
doc.setTextColor(0, 0, 0);
|
|
35095
35291
|
doc.setDrawColor(180, 180, 180);
|
|
35096
35292
|
doc.setLineWidth(0.8);
|
|
35097
|
-
doc.line(20,
|
|
35293
|
+
doc.line(20, 88, 190, 88);
|
|
35098
35294
|
const createKPIBox = (y) => {
|
|
35099
35295
|
doc.setFillColor(255, 255, 255);
|
|
35100
35296
|
doc.roundedRect(22, y - 7, 165, 12, 2, 2, "F");
|
|
@@ -35102,66 +35298,72 @@ var WorkspacePdfGenerator = ({ workspace, className }) => {
|
|
|
35102
35298
|
doc.setLineWidth(0.2);
|
|
35103
35299
|
doc.roundedRect(22, y - 7, 165, 12, 2, 2, "S");
|
|
35104
35300
|
};
|
|
35301
|
+
const perfOverviewStartY = 93;
|
|
35105
35302
|
doc.setFillColor(245, 245, 245);
|
|
35106
|
-
doc.roundedRect(15,
|
|
35303
|
+
doc.roundedRect(15, perfOverviewStartY, 180, 60, 3, 3, "F");
|
|
35107
35304
|
doc.setFontSize(18);
|
|
35108
35305
|
doc.setFont("helvetica", "bold");
|
|
35109
35306
|
doc.setTextColor(40, 40, 40);
|
|
35110
|
-
doc.text("Performance Overview", 20,
|
|
35307
|
+
doc.text("Performance Overview", 20, 103);
|
|
35111
35308
|
doc.setTextColor(0, 0, 0);
|
|
35112
|
-
const kpiStartY =
|
|
35309
|
+
const kpiStartY = 115;
|
|
35113
35310
|
const kpiSpacing = 10;
|
|
35114
35311
|
createKPIBox(kpiStartY);
|
|
35115
35312
|
doc.setFontSize(11);
|
|
35116
35313
|
doc.setFont("helvetica", "normal");
|
|
35117
|
-
doc.text("
|
|
35314
|
+
doc.text("Current Output/Target Output:", 25, kpiStartY);
|
|
35118
35315
|
doc.setFont("helvetica", "bold");
|
|
35119
|
-
doc.text(`${
|
|
35316
|
+
doc.text(`${workspace.total_actions} / ${workspace.target_output}`, 120, kpiStartY);
|
|
35120
35317
|
createKPIBox(kpiStartY + kpiSpacing);
|
|
35121
35318
|
doc.setFont("helvetica", "normal");
|
|
35122
|
-
doc.text("
|
|
35319
|
+
doc.text("Efficiency:", 25, kpiStartY + kpiSpacing);
|
|
35123
35320
|
doc.setFont("helvetica", "bold");
|
|
35124
|
-
doc.text(`${workspace.
|
|
35321
|
+
doc.text(`${(workspace.avg_efficiency || 0).toFixed(1)}% (Target: 80%)`, 120, kpiStartY + kpiSpacing);
|
|
35125
35322
|
createKPIBox(kpiStartY + kpiSpacing * 2);
|
|
35126
35323
|
doc.setFont("helvetica", "normal");
|
|
35127
|
-
doc.text("
|
|
35128
|
-
doc.setFont("helvetica", "bold");
|
|
35129
|
-
doc.text(`${(workspace.avg_efficiency || 0).toFixed(1)}% (Target: 80%)`, 120, kpiStartY + kpiSpacing * 2);
|
|
35130
|
-
createKPIBox(kpiStartY + kpiSpacing * 3);
|
|
35131
|
-
doc.setFont("helvetica", "normal");
|
|
35132
|
-
doc.text("PPH (Pieces Per Hour):", 25, kpiStartY + kpiSpacing * 3);
|
|
35324
|
+
doc.text("PPH (Pieces Per Hour):", 25, kpiStartY + kpiSpacing * 2);
|
|
35133
35325
|
doc.setFont("helvetica", "bold");
|
|
35134
|
-
doc.text(`${workspace.avg_pph.toFixed(1)} (Standard: ${workspace.pph_threshold.toFixed(1)})`, 120, kpiStartY + kpiSpacing *
|
|
35326
|
+
doc.text(`${workspace.avg_pph.toFixed(1)} (Standard: ${workspace.pph_threshold.toFixed(1)})`, 120, kpiStartY + kpiSpacing * 2);
|
|
35135
35327
|
doc.setDrawColor(180, 180, 180);
|
|
35136
35328
|
doc.setLineWidth(0.8);
|
|
35137
|
-
doc.line(20,
|
|
35329
|
+
doc.line(20, 163, 190, 163);
|
|
35330
|
+
const hourlyPerfStartY = 168;
|
|
35331
|
+
const hourlyData = workspace.hourly_action_counts || [];
|
|
35332
|
+
const hourlyTarget = workspace.pph_threshold;
|
|
35333
|
+
const tableStartY = 199;
|
|
35334
|
+
const rowHeight = 8;
|
|
35335
|
+
const bottomPadding = 8;
|
|
35336
|
+
const backgroundHeight = tableStartY - hourlyPerfStartY + hourlyData.length * rowHeight + bottomPadding;
|
|
35138
35337
|
doc.setFillColor(245, 245, 245);
|
|
35139
|
-
doc.roundedRect(15,
|
|
35338
|
+
doc.roundedRect(15, hourlyPerfStartY, 180, backgroundHeight, 3, 3, "F");
|
|
35140
35339
|
doc.setFontSize(18);
|
|
35141
35340
|
doc.setFont("helvetica", "bold");
|
|
35142
35341
|
doc.setTextColor(40, 40, 40);
|
|
35143
|
-
doc.text("Hourly Performance", 20,
|
|
35342
|
+
doc.text("Hourly Performance", 20, 178);
|
|
35144
35343
|
doc.setTextColor(0, 0, 0);
|
|
35145
35344
|
doc.setFontSize(11);
|
|
35146
35345
|
doc.setFont("helvetica", "bold");
|
|
35147
|
-
doc.
|
|
35148
|
-
doc.
|
|
35149
|
-
doc.text("
|
|
35150
|
-
doc.text("
|
|
35151
|
-
doc.
|
|
35152
|
-
doc.
|
|
35153
|
-
doc.
|
|
35154
|
-
doc.setDrawColor(220, 220, 220);
|
|
35155
|
-
doc.line(20, 185, 190, 185);
|
|
35346
|
+
doc.text("Time Range", 25, 188);
|
|
35347
|
+
doc.text("Output", 95, 188);
|
|
35348
|
+
doc.text("Target", 135, 188);
|
|
35349
|
+
doc.text("Status", 170, 188);
|
|
35350
|
+
doc.setLineWidth(0.3);
|
|
35351
|
+
doc.setDrawColor(200, 200, 200);
|
|
35352
|
+
doc.line(20, 191, 190, 191);
|
|
35156
35353
|
doc.setFont("helvetica", "normal");
|
|
35157
|
-
let yPos =
|
|
35158
|
-
const
|
|
35159
|
-
const
|
|
35354
|
+
let yPos = tableStartY;
|
|
35355
|
+
const workspaceDate = new Date(workspace.date);
|
|
35356
|
+
const today = /* @__PURE__ */ new Date();
|
|
35357
|
+
today.setHours(0, 0, 0, 0);
|
|
35358
|
+
workspaceDate.setHours(0, 0, 0, 0);
|
|
35359
|
+
const isToday = workspaceDate.getTime() === today.getTime();
|
|
35360
|
+
let currentHour = 24;
|
|
35361
|
+
if (isToday) {
|
|
35362
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
35363
|
+
const currentTimeIST = new Date(now2.toLocaleString("en-US", { timeZone: "Asia/Kolkata" }));
|
|
35364
|
+
currentHour = currentTimeIST.getHours();
|
|
35365
|
+
}
|
|
35160
35366
|
hourlyData.forEach((output, index) => {
|
|
35161
|
-
if (index % 2 === 0) {
|
|
35162
|
-
doc.setFillColor(252, 252, 252);
|
|
35163
|
-
doc.roundedRect(20, yPos - 5, 170, 8, 1, 1, "F");
|
|
35164
|
-
}
|
|
35165
35367
|
const startTime = /* @__PURE__ */ new Date(`2000-01-01 ${workspace.shift_start}`);
|
|
35166
35368
|
startTime.setHours(startTime.getHours() + index);
|
|
35167
35369
|
const endTime = new Date(startTime);
|
|
@@ -35173,14 +35375,17 @@ var WorkspacePdfGenerator = ({ workspace, className }) => {
|
|
|
35173
35375
|
hour: "numeric",
|
|
35174
35376
|
hour12: true
|
|
35175
35377
|
})}`;
|
|
35176
|
-
const
|
|
35378
|
+
const hourNumber = startTime.getHours();
|
|
35379
|
+
const dataCollected = !isToday || hourNumber < currentHour;
|
|
35380
|
+
const outputStr = dataCollected ? output.toString() : "TBD";
|
|
35177
35381
|
const targetStr = hourlyTarget.toString();
|
|
35178
|
-
const outputX = 95 + doc.getStringUnitWidth(outputStr) * doc.getFontSize() / (2 * doc.internal.scaleFactor);
|
|
35179
|
-
const targetX = 135 + doc.getStringUnitWidth(targetStr) * doc.getFontSize() / (2 * doc.internal.scaleFactor);
|
|
35180
35382
|
doc.text(timeRange, 25, yPos);
|
|
35181
|
-
doc.text(outputStr,
|
|
35182
|
-
doc.text(targetStr,
|
|
35183
|
-
if (
|
|
35383
|
+
doc.text(outputStr, 95, yPos);
|
|
35384
|
+
doc.text(targetStr, 135, yPos);
|
|
35385
|
+
if (!dataCollected) {
|
|
35386
|
+
doc.setTextColor(100, 100, 100);
|
|
35387
|
+
doc.text("-", 170, yPos);
|
|
35388
|
+
} else if (output >= hourlyTarget) {
|
|
35184
35389
|
doc.setTextColor(0, 171, 69);
|
|
35185
35390
|
doc.setFont("ZapfDingbats", "normal");
|
|
35186
35391
|
doc.text("4", 170, yPos);
|
|
@@ -35190,15 +35395,8 @@ var WorkspacePdfGenerator = ({ workspace, className }) => {
|
|
|
35190
35395
|
doc.text("\xD7", 170, yPos);
|
|
35191
35396
|
}
|
|
35192
35397
|
doc.setTextColor(0, 0, 0);
|
|
35193
|
-
yPos +=
|
|
35398
|
+
yPos += rowHeight;
|
|
35194
35399
|
});
|
|
35195
|
-
doc.setLineWidth(0.2);
|
|
35196
|
-
doc.setDrawColor(220, 220, 220);
|
|
35197
|
-
doc.roundedRect(20, 187, 170, yPos - 187 - 3, 1, 1, "S");
|
|
35198
|
-
doc.setFontSize(9);
|
|
35199
|
-
doc.setTextColor(130, 130, 130);
|
|
35200
|
-
const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: "Asia/Kolkata" })}`;
|
|
35201
|
-
doc.text(generatedText, 20, 280);
|
|
35202
35400
|
doc.save(`${workspace.workspace_name}_${date.split(",")[0]}.pdf`);
|
|
35203
35401
|
} catch (error) {
|
|
35204
35402
|
console.error("PDF generation failed:", error);
|
|
@@ -36278,7 +36476,8 @@ var WorkspaceHealthCard = ({
|
|
|
36278
36476
|
workspace,
|
|
36279
36477
|
onClick,
|
|
36280
36478
|
showDetails = true,
|
|
36281
|
-
className = ""
|
|
36479
|
+
className = "",
|
|
36480
|
+
onViewDetails
|
|
36282
36481
|
}) => {
|
|
36283
36482
|
const getStatusConfig = () => {
|
|
36284
36483
|
switch (workspace.status) {
|
|
@@ -36331,38 +36530,101 @@ var WorkspaceHealthCard = ({
|
|
|
36331
36530
|
onClick(workspace);
|
|
36332
36531
|
}
|
|
36333
36532
|
};
|
|
36533
|
+
const handleViewDetails = (event) => {
|
|
36534
|
+
event.stopPropagation();
|
|
36535
|
+
event.preventDefault();
|
|
36536
|
+
if (onViewDetails) {
|
|
36537
|
+
onViewDetails(workspace);
|
|
36538
|
+
}
|
|
36539
|
+
};
|
|
36334
36540
|
const handleKeyDown = (event) => {
|
|
36335
36541
|
if (onClick && (event.key === "Enter" || event.key === " ")) {
|
|
36336
36542
|
event.preventDefault();
|
|
36337
36543
|
onClick(workspace);
|
|
36338
36544
|
}
|
|
36339
36545
|
};
|
|
36546
|
+
const formatDuration3 = (minutes) => {
|
|
36547
|
+
if (!minutes || minutes <= 0) return "0 min";
|
|
36548
|
+
const rounded = Math.max(Math.round(minutes), 0);
|
|
36549
|
+
const days = Math.floor(rounded / 1440);
|
|
36550
|
+
const hours = Math.floor(rounded % 1440 / 60);
|
|
36551
|
+
const mins = rounded % 60;
|
|
36552
|
+
const parts = [];
|
|
36553
|
+
if (days) parts.push(`${days} day${days === 1 ? "" : "s"}`);
|
|
36554
|
+
if (hours) parts.push(`${hours} hr${hours === 1 ? "" : "s"}`);
|
|
36555
|
+
if (mins) parts.push(`${mins} min${mins === 1 ? "" : "s"}`);
|
|
36556
|
+
if (!parts.length) {
|
|
36557
|
+
parts.push("1 min");
|
|
36558
|
+
}
|
|
36559
|
+
return parts.join(" ");
|
|
36560
|
+
};
|
|
36340
36561
|
const formatTimeAgo = (timeString) => {
|
|
36341
|
-
|
|
36562
|
+
if (!timeString) return "Unknown";
|
|
36563
|
+
const cleaned = timeString.replace("about ", "").trim();
|
|
36564
|
+
if (cleaned.toLowerCase() === "never") return "Never";
|
|
36565
|
+
const minuteMatch = cleaned.match(/(\d+)\s*m/);
|
|
36566
|
+
if (!minuteMatch) {
|
|
36567
|
+
return cleaned;
|
|
36568
|
+
}
|
|
36569
|
+
const minutes = parseInt(minuteMatch[1], 10);
|
|
36570
|
+
if (!Number.isFinite(minutes)) return cleaned;
|
|
36571
|
+
if (minutes < 1) return "Just now";
|
|
36572
|
+
if (minutes < 60) {
|
|
36573
|
+
return `${minutes} min ago`;
|
|
36574
|
+
}
|
|
36575
|
+
const hours = Math.floor(minutes / 60);
|
|
36576
|
+
const remainingMinutes = minutes % 60;
|
|
36577
|
+
if (hours < 24) {
|
|
36578
|
+
const parts2 = [`${hours} hr${hours === 1 ? "" : "s"}`];
|
|
36579
|
+
if (remainingMinutes) {
|
|
36580
|
+
parts2.push(`${remainingMinutes} min`);
|
|
36581
|
+
}
|
|
36582
|
+
return `${parts2.join(" ")} ago`;
|
|
36583
|
+
}
|
|
36584
|
+
const days = Math.floor(hours / 24);
|
|
36585
|
+
const remainingHours = hours % 24;
|
|
36586
|
+
const parts = [`${days} day${days === 1 ? "" : "s"}`];
|
|
36587
|
+
if (remainingHours) {
|
|
36588
|
+
parts.push(`${remainingHours} hr${remainingHours === 1 ? "" : "s"}`);
|
|
36589
|
+
}
|
|
36590
|
+
return `${parts.join(" ")} ago`;
|
|
36342
36591
|
};
|
|
36343
|
-
const
|
|
36344
|
-
if (!uptimeDetails)
|
|
36592
|
+
const getDowntimeConfig = (uptimeDetails) => {
|
|
36593
|
+
if (!uptimeDetails) {
|
|
36594
|
+
if (workspace.status === "healthy") {
|
|
36595
|
+
return {
|
|
36596
|
+
text: "0m",
|
|
36597
|
+
className: "text-emerald-600 dark:text-emerald-400",
|
|
36598
|
+
label: "Total Downtime"
|
|
36599
|
+
};
|
|
36600
|
+
}
|
|
36601
|
+
return { text: "--", className: "text-slate-400", label: "Total Downtime" };
|
|
36602
|
+
}
|
|
36345
36603
|
const downtimeMinutes = Math.max(0, uptimeDetails.expectedMinutes - uptimeDetails.actualMinutes);
|
|
36346
|
-
if (downtimeMinutes === 0)
|
|
36347
|
-
|
|
36348
|
-
|
|
36349
|
-
|
|
36350
|
-
|
|
36351
|
-
|
|
36352
|
-
return `${hours} hr downtime`;
|
|
36604
|
+
if (downtimeMinutes === 0) {
|
|
36605
|
+
return {
|
|
36606
|
+
text: "0m",
|
|
36607
|
+
className: "text-emerald-600 dark:text-emerald-400",
|
|
36608
|
+
label: "Total Downtime"
|
|
36609
|
+
};
|
|
36353
36610
|
}
|
|
36354
|
-
return
|
|
36611
|
+
return {
|
|
36612
|
+
text: `${formatDuration3(downtimeMinutes)}`,
|
|
36613
|
+
className: downtimeMinutes > 60 ? "text-rose-600 dark:text-rose-400" : "text-amber-600 dark:text-amber-400",
|
|
36614
|
+
label: "Total Downtime"
|
|
36615
|
+
};
|
|
36355
36616
|
};
|
|
36617
|
+
const downtimeConfig = getDowntimeConfig(workspace.uptimeDetails);
|
|
36356
36618
|
return /* @__PURE__ */ jsx(
|
|
36357
36619
|
Card2,
|
|
36358
36620
|
{
|
|
36359
36621
|
className: clsx(
|
|
36360
|
-
"relative overflow-hidden transition-all duration-300",
|
|
36622
|
+
"relative overflow-hidden transition-all duration-300 h-full flex flex-col",
|
|
36361
36623
|
"bg-gradient-to-br",
|
|
36362
36624
|
config.gradient,
|
|
36363
36625
|
"border",
|
|
36364
36626
|
config.border,
|
|
36365
|
-
"shadow-sm hover:shadow-
|
|
36627
|
+
"shadow-sm hover:shadow-lg hover:border-blue-300 dark:hover:border-blue-700",
|
|
36366
36628
|
onClick && "cursor-pointer hover:scale-[1.01]",
|
|
36367
36629
|
workspace.isStale && "opacity-90",
|
|
36368
36630
|
className
|
|
@@ -36372,7 +36634,7 @@ var WorkspaceHealthCard = ({
|
|
|
36372
36634
|
tabIndex: onClick ? 0 : void 0,
|
|
36373
36635
|
role: onClick ? "button" : void 0,
|
|
36374
36636
|
"aria-label": `Workspace ${workspace.workspace_display_name} status: ${workspace.status}`,
|
|
36375
|
-
children: /* @__PURE__ */ jsxs("div", { className: "p-4", children: [
|
|
36637
|
+
children: /* @__PURE__ */ jsxs("div", { className: "p-4 flex-grow flex flex-col", children: [
|
|
36376
36638
|
/* @__PURE__ */ jsx("div", { className: "mb-3", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start gap-2 sm:gap-3", children: [
|
|
36377
36639
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
36378
36640
|
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-gray-900 dark:text-gray-100 mb-1 break-words", children: workspace.workspace_display_name || `Workspace ${workspace.workspace_id.slice(0, 8)}` }),
|
|
@@ -36394,21 +36656,20 @@ var WorkspaceHealthCard = ({
|
|
|
36394
36656
|
/* @__PURE__ */ jsx("span", { className: "font-medium", children: formatTimeAgo(workspace.timeSinceLastUpdate) })
|
|
36395
36657
|
] })
|
|
36396
36658
|
] }),
|
|
36397
|
-
|
|
36398
|
-
/* @__PURE__ */ jsx(
|
|
36399
|
-
/* @__PURE__ */
|
|
36400
|
-
|
|
36401
|
-
|
|
36402
|
-
|
|
36403
|
-
|
|
36404
|
-
|
|
36405
|
-
|
|
36406
|
-
|
|
36407
|
-
|
|
36408
|
-
"
|
|
36409
|
-
|
|
36410
|
-
|
|
36411
|
-
] })
|
|
36659
|
+
/* @__PURE__ */ jsx("div", { className: "mt-3 pt-3 border-t border-slate-100 dark:border-slate-800", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
36660
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-slate-500 uppercase tracking-wide", children: "Total Downtime" }),
|
|
36661
|
+
/* @__PURE__ */ jsx("span", { className: clsx("text-sm font-semibold", downtimeConfig.className), children: downtimeConfig.text })
|
|
36662
|
+
] }) })
|
|
36663
|
+
] }),
|
|
36664
|
+
onViewDetails && /* @__PURE__ */ jsx("div", { className: "pt-4 mt-auto", children: /* @__PURE__ */ jsx(
|
|
36665
|
+
"button",
|
|
36666
|
+
{
|
|
36667
|
+
onClick: handleViewDetails,
|
|
36668
|
+
className: "w-full inline-flex items-center justify-center rounded-lg border border-slate-200/60 bg-white/60 px-3 py-2 text-sm font-medium text-slate-700 shadow-sm backdrop-blur-sm transition-all hover:bg-white/90 hover:text-slate-900 dark:bg-white/10 dark:text-slate-200 dark:border-white/10 dark:hover:bg-white/20",
|
|
36669
|
+
type: "button",
|
|
36670
|
+
children: "View shift timeline"
|
|
36671
|
+
}
|
|
36672
|
+
) })
|
|
36412
36673
|
] })
|
|
36413
36674
|
}
|
|
36414
36675
|
);
|
|
@@ -36416,8 +36677,11 @@ var WorkspaceHealthCard = ({
|
|
|
36416
36677
|
var CompactWorkspaceHealthCard = ({
|
|
36417
36678
|
workspace,
|
|
36418
36679
|
onClick,
|
|
36419
|
-
className = ""
|
|
36680
|
+
className = "",
|
|
36681
|
+
onViewDetails
|
|
36420
36682
|
}) => {
|
|
36683
|
+
const downtimeMinutes = workspace.uptimeDetails ? Math.max(0, workspace.uptimeDetails.expectedMinutes - workspace.uptimeDetails.actualMinutes) : null;
|
|
36684
|
+
const downtimeLabel = downtimeMinutes === null ? "No downtime data" : downtimeMinutes === 0 ? "No downtime" : `${downtimeMinutes} min down`;
|
|
36421
36685
|
const getStatusConfig = () => {
|
|
36422
36686
|
switch (workspace.status) {
|
|
36423
36687
|
case "healthy":
|
|
@@ -36457,6 +36721,13 @@ var CompactWorkspaceHealthCard = ({
|
|
|
36457
36721
|
onClick(workspace);
|
|
36458
36722
|
}
|
|
36459
36723
|
};
|
|
36724
|
+
const handleViewDetails = (event) => {
|
|
36725
|
+
event.stopPropagation();
|
|
36726
|
+
event.preventDefault();
|
|
36727
|
+
if (onViewDetails) {
|
|
36728
|
+
onViewDetails(workspace);
|
|
36729
|
+
}
|
|
36730
|
+
};
|
|
36460
36731
|
return /* @__PURE__ */ jsxs(
|
|
36461
36732
|
"div",
|
|
36462
36733
|
{
|
|
@@ -36484,14 +36755,20 @@ var CompactWorkspaceHealthCard = ({
|
|
|
36484
36755
|
workspace.uptimePercentage.toFixed(1),
|
|
36485
36756
|
"%"
|
|
36486
36757
|
] }),
|
|
36487
|
-
|
|
36488
|
-
|
|
36489
|
-
Math.max(0, workspace.uptimeDetails.expectedMinutes - workspace.uptimeDetails.actualMinutes),
|
|
36490
|
-
"m down"
|
|
36491
|
-
] })
|
|
36758
|
+
downtimeMinutes !== null && downtimeMinutes > 0 && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 dark:text-gray-400", children: "\u2022" }),
|
|
36759
|
+
downtimeLabel && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: downtimeLabel })
|
|
36492
36760
|
] }),
|
|
36493
36761
|
/* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: workspace.timeSinceLastUpdate }),
|
|
36494
|
-
/* @__PURE__ */ jsx("div", { className: clsx("h-2 w-2 rounded-full", config.dot) })
|
|
36762
|
+
/* @__PURE__ */ jsx("div", { className: clsx("h-2 w-2 rounded-full", config.dot) }),
|
|
36763
|
+
onViewDetails && /* @__PURE__ */ jsx(
|
|
36764
|
+
"button",
|
|
36765
|
+
{
|
|
36766
|
+
onClick: handleViewDetails,
|
|
36767
|
+
className: "rounded-full border border-gray-200 px-2 py-0.5 text-[11px] font-medium text-gray-600 hover:bg-gray-50",
|
|
36768
|
+
type: "button",
|
|
36769
|
+
children: "View"
|
|
36770
|
+
}
|
|
36771
|
+
)
|
|
36495
36772
|
] })
|
|
36496
36773
|
]
|
|
36497
36774
|
}
|
|
@@ -36500,6 +36777,7 @@ var CompactWorkspaceHealthCard = ({
|
|
|
36500
36777
|
var HealthStatusGrid = ({
|
|
36501
36778
|
workspaces,
|
|
36502
36779
|
onWorkspaceClick,
|
|
36780
|
+
onWorkspaceViewDetails,
|
|
36503
36781
|
showFilters = true,
|
|
36504
36782
|
groupBy: initialGroupBy = "none",
|
|
36505
36783
|
className = ""
|
|
@@ -36687,7 +36965,8 @@ var HealthStatusGrid = ({
|
|
|
36687
36965
|
{
|
|
36688
36966
|
workspace,
|
|
36689
36967
|
onClick: onWorkspaceClick,
|
|
36690
|
-
showDetails: true
|
|
36968
|
+
showDetails: true,
|
|
36969
|
+
onViewDetails: onWorkspaceViewDetails
|
|
36691
36970
|
},
|
|
36692
36971
|
workspace.workspace_id
|
|
36693
36972
|
)) })
|
|
@@ -40223,7 +40502,7 @@ var AIAgentView = () => {
|
|
|
40223
40502
|
}
|
|
40224
40503
|
return formattedLines.join("");
|
|
40225
40504
|
};
|
|
40226
|
-
const
|
|
40505
|
+
const formatTime5 = (timestamp) => {
|
|
40227
40506
|
const date = new Date(timestamp);
|
|
40228
40507
|
return date.toLocaleTimeString([], {
|
|
40229
40508
|
hour: "2-digit",
|
|
@@ -41487,7 +41766,7 @@ var AIAgentView = () => {
|
|
|
41487
41766
|
}
|
|
41488
41767
|
),
|
|
41489
41768
|
/* @__PURE__ */ jsxs("div", { className: `mt-1.5 sm:mt-2 flex items-center gap-2 text-xs text-gray-400 ${message.role === "user" ? "justify-end" : "justify-start"}`, children: [
|
|
41490
|
-
/* @__PURE__ */ jsx("span", { children:
|
|
41769
|
+
/* @__PURE__ */ jsx("span", { children: formatTime5(message.created_at) }),
|
|
41491
41770
|
message.role === "assistant" && message.id !== -1 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
41492
41771
|
/* @__PURE__ */ jsx("div", { className: "w-1 h-1 bg-gray-300 rounded-full" }),
|
|
41493
41772
|
/* @__PURE__ */ jsx("span", { children: "Axel" })
|
|
@@ -44318,8 +44597,7 @@ var KPIsOverviewView = ({
|
|
|
44318
44597
|
" Shift"
|
|
44319
44598
|
] })
|
|
44320
44599
|
] })
|
|
44321
|
-
] }) })
|
|
44322
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs sm:text-sm text-gray-600 text-center mt-2 sm:mt-3 px-2 sm:px-0", children: "Click on any line to view detailed performance metrics" })
|
|
44600
|
+
] }) })
|
|
44323
44601
|
] }) }),
|
|
44324
44602
|
/* @__PURE__ */ jsx("main", { className: "flex-1 p-3 sm:p-4 md:p-6 overflow-y-auto", children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3 sm:gap-4 md:gap-6", children: lines.map((line) => /* @__PURE__ */ jsx(
|
|
44325
44603
|
LineCard,
|
|
@@ -48636,18 +48914,41 @@ var useWorkspaceHealth = (options) => {
|
|
|
48636
48914
|
const isFetchingRef = useRef(false);
|
|
48637
48915
|
const refreshIntervalRef = useRef(null);
|
|
48638
48916
|
const healthTable = databaseConfig?.tables?.workspace_health || "workspace_health_status";
|
|
48639
|
-
const
|
|
48640
|
-
|
|
48641
|
-
const
|
|
48642
|
-
const
|
|
48643
|
-
const
|
|
48644
|
-
|
|
48645
|
-
|
|
48646
|
-
|
|
48647
|
-
|
|
48917
|
+
const computeSummary = useCallback((data) => {
|
|
48918
|
+
const total = data.length;
|
|
48919
|
+
const healthy = data.filter((w) => w.status === "healthy").length;
|
|
48920
|
+
const unhealthy = data.filter((w) => w.status === "unhealthy").length;
|
|
48921
|
+
const warning6 = data.filter((w) => w.status === "warning").length;
|
|
48922
|
+
let uptimePercentage = total > 0 ? healthy / total * 100 : 100;
|
|
48923
|
+
let totalDowntimeMinutes;
|
|
48924
|
+
const withUptime = data.filter(
|
|
48925
|
+
(w) => w.uptimePercentage !== void 0 && w.uptimeDetails !== void 0
|
|
48926
|
+
);
|
|
48927
|
+
if (withUptime.length > 0) {
|
|
48928
|
+
const totalUptime = withUptime.reduce((sum, w) => sum + (w.uptimePercentage || 0), 0);
|
|
48929
|
+
uptimePercentage = totalUptime / withUptime.length;
|
|
48930
|
+
totalDowntimeMinutes = withUptime.reduce((sum, w) => {
|
|
48931
|
+
if (w.uptimeDetails) {
|
|
48932
|
+
return sum + Math.max(0, w.uptimeDetails.expectedMinutes - w.uptimeDetails.actualMinutes);
|
|
48933
|
+
}
|
|
48934
|
+
return sum;
|
|
48935
|
+
}, 0);
|
|
48936
|
+
}
|
|
48937
|
+
return {
|
|
48938
|
+
totalWorkspaces: total,
|
|
48939
|
+
healthyWorkspaces: healthy,
|
|
48940
|
+
unhealthyWorkspaces: unhealthy,
|
|
48941
|
+
warningWorkspaces: warning6,
|
|
48942
|
+
uptimePercentage,
|
|
48943
|
+
totalDowntimeMinutes,
|
|
48944
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
48945
|
+
};
|
|
48946
|
+
}, []);
|
|
48648
48947
|
const fetchWorkspacesHealth = useCallback(async () => {
|
|
48649
|
-
if (
|
|
48948
|
+
if (isFetchingRef.current) return;
|
|
48650
48949
|
if (!options.companyId) {
|
|
48950
|
+
setWorkspaces([]);
|
|
48951
|
+
setSummary(computeSummary([]));
|
|
48651
48952
|
setLoading(false);
|
|
48652
48953
|
return;
|
|
48653
48954
|
}
|
|
@@ -48655,39 +48956,12 @@ var useWorkspaceHealth = (options) => {
|
|
|
48655
48956
|
isFetchingRef.current = true;
|
|
48656
48957
|
setLoading(true);
|
|
48657
48958
|
setError(null);
|
|
48658
|
-
|
|
48659
|
-
|
|
48660
|
-
|
|
48661
|
-
}
|
|
48662
|
-
query = query.order("workspace_display_name", { ascending: true });
|
|
48663
|
-
const { data, error: fetchError } = await query;
|
|
48664
|
-
if (fetchError) throw fetchError;
|
|
48665
|
-
const healthData = data || [];
|
|
48666
|
-
const workspacesWithStatus = healthData.map((ws) => {
|
|
48667
|
-
const status = calculateHealthStatus(ws);
|
|
48668
|
-
const now2 = /* @__PURE__ */ new Date();
|
|
48669
|
-
const lastUpdate = ws.last_heartbeat ? new Date(ws.last_heartbeat) : null;
|
|
48670
|
-
const timeSinceLastUpdate = lastUpdate ? `${Math.floor((now2.getTime() - lastUpdate.getTime()) / 6e4)}m ago` : "Never";
|
|
48671
|
-
return {
|
|
48672
|
-
...ws,
|
|
48673
|
-
status,
|
|
48674
|
-
timeSinceLastUpdate,
|
|
48675
|
-
isStale: !lastUpdate || now2.getTime() - lastUpdate.getTime() > 15 * 6e4
|
|
48676
|
-
};
|
|
48959
|
+
const workspacesWithStatus = await workspaceHealthService.getWorkspaceHealthStatus({
|
|
48960
|
+
lineId: options.lineId,
|
|
48961
|
+
companyId: options.companyId
|
|
48677
48962
|
});
|
|
48678
48963
|
setWorkspaces(workspacesWithStatus);
|
|
48679
|
-
|
|
48680
|
-
const healthy = workspacesWithStatus.filter((w) => w.status === "healthy").length;
|
|
48681
|
-
const unhealthy = workspacesWithStatus.filter((w) => w.status === "unhealthy").length;
|
|
48682
|
-
const warning6 = workspacesWithStatus.filter((w) => w.status === "warning").length;
|
|
48683
|
-
setSummary({
|
|
48684
|
-
totalWorkspaces: total,
|
|
48685
|
-
healthyWorkspaces: healthy,
|
|
48686
|
-
unhealthyWorkspaces: unhealthy,
|
|
48687
|
-
warningWorkspaces: warning6,
|
|
48688
|
-
uptimePercentage: total > 0 ? healthy / total * 100 : 100,
|
|
48689
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
48690
|
-
});
|
|
48964
|
+
setSummary(computeSummary(workspacesWithStatus));
|
|
48691
48965
|
} catch (err) {
|
|
48692
48966
|
console.error("[useWorkspaceHealth] Error fetching workspace health:", err);
|
|
48693
48967
|
setError({ message: err.message, code: err.code || "FETCH_ERROR" });
|
|
@@ -48696,7 +48970,7 @@ var useWorkspaceHealth = (options) => {
|
|
|
48696
48970
|
setLoading(false);
|
|
48697
48971
|
isFetchingRef.current = false;
|
|
48698
48972
|
}
|
|
48699
|
-
}, [
|
|
48973
|
+
}, [options.companyId, options.lineId, computeSummary]);
|
|
48700
48974
|
useEffect(() => {
|
|
48701
48975
|
fetchWorkspacesHealth();
|
|
48702
48976
|
}, [fetchWorkspacesHealth]);
|
|
@@ -48741,6 +49015,395 @@ var useWorkspaceHealth = (options) => {
|
|
|
48741
49015
|
refetch: fetchWorkspacesHealth
|
|
48742
49016
|
};
|
|
48743
49017
|
};
|
|
49018
|
+
var STATUS_COLORS = {
|
|
49019
|
+
up: "bg-emerald-500",
|
|
49020
|
+
down: "bg-rose-500",
|
|
49021
|
+
pending: "bg-gray-200"
|
|
49022
|
+
};
|
|
49023
|
+
var STATUS_TITLES = {
|
|
49024
|
+
up: "Uptime",
|
|
49025
|
+
down: "Downtime",
|
|
49026
|
+
pending: "Pending"
|
|
49027
|
+
};
|
|
49028
|
+
var formatTime4 = (date, timezone) => new Intl.DateTimeFormat("en-IN", {
|
|
49029
|
+
hour: "numeric",
|
|
49030
|
+
minute: "2-digit",
|
|
49031
|
+
hour12: true,
|
|
49032
|
+
timeZone: timezone
|
|
49033
|
+
}).format(date);
|
|
49034
|
+
var formatDuration = (minutes) => {
|
|
49035
|
+
if (minutes < 1) return "<1 min";
|
|
49036
|
+
if (minutes < 60) return `${minutes} min`;
|
|
49037
|
+
const hours = Math.floor(minutes / 60);
|
|
49038
|
+
const remainder = minutes % 60;
|
|
49039
|
+
if (remainder === 0) return `${hours} hr${hours > 1 ? "s" : ""}`;
|
|
49040
|
+
return `${hours} hr ${remainder} min`;
|
|
49041
|
+
};
|
|
49042
|
+
var formatDowntimeLabel = (minutes, includeSuffix = true) => {
|
|
49043
|
+
if (!minutes || minutes <= 0) {
|
|
49044
|
+
return includeSuffix ? "No downtime" : "0 min";
|
|
49045
|
+
}
|
|
49046
|
+
const rounded = Math.max(Math.round(minutes), 0);
|
|
49047
|
+
const days = Math.floor(rounded / 1440);
|
|
49048
|
+
const hours = Math.floor(rounded % 1440 / 60);
|
|
49049
|
+
const mins = rounded % 60;
|
|
49050
|
+
const parts = [];
|
|
49051
|
+
if (days) parts.push(`${days} day${days === 1 ? "" : "s"}`);
|
|
49052
|
+
if (hours) parts.push(`${hours} hr${hours === 1 ? "" : "s"}`);
|
|
49053
|
+
if (mins) parts.push(`${mins} min${mins === 1 ? "" : "s"}`);
|
|
49054
|
+
if (!parts.length) {
|
|
49055
|
+
parts.push("1 min");
|
|
49056
|
+
}
|
|
49057
|
+
const label = parts.join(" ");
|
|
49058
|
+
return includeSuffix ? `${label} down` : label;
|
|
49059
|
+
};
|
|
49060
|
+
var UptimeTimelineStrip = ({
|
|
49061
|
+
points,
|
|
49062
|
+
totalMinutes,
|
|
49063
|
+
shiftStart,
|
|
49064
|
+
shiftEnd,
|
|
49065
|
+
timezone,
|
|
49066
|
+
className = "",
|
|
49067
|
+
uptimePercentage = 0,
|
|
49068
|
+
downtimeMinutes = 0
|
|
49069
|
+
}) => {
|
|
49070
|
+
const segments = useMemo(() => {
|
|
49071
|
+
if (!points.length || totalMinutes <= 0) return [];
|
|
49072
|
+
const result = [];
|
|
49073
|
+
let current = {
|
|
49074
|
+
status: points[0].status,
|
|
49075
|
+
length: 1,
|
|
49076
|
+
startMinuteIndex: points[0].minuteIndex,
|
|
49077
|
+
startTimestamp: points[0].timestamp,
|
|
49078
|
+
endTimestamp: points[0].timestamp
|
|
49079
|
+
};
|
|
49080
|
+
for (let i = 1; i < points.length; i++) {
|
|
49081
|
+
const point = points[i];
|
|
49082
|
+
if (point.status === current.status) {
|
|
49083
|
+
current.length += 1;
|
|
49084
|
+
current.endTimestamp = point.timestamp;
|
|
49085
|
+
} else {
|
|
49086
|
+
result.push(current);
|
|
49087
|
+
current = {
|
|
49088
|
+
status: point.status,
|
|
49089
|
+
length: 1,
|
|
49090
|
+
startMinuteIndex: point.minuteIndex,
|
|
49091
|
+
startTimestamp: point.timestamp,
|
|
49092
|
+
endTimestamp: point.timestamp
|
|
49093
|
+
};
|
|
49094
|
+
}
|
|
49095
|
+
}
|
|
49096
|
+
result.push(current);
|
|
49097
|
+
return result;
|
|
49098
|
+
}, [points, totalMinutes]);
|
|
49099
|
+
const markers = useMemo(() => {
|
|
49100
|
+
if (totalMinutes <= 0) return [];
|
|
49101
|
+
const startDate = new Date(shiftStart);
|
|
49102
|
+
const endDate = new Date(shiftEnd);
|
|
49103
|
+
const roundedTotal = Math.max(totalMinutes, 1);
|
|
49104
|
+
const markerInterval = totalMinutes > 360 ? 120 : 60;
|
|
49105
|
+
const markerList = [];
|
|
49106
|
+
for (let minute = 0; minute <= roundedTotal; minute += markerInterval) {
|
|
49107
|
+
const markerMinute = Math.min(minute, roundedTotal);
|
|
49108
|
+
const markerDate = addMinutes(startDate, markerMinute);
|
|
49109
|
+
markerList.push({
|
|
49110
|
+
minute: markerMinute,
|
|
49111
|
+
label: formatTime4(markerDate, timezone)
|
|
49112
|
+
});
|
|
49113
|
+
}
|
|
49114
|
+
const endLabel = formatTime4(endDate, timezone);
|
|
49115
|
+
if (!markerList.some((marker) => marker.minute === roundedTotal)) {
|
|
49116
|
+
markerList.push({
|
|
49117
|
+
minute: roundedTotal,
|
|
49118
|
+
label: endLabel
|
|
49119
|
+
});
|
|
49120
|
+
} else {
|
|
49121
|
+
markerList[markerList.length - 1] = {
|
|
49122
|
+
minute: roundedTotal,
|
|
49123
|
+
label: endLabel
|
|
49124
|
+
};
|
|
49125
|
+
}
|
|
49126
|
+
return markerList;
|
|
49127
|
+
}, [shiftStart, shiftEnd, timezone, totalMinutes]);
|
|
49128
|
+
if (!points.length || totalMinutes <= 0) {
|
|
49129
|
+
return /* @__PURE__ */ jsx("div", { className: "w-full rounded-xl border border-dashed border-gray-200 bg-gray-50/50 p-6 text-center text-sm text-gray-600", children: "No uptime data available for this shift yet." });
|
|
49130
|
+
}
|
|
49131
|
+
return /* @__PURE__ */ jsxs("div", { className: `relative w-full ${className}`, children: [
|
|
49132
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center mb-3 text-sm", children: /* @__PURE__ */ jsxs("span", { className: "text-gray-900 font-semibold", children: [
|
|
49133
|
+
uptimePercentage.toFixed(1),
|
|
49134
|
+
" % uptime ",
|
|
49135
|
+
downtimeMinutes > 0 && /* @__PURE__ */ jsxs("span", { className: "text-gray-600 font-normal", children: [
|
|
49136
|
+
"(",
|
|
49137
|
+
formatDowntimeLabel(downtimeMinutes),
|
|
49138
|
+
")"
|
|
49139
|
+
] })
|
|
49140
|
+
] }) }),
|
|
49141
|
+
/* @__PURE__ */ jsx("div", { className: "relative flex h-4 overflow-hidden rounded-lg border border-gray-200 shadow-sm bg-white", children: segments.map((segment, index) => {
|
|
49142
|
+
const startDate = new Date(segment.startTimestamp);
|
|
49143
|
+
const endDate = new Date(segment.endTimestamp);
|
|
49144
|
+
if (segment.length > 1) {
|
|
49145
|
+
endDate.setMinutes(endDate.getMinutes() + 1);
|
|
49146
|
+
}
|
|
49147
|
+
const tooltip = `${STATUS_TITLES[segment.status]} \u2022 ${formatDuration(segment.length)} (${formatTime4(
|
|
49148
|
+
startDate,
|
|
49149
|
+
timezone
|
|
49150
|
+
)} - ${formatTime4(endDate, timezone)})`;
|
|
49151
|
+
return /* @__PURE__ */ jsx(
|
|
49152
|
+
"div",
|
|
49153
|
+
{
|
|
49154
|
+
className: `${STATUS_COLORS[segment.status]} transition-all hover:opacity-80 cursor-pointer`,
|
|
49155
|
+
style: { flex: segment.length },
|
|
49156
|
+
title: tooltip
|
|
49157
|
+
},
|
|
49158
|
+
`${segment.status}-${segment.startMinuteIndex}-${index}`
|
|
49159
|
+
);
|
|
49160
|
+
}) }),
|
|
49161
|
+
/* @__PURE__ */ jsx("div", { className: "pointer-events-none relative w-full mt-4 min-h-6", children: markers.map((marker) => {
|
|
49162
|
+
const left = totalMinutes > 0 ? marker.minute / totalMinutes * 100 : 0;
|
|
49163
|
+
return /* @__PURE__ */ jsxs(
|
|
49164
|
+
"div",
|
|
49165
|
+
{
|
|
49166
|
+
className: "absolute flex -translate-x-1/2 flex-col items-center",
|
|
49167
|
+
style: { left: `${left}%` },
|
|
49168
|
+
children: [
|
|
49169
|
+
/* @__PURE__ */ jsx("span", { className: "mb-1.5 h-2 w-px bg-gray-300" }),
|
|
49170
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium text-gray-600 whitespace-nowrap", children: marker.label })
|
|
49171
|
+
]
|
|
49172
|
+
},
|
|
49173
|
+
`${marker.label}-${marker.minute}`
|
|
49174
|
+
);
|
|
49175
|
+
}) })
|
|
49176
|
+
] });
|
|
49177
|
+
};
|
|
49178
|
+
var UptimeTimelineStrip_default = UptimeTimelineStrip;
|
|
49179
|
+
var SHORT_INTERRUPT_THRESHOLD_MINUTES = 3;
|
|
49180
|
+
var formatDuration2 = (minutes) => {
|
|
49181
|
+
if (!minutes || minutes <= 0) return "0 min";
|
|
49182
|
+
const rounded = Math.max(Math.round(minutes), 0);
|
|
49183
|
+
const days = Math.floor(rounded / 1440);
|
|
49184
|
+
const hours = Math.floor(rounded % 1440 / 60);
|
|
49185
|
+
const mins = rounded % 60;
|
|
49186
|
+
const parts = [];
|
|
49187
|
+
if (days) parts.push(`${days} day${days === 1 ? "" : "s"}`);
|
|
49188
|
+
if (hours) parts.push(`${hours} hr${hours === 1 ? "" : "s"}`);
|
|
49189
|
+
if (mins) parts.push(`${mins} min${mins === 1 ? "" : "s"}`);
|
|
49190
|
+
if (!parts.length) {
|
|
49191
|
+
parts.push("1 min");
|
|
49192
|
+
}
|
|
49193
|
+
return parts.join(" ");
|
|
49194
|
+
};
|
|
49195
|
+
var formatDowntimeLabel2 = (minutes, includeSuffix = true) => {
|
|
49196
|
+
if (!minutes || minutes <= 0) {
|
|
49197
|
+
return includeSuffix ? "No downtime" : "0 min";
|
|
49198
|
+
}
|
|
49199
|
+
const label = formatDuration2(minutes);
|
|
49200
|
+
return includeSuffix ? `${label} down` : label;
|
|
49201
|
+
};
|
|
49202
|
+
var formatTimeRange = (start, end, timezone) => {
|
|
49203
|
+
const formatter = new Intl.DateTimeFormat("en-IN", {
|
|
49204
|
+
hour: "numeric",
|
|
49205
|
+
minute: "2-digit",
|
|
49206
|
+
hour12: true,
|
|
49207
|
+
timeZone: timezone
|
|
49208
|
+
});
|
|
49209
|
+
return `${formatter.format(start)} - ${formatter.format(end)}`;
|
|
49210
|
+
};
|
|
49211
|
+
var WorkspaceUptimeDetailModal = ({
|
|
49212
|
+
workspace,
|
|
49213
|
+
isOpen,
|
|
49214
|
+
onClose
|
|
49215
|
+
}) => {
|
|
49216
|
+
const timezone = useAppTimezone() || "UTC";
|
|
49217
|
+
const logsContainerRef = useRef(null);
|
|
49218
|
+
const [showScrollIndicator, setShowScrollIndicator] = useState(false);
|
|
49219
|
+
const {
|
|
49220
|
+
timeline,
|
|
49221
|
+
loading,
|
|
49222
|
+
error,
|
|
49223
|
+
refetch
|
|
49224
|
+
} = useWorkspaceUptimeTimeline({
|
|
49225
|
+
workspaceId: workspace?.workspace_id,
|
|
49226
|
+
companyId: workspace?.company_id,
|
|
49227
|
+
enabled: isOpen && Boolean(workspace?.workspace_id && workspace?.company_id),
|
|
49228
|
+
refreshInterval: 6e4
|
|
49229
|
+
});
|
|
49230
|
+
useEffect(() => {
|
|
49231
|
+
if (!isOpen || !workspace) return;
|
|
49232
|
+
const handleKeyDown = (event) => {
|
|
49233
|
+
if (event.key === "Escape") {
|
|
49234
|
+
onClose();
|
|
49235
|
+
}
|
|
49236
|
+
};
|
|
49237
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
49238
|
+
return () => {
|
|
49239
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
49240
|
+
};
|
|
49241
|
+
}, [isOpen, onClose, workspace]);
|
|
49242
|
+
const shiftStart = timeline ? new Date(timeline.shiftStart) : null;
|
|
49243
|
+
const shiftEnd = timeline ? new Date(timeline.shiftEnd) : null;
|
|
49244
|
+
const downtimeSegments = timeline?.downtimeSegments || [];
|
|
49245
|
+
downtimeSegments.length;
|
|
49246
|
+
const downtimeMinutes = timeline?.downtimeMinutes ?? 0;
|
|
49247
|
+
const uptimePercentage = timeline?.uptimePercentage ?? workspace?.uptimePercentage ?? 0;
|
|
49248
|
+
const allInterruptionsSorted = useMemo(
|
|
49249
|
+
() => [...downtimeSegments].sort(
|
|
49250
|
+
(a, b) => new Date(b.startTime).getTime() - new Date(a.startTime).getTime()
|
|
49251
|
+
),
|
|
49252
|
+
[downtimeSegments]
|
|
49253
|
+
);
|
|
49254
|
+
useEffect(() => {
|
|
49255
|
+
const checkScroll = () => {
|
|
49256
|
+
const container2 = logsContainerRef.current;
|
|
49257
|
+
if (container2) {
|
|
49258
|
+
const hasScroll = container2.scrollHeight > container2.clientHeight;
|
|
49259
|
+
const isAtBottom = container2.scrollHeight - container2.scrollTop <= container2.clientHeight + 10;
|
|
49260
|
+
setShowScrollIndicator(hasScroll && !isAtBottom);
|
|
49261
|
+
}
|
|
49262
|
+
};
|
|
49263
|
+
checkScroll();
|
|
49264
|
+
const container = logsContainerRef.current;
|
|
49265
|
+
if (container) {
|
|
49266
|
+
container.addEventListener("scroll", checkScroll);
|
|
49267
|
+
return () => container.removeEventListener("scroll", checkScroll);
|
|
49268
|
+
}
|
|
49269
|
+
}, [downtimeSegments]);
|
|
49270
|
+
const renderSegment = (segment) => {
|
|
49271
|
+
const start = new Date(segment.startTime);
|
|
49272
|
+
const end = new Date(segment.endTime);
|
|
49273
|
+
const isMajor = segment.durationMinutes >= SHORT_INTERRUPT_THRESHOLD_MINUTES;
|
|
49274
|
+
const containerClasses = isMajor ? "border-rose-200 bg-rose-50" : "border-gray-200 bg-white";
|
|
49275
|
+
return /* @__PURE__ */ jsxs(
|
|
49276
|
+
"div",
|
|
49277
|
+
{
|
|
49278
|
+
className: `rounded-lg border px-5 py-3 ${containerClasses}`,
|
|
49279
|
+
children: [
|
|
49280
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-gray-900", children: formatTimeRange(start, end, timezone) }),
|
|
49281
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-600 mt-1", children: [
|
|
49282
|
+
"Duration: ",
|
|
49283
|
+
formatDowntimeLabel2(segment.durationMinutes, false)
|
|
49284
|
+
] })
|
|
49285
|
+
]
|
|
49286
|
+
},
|
|
49287
|
+
`${segment.startMinuteIndex}-${segment.endMinuteIndex}`
|
|
49288
|
+
);
|
|
49289
|
+
};
|
|
49290
|
+
if (!isOpen || !workspace) {
|
|
49291
|
+
return null;
|
|
49292
|
+
}
|
|
49293
|
+
return /* @__PURE__ */ jsx(
|
|
49294
|
+
"div",
|
|
49295
|
+
{
|
|
49296
|
+
className: "fixed inset-0 z-[60] flex items-center justify-center bg-black/40 backdrop-blur-sm p-4",
|
|
49297
|
+
onClick: onClose,
|
|
49298
|
+
"aria-modal": "true",
|
|
49299
|
+
role: "dialog",
|
|
49300
|
+
"aria-labelledby": "uptime-detail-title",
|
|
49301
|
+
children: /* @__PURE__ */ jsxs(
|
|
49302
|
+
"div",
|
|
49303
|
+
{
|
|
49304
|
+
className: "relative flex w-full max-w-4xl max-h-[90vh] flex-col rounded-2xl bg-white shadow-2xl border border-gray-100",
|
|
49305
|
+
onClick: (event) => event.stopPropagation(),
|
|
49306
|
+
role: "document",
|
|
49307
|
+
"aria-labelledby": "uptime-detail-title",
|
|
49308
|
+
children: [
|
|
49309
|
+
/* @__PURE__ */ jsxs("header", { className: "flex items-start justify-between border-b border-gray-100 px-8 py-6 sticky top-0 z-10 bg-white rounded-t-2xl", children: [
|
|
49310
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0 mr-4", children: [
|
|
49311
|
+
/* @__PURE__ */ jsx("h2", { id: "uptime-detail-title", className: "text-2xl font-semibold text-gray-900 truncate mb-3", children: workspace.workspace_display_name || `Workspace ${workspace.workspace_id.slice(0, 6)}` }),
|
|
49312
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 text-sm text-gray-600", children: [
|
|
49313
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-gray-900", children: timeline?.shiftLabel || "Current Shift" }),
|
|
49314
|
+
shiftStart && shiftEnd && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
49315
|
+
/* @__PURE__ */ jsx("span", { className: "text-gray-300", children: "\u2022" }),
|
|
49316
|
+
/* @__PURE__ */ jsx("span", { className: "text-gray-600", children: formatTimeRange(shiftStart, shiftEnd, timezone) })
|
|
49317
|
+
] })
|
|
49318
|
+
] }),
|
|
49319
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center gap-2", children: [
|
|
49320
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
49321
|
+
/* @__PURE__ */ jsx("div", { className: `w-2 h-2 rounded-full ${workspace.status === "healthy" ? "bg-emerald-500 animate-pulse" : workspace.status === "warning" ? "bg-amber-500" : "bg-rose-500"}` }),
|
|
49322
|
+
/* @__PURE__ */ jsx("span", { className: `text-xs font-medium ${workspace.status === "healthy" ? "text-emerald-700" : workspace.status === "warning" ? "text-amber-700" : "text-rose-700"}`, children: workspace.status === "healthy" ? "Operational" : workspace.status === "warning" ? "Intermittent" : "Down" })
|
|
49323
|
+
] }),
|
|
49324
|
+
/* @__PURE__ */ jsx("span", { className: "text-gray-300", children: "\u2022" }),
|
|
49325
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500", children: [
|
|
49326
|
+
"Last heartbeat ",
|
|
49327
|
+
workspace.timeSinceLastUpdate
|
|
49328
|
+
] })
|
|
49329
|
+
] })
|
|
49330
|
+
] }),
|
|
49331
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [
|
|
49332
|
+
/* @__PURE__ */ jsxs(
|
|
49333
|
+
"button",
|
|
49334
|
+
{
|
|
49335
|
+
onClick: refetch,
|
|
49336
|
+
disabled: loading,
|
|
49337
|
+
className: "inline-flex items-center gap-2 rounded-lg border border-gray-200 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50 transition-all duration-200 shadow-sm",
|
|
49338
|
+
children: [
|
|
49339
|
+
/* @__PURE__ */ jsx(RefreshCw, { className: `h-4 w-4 ${loading ? "animate-spin" : ""}` }),
|
|
49340
|
+
/* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "Refresh" })
|
|
49341
|
+
]
|
|
49342
|
+
}
|
|
49343
|
+
),
|
|
49344
|
+
/* @__PURE__ */ jsx(
|
|
49345
|
+
"button",
|
|
49346
|
+
{
|
|
49347
|
+
onClick: onClose,
|
|
49348
|
+
className: "rounded-lg p-2 text-gray-400 hover:bg-gray-100 hover:text-gray-600 transition-colors duration-200",
|
|
49349
|
+
"aria-label": "Close uptime details",
|
|
49350
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-5 w-5" })
|
|
49351
|
+
}
|
|
49352
|
+
)
|
|
49353
|
+
] })
|
|
49354
|
+
] }),
|
|
49355
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsx("div", { className: "px-8 py-6 space-y-6", children: error ? /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-rose-100 bg-rose-50 p-5 text-sm text-rose-700", children: [
|
|
49356
|
+
/* @__PURE__ */ jsx("p", { className: "font-semibold mb-1", children: "Unable to load uptime details" }),
|
|
49357
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-rose-600/90", children: error.message })
|
|
49358
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
49359
|
+
/* @__PURE__ */ jsxs("div", { className: "relative pb-4 border-b border-gray-200", children: [
|
|
49360
|
+
/* @__PURE__ */ jsx(
|
|
49361
|
+
UptimeTimelineStrip_default,
|
|
49362
|
+
{
|
|
49363
|
+
points: timeline?.points || [],
|
|
49364
|
+
totalMinutes: timeline?.totalMinutes || 0,
|
|
49365
|
+
shiftStart: timeline?.shiftStart || (/* @__PURE__ */ new Date()).toISOString(),
|
|
49366
|
+
shiftEnd: timeline?.shiftEnd || (/* @__PURE__ */ new Date()).toISOString(),
|
|
49367
|
+
timezone,
|
|
49368
|
+
uptimePercentage,
|
|
49369
|
+
downtimeMinutes
|
|
49370
|
+
}
|
|
49371
|
+
),
|
|
49372
|
+
loading && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-gray-600 mt-4", children: [
|
|
49373
|
+
/* @__PURE__ */ jsx(RefreshCw, { className: "h-4 w-4 animate-spin text-gray-500" }),
|
|
49374
|
+
/* @__PURE__ */ jsx("span", { children: "Updating timeline\u2026" })
|
|
49375
|
+
] })
|
|
49376
|
+
] }),
|
|
49377
|
+
/* @__PURE__ */ jsxs("div", { className: "pt-4", children: [
|
|
49378
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-900 uppercase tracking-wider mb-3", children: "Downtime Logs" }),
|
|
49379
|
+
downtimeSegments.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-gray-100 bg-gray-50/50 px-5 py-4 text-center", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-600", children: "No downtime events recorded for this shift." }) }) : /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
49380
|
+
/* @__PURE__ */ jsx(
|
|
49381
|
+
"div",
|
|
49382
|
+
{
|
|
49383
|
+
ref: logsContainerRef,
|
|
49384
|
+
className: "max-h-[400px] overflow-y-auto space-y-2 pr-2",
|
|
49385
|
+
style: {
|
|
49386
|
+
scrollbarWidth: "thin",
|
|
49387
|
+
scrollbarColor: "#CBD5E0 #F7FAFC"
|
|
49388
|
+
},
|
|
49389
|
+
children: allInterruptionsSorted.map((segment) => renderSegment(segment))
|
|
49390
|
+
}
|
|
49391
|
+
),
|
|
49392
|
+
showScrollIndicator && /* @__PURE__ */ jsx("div", { className: "absolute bottom-0 left-0 right-0 h-12 bg-gradient-to-t from-white via-white/80 to-transparent pointer-events-none flex items-end justify-center pb-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs text-gray-500 animate-bounce", children: [
|
|
49393
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" }),
|
|
49394
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Scroll for more" }),
|
|
49395
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" })
|
|
49396
|
+
] }) })
|
|
49397
|
+
] })
|
|
49398
|
+
] })
|
|
49399
|
+
] }) }) })
|
|
49400
|
+
]
|
|
49401
|
+
}
|
|
49402
|
+
)
|
|
49403
|
+
}
|
|
49404
|
+
);
|
|
49405
|
+
};
|
|
49406
|
+
var WorkspaceUptimeDetailModal_default = WorkspaceUptimeDetailModal;
|
|
48744
49407
|
var WorkspaceHealthView = ({
|
|
48745
49408
|
lineId,
|
|
48746
49409
|
companyId,
|
|
@@ -48750,6 +49413,7 @@ var WorkspaceHealthView = ({
|
|
|
48750
49413
|
const router = useRouter();
|
|
48751
49414
|
const [groupBy, setGroupBy] = useState("line");
|
|
48752
49415
|
const timezone = useAppTimezone();
|
|
49416
|
+
const [selectedWorkspace, setSelectedWorkspace] = useState(null);
|
|
48753
49417
|
const operationalDate = getOperationalDate(timezone || "UTC");
|
|
48754
49418
|
const currentHour = (/* @__PURE__ */ new Date()).getHours();
|
|
48755
49419
|
const isNightShift = currentHour >= 18 || currentHour < 6;
|
|
@@ -48790,6 +49454,12 @@ var WorkspaceHealthView = ({
|
|
|
48790
49454
|
},
|
|
48791
49455
|
[router, onNavigate]
|
|
48792
49456
|
);
|
|
49457
|
+
const handleViewDetails = useCallback((workspace) => {
|
|
49458
|
+
setSelectedWorkspace(workspace);
|
|
49459
|
+
}, []);
|
|
49460
|
+
const handleCloseDetails = useCallback(() => {
|
|
49461
|
+
setSelectedWorkspace(null);
|
|
49462
|
+
}, []);
|
|
48793
49463
|
const handleExport = useCallback(() => {
|
|
48794
49464
|
const csv = [
|
|
48795
49465
|
["Workspace", "Line", "Company", "Status", "Last Heartbeat", "Consecutive Misses"],
|
|
@@ -48847,178 +49517,189 @@ var WorkspaceHealthView = ({
|
|
|
48847
49517
|
)
|
|
48848
49518
|
] }) }) }) });
|
|
48849
49519
|
}
|
|
48850
|
-
return /* @__PURE__ */ jsxs(
|
|
48851
|
-
/* @__PURE__ */ jsxs("
|
|
48852
|
-
/* @__PURE__ */ jsxs("
|
|
48853
|
-
/* @__PURE__ */ jsxs("div", { className: "
|
|
48854
|
-
/* @__PURE__ */
|
|
49520
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
49521
|
+
/* @__PURE__ */ jsxs("div", { className: clsx("min-h-screen bg-slate-50", className), children: [
|
|
49522
|
+
/* @__PURE__ */ jsxs("header", { className: "sticky top-0 z-10 px-3 sm:px-4 md:px-5 lg:px-6 py-2 sm:py-2.5 lg:py-3 flex flex-col shadow-sm bg-white", children: [
|
|
49523
|
+
/* @__PURE__ */ jsxs("div", { className: "sm:hidden", children: [
|
|
49524
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-1", children: [
|
|
49525
|
+
/* @__PURE__ */ jsx(
|
|
49526
|
+
BackButtonMinimal,
|
|
49527
|
+
{
|
|
49528
|
+
onClick: () => router.push("/"),
|
|
49529
|
+
text: "Back",
|
|
49530
|
+
size: "sm",
|
|
49531
|
+
"aria-label": "Navigate back to dashboard"
|
|
49532
|
+
}
|
|
49533
|
+
),
|
|
49534
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
49535
|
+
/* @__PURE__ */ jsx(
|
|
49536
|
+
"button",
|
|
49537
|
+
{
|
|
49538
|
+
onClick: () => {
|
|
49539
|
+
refetch();
|
|
49540
|
+
},
|
|
49541
|
+
className: "p-1.5 text-gray-600 hover:bg-gray-100 rounded-lg transition-colors",
|
|
49542
|
+
"aria-label": "Refresh",
|
|
49543
|
+
children: /* @__PURE__ */ jsx(RefreshCw, { className: "h-4 w-4" })
|
|
49544
|
+
}
|
|
49545
|
+
),
|
|
49546
|
+
/* @__PURE__ */ jsx(
|
|
49547
|
+
"button",
|
|
49548
|
+
{
|
|
49549
|
+
onClick: handleExport,
|
|
49550
|
+
className: "p-1.5 text-gray-600 hover:bg-gray-100 rounded-lg transition-colors",
|
|
49551
|
+
"aria-label": "Export CSV",
|
|
49552
|
+
children: /* @__PURE__ */ jsx(Download, { className: "h-4 w-4" })
|
|
49553
|
+
}
|
|
49554
|
+
)
|
|
49555
|
+
] })
|
|
49556
|
+
] }),
|
|
49557
|
+
/* @__PURE__ */ jsx("div", { className: "text-center", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-2", children: [
|
|
49558
|
+
/* @__PURE__ */ jsx("h1", { className: "text-base font-semibold text-gray-900", children: "System Health" }),
|
|
49559
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex h-2 w-2", children: [
|
|
49560
|
+
/* @__PURE__ */ jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75" }),
|
|
49561
|
+
/* @__PURE__ */ jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-emerald-500" })
|
|
49562
|
+
] })
|
|
49563
|
+
] }) })
|
|
49564
|
+
] }),
|
|
49565
|
+
/* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxs("div", { className: "relative flex items-center", children: [
|
|
49566
|
+
/* @__PURE__ */ jsx("div", { className: "absolute left-0 z-10", children: /* @__PURE__ */ jsx(
|
|
48855
49567
|
BackButtonMinimal,
|
|
48856
49568
|
{
|
|
48857
49569
|
onClick: () => router.push("/"),
|
|
48858
49570
|
text: "Back",
|
|
48859
|
-
size: "
|
|
49571
|
+
size: "default",
|
|
48860
49572
|
"aria-label": "Navigate back to dashboard"
|
|
48861
49573
|
}
|
|
48862
|
-
),
|
|
48863
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-
|
|
49574
|
+
) }),
|
|
49575
|
+
/* @__PURE__ */ jsx("div", { className: "absolute left-1/2 transform -translate-x-1/2 max-w-[calc(100%-200px)]", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
49576
|
+
/* @__PURE__ */ jsx("h1", { className: "text-lg md:text-xl lg:text-2xl xl:text-3xl font-semibold text-gray-900 truncate", children: "System Health" }),
|
|
49577
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex h-2.5 w-2.5", children: [
|
|
49578
|
+
/* @__PURE__ */ jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75" }),
|
|
49579
|
+
/* @__PURE__ */ jsx("span", { className: "relative inline-flex rounded-full h-2.5 w-2.5 bg-emerald-500" })
|
|
49580
|
+
] })
|
|
49581
|
+
] }) }),
|
|
49582
|
+
/* @__PURE__ */ jsxs("div", { className: "absolute right-0 flex gap-2", children: [
|
|
48864
49583
|
/* @__PURE__ */ jsx(
|
|
48865
49584
|
"button",
|
|
48866
49585
|
{
|
|
48867
49586
|
onClick: () => {
|
|
48868
49587
|
refetch();
|
|
48869
49588
|
},
|
|
48870
|
-
className: "p-
|
|
49589
|
+
className: "p-2 text-gray-600 hover:bg-gray-100 rounded-lg transition-colors",
|
|
48871
49590
|
"aria-label": "Refresh",
|
|
48872
|
-
children: /* @__PURE__ */ jsx(RefreshCw, { className: "h-
|
|
49591
|
+
children: /* @__PURE__ */ jsx(RefreshCw, { className: "h-5 w-5" })
|
|
48873
49592
|
}
|
|
48874
49593
|
),
|
|
48875
49594
|
/* @__PURE__ */ jsx(
|
|
48876
49595
|
"button",
|
|
48877
49596
|
{
|
|
48878
49597
|
onClick: handleExport,
|
|
48879
|
-
className: "p-
|
|
49598
|
+
className: "p-2 text-gray-600 hover:bg-gray-100 rounded-lg transition-colors",
|
|
48880
49599
|
"aria-label": "Export CSV",
|
|
48881
|
-
children: /* @__PURE__ */ jsx(Download, { className: "h-
|
|
49600
|
+
children: /* @__PURE__ */ jsx(Download, { className: "h-5 w-5" })
|
|
48882
49601
|
}
|
|
48883
49602
|
)
|
|
48884
|
-
] })
|
|
48885
|
-
|
|
48886
|
-
|
|
48887
|
-
|
|
48888
|
-
/* @__PURE__ */
|
|
48889
|
-
|
|
48890
|
-
|
|
49603
|
+
] }),
|
|
49604
|
+
/* @__PURE__ */ jsx("div", { className: "w-full h-8" })
|
|
49605
|
+
] }) }),
|
|
49606
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1 sm:mt-2 bg-blue-50 px-2 sm:px-3 py-1.5 sm:py-2 rounded-lg", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-center gap-2 sm:gap-4", children: [
|
|
49607
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm sm:text-base md:text-lg font-medium text-blue-600", children: /* @__PURE__ */ jsx(LiveTimer, {}) }),
|
|
49608
|
+
/* @__PURE__ */ jsx("div", { className: "hidden sm:block w-px h-4 bg-blue-300" }),
|
|
49609
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm md:text-base font-medium text-blue-600", children: formatDate(operationalDate) }),
|
|
49610
|
+
/* @__PURE__ */ jsx("div", { className: "hidden sm:block w-px h-4 bg-blue-300" }),
|
|
49611
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 sm:gap-2", children: [
|
|
49612
|
+
/* @__PURE__ */ jsx("div", { className: "text-blue-600", children: getShiftIcon(shiftType) }),
|
|
49613
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs sm:text-sm md:text-base font-medium text-blue-600", children: [
|
|
49614
|
+
shiftType,
|
|
49615
|
+
" Shift"
|
|
49616
|
+
] })
|
|
48891
49617
|
] })
|
|
48892
49618
|
] }) })
|
|
48893
49619
|
] }),
|
|
48894
|
-
/* @__PURE__ */
|
|
48895
|
-
|
|
48896
|
-
|
|
49620
|
+
/* @__PURE__ */ jsxs("div", { className: "max-w-7xl mx-auto p-4 space-y-6", children: [
|
|
49621
|
+
summary && /* @__PURE__ */ jsxs(
|
|
49622
|
+
motion.div,
|
|
48897
49623
|
{
|
|
48898
|
-
|
|
48899
|
-
|
|
48900
|
-
|
|
48901
|
-
"
|
|
48902
|
-
|
|
48903
|
-
|
|
48904
|
-
|
|
48905
|
-
|
|
48906
|
-
|
|
48907
|
-
|
|
48908
|
-
|
|
48909
|
-
|
|
48910
|
-
|
|
48911
|
-
|
|
48912
|
-
/* @__PURE__ */ jsx(
|
|
48913
|
-
"button",
|
|
48914
|
-
{
|
|
48915
|
-
onClick: () => {
|
|
48916
|
-
refetch();
|
|
48917
|
-
},
|
|
48918
|
-
className: "p-2 text-gray-600 hover:bg-gray-100 rounded-lg transition-colors",
|
|
48919
|
-
"aria-label": "Refresh",
|
|
48920
|
-
children: /* @__PURE__ */ jsx(RefreshCw, { className: "h-5 w-5" })
|
|
48921
|
-
}
|
|
48922
|
-
),
|
|
48923
|
-
/* @__PURE__ */ jsx(
|
|
48924
|
-
"button",
|
|
48925
|
-
{
|
|
48926
|
-
onClick: handleExport,
|
|
48927
|
-
className: "p-2 text-gray-600 hover:bg-gray-100 rounded-lg transition-colors",
|
|
48928
|
-
"aria-label": "Export CSV",
|
|
48929
|
-
children: /* @__PURE__ */ jsx(Download, { className: "h-5 w-5" })
|
|
48930
|
-
}
|
|
48931
|
-
)
|
|
48932
|
-
] }),
|
|
48933
|
-
/* @__PURE__ */ jsx("div", { className: "w-full h-8" })
|
|
48934
|
-
] }) }),
|
|
48935
|
-
/* @__PURE__ */ jsx("div", { className: "mt-2 sm:mt-3 bg-blue-50 px-2 sm:px-3 py-1.5 sm:py-2 rounded-lg", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-center gap-2 sm:gap-4", children: [
|
|
48936
|
-
/* @__PURE__ */ jsx("div", { className: "text-sm sm:text-base md:text-lg font-medium text-blue-600", children: /* @__PURE__ */ jsx(LiveTimer, {}) }),
|
|
48937
|
-
/* @__PURE__ */ jsx("div", { className: "hidden sm:block w-px h-4 bg-blue-300" }),
|
|
48938
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm md:text-base font-medium text-blue-600", children: formatDate(operationalDate) }),
|
|
48939
|
-
/* @__PURE__ */ jsx("div", { className: "hidden sm:block w-px h-4 bg-blue-300" }),
|
|
48940
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 sm:gap-2", children: [
|
|
48941
|
-
/* @__PURE__ */ jsx("div", { className: "text-blue-600", children: getShiftIcon(shiftType) }),
|
|
48942
|
-
/* @__PURE__ */ jsxs("span", { className: "text-xs sm:text-sm md:text-base font-medium text-blue-600", children: [
|
|
48943
|
-
shiftType,
|
|
48944
|
-
" Shift"
|
|
48945
|
-
] })
|
|
48946
|
-
] })
|
|
48947
|
-
] }) })
|
|
48948
|
-
] }),
|
|
48949
|
-
/* @__PURE__ */ jsxs("div", { className: "max-w-7xl mx-auto p-4 space-y-6", children: [
|
|
48950
|
-
summary && /* @__PURE__ */ jsxs(
|
|
48951
|
-
motion.div,
|
|
48952
|
-
{
|
|
48953
|
-
initial: { opacity: 0, y: 20 },
|
|
48954
|
-
animate: { opacity: 1, y: 0 },
|
|
48955
|
-
transition: { duration: 0.3, delay: 0.1 },
|
|
48956
|
-
className: "grid grid-cols-2 sm:grid-cols-2 md:grid-cols-5 gap-2 sm:gap-3 lg:gap-4",
|
|
48957
|
-
children: [
|
|
48958
|
-
/* @__PURE__ */ jsxs(Card2, { className: "col-span-2 sm:col-span-2 md:col-span-2 bg-white", children: [
|
|
48959
|
-
/* @__PURE__ */ jsx(CardHeader2, { className: "pb-3", children: /* @__PURE__ */ jsx(CardTitle2, { className: "text-sm font-medium text-gray-500 dark:text-gray-400", children: "System Availability" }) }),
|
|
48960
|
-
/* @__PURE__ */ jsxs(CardContent2, { children: [
|
|
48961
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2", children: [
|
|
48962
|
-
/* @__PURE__ */ jsxs("span", { className: clsx("text-3xl font-bold", getUptimeColor(summary.uptimePercentage)), children: [
|
|
48963
|
-
summary.uptimePercentage.toFixed(1),
|
|
48964
|
-
"%"
|
|
49624
|
+
initial: { opacity: 0, y: 20 },
|
|
49625
|
+
animate: { opacity: 1, y: 0 },
|
|
49626
|
+
transition: { duration: 0.3, delay: 0.1 },
|
|
49627
|
+
className: "grid grid-cols-2 sm:grid-cols-2 md:grid-cols-5 gap-2 sm:gap-3 lg:gap-4",
|
|
49628
|
+
children: [
|
|
49629
|
+
/* @__PURE__ */ jsxs(Card2, { className: "col-span-2 sm:col-span-2 md:col-span-2 bg-white", children: [
|
|
49630
|
+
/* @__PURE__ */ jsx(CardHeader2, { className: "pb-3", children: /* @__PURE__ */ jsx(CardTitle2, { className: "text-sm font-medium text-gray-500 dark:text-gray-400", children: "System Availability" }) }),
|
|
49631
|
+
/* @__PURE__ */ jsxs(CardContent2, { children: [
|
|
49632
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2", children: [
|
|
49633
|
+
/* @__PURE__ */ jsxs("span", { className: clsx("text-3xl font-bold", getUptimeColor(summary.uptimePercentage)), children: [
|
|
49634
|
+
summary.uptimePercentage.toFixed(1),
|
|
49635
|
+
"%"
|
|
49636
|
+
] }),
|
|
49637
|
+
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" })
|
|
48965
49638
|
] }),
|
|
48966
|
-
|
|
48967
|
-
] })
|
|
48968
|
-
|
|
48969
|
-
|
|
48970
|
-
|
|
48971
|
-
|
|
48972
|
-
|
|
48973
|
-
|
|
48974
|
-
|
|
48975
|
-
|
|
48976
|
-
|
|
48977
|
-
|
|
48978
|
-
|
|
48979
|
-
|
|
48980
|
-
|
|
48981
|
-
|
|
48982
|
-
|
|
48983
|
-
|
|
48984
|
-
|
|
48985
|
-
|
|
48986
|
-
|
|
48987
|
-
|
|
48988
|
-
|
|
48989
|
-
|
|
48990
|
-
|
|
48991
|
-
|
|
48992
|
-
|
|
48993
|
-
|
|
48994
|
-
|
|
48995
|
-
|
|
48996
|
-
|
|
48997
|
-
|
|
48998
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: "Requires attention" })
|
|
49639
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: "Overall system uptime today" })
|
|
49640
|
+
] })
|
|
49641
|
+
] }),
|
|
49642
|
+
/* @__PURE__ */ jsxs(Card2, { className: "bg-white", children: [
|
|
49643
|
+
/* @__PURE__ */ jsx(CardHeader2, { className: "pb-3", children: /* @__PURE__ */ jsxs(CardTitle2, { className: "text-sm font-medium text-gray-500 dark:text-gray-400 flex items-center gap-2", children: [
|
|
49644
|
+
getStatusIcon("healthy"),
|
|
49645
|
+
"Healthy"
|
|
49646
|
+
] }) }),
|
|
49647
|
+
/* @__PURE__ */ jsxs(CardContent2, { children: [
|
|
49648
|
+
/* @__PURE__ */ jsx("p", { className: "text-2xl font-bold text-gray-900 dark:text-gray-50", children: summary.healthyWorkspaces }),
|
|
49649
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: "Operating normally" })
|
|
49650
|
+
] })
|
|
49651
|
+
] }),
|
|
49652
|
+
/* @__PURE__ */ jsxs(Card2, { className: "bg-white", children: [
|
|
49653
|
+
/* @__PURE__ */ jsx(CardHeader2, { className: "pb-3", children: /* @__PURE__ */ jsxs(CardTitle2, { className: "text-sm font-medium text-gray-500 dark:text-gray-400 flex items-center gap-2", children: [
|
|
49654
|
+
getStatusIcon("warning"),
|
|
49655
|
+
"Warning"
|
|
49656
|
+
] }) }),
|
|
49657
|
+
/* @__PURE__ */ jsxs(CardContent2, { children: [
|
|
49658
|
+
/* @__PURE__ */ jsx("p", { className: "text-2xl font-bold text-gray-900 dark:text-gray-50", children: summary.warningWorkspaces }),
|
|
49659
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: "Delayed updates" })
|
|
49660
|
+
] })
|
|
49661
|
+
] }),
|
|
49662
|
+
/* @__PURE__ */ jsxs(Card2, { className: "bg-white", children: [
|
|
49663
|
+
/* @__PURE__ */ jsx(CardHeader2, { className: "pb-3", children: /* @__PURE__ */ jsxs(CardTitle2, { className: "text-sm font-medium text-gray-500 dark:text-gray-400 flex items-center gap-2", children: [
|
|
49664
|
+
getStatusIcon("unhealthy"),
|
|
49665
|
+
"Unhealthy"
|
|
49666
|
+
] }) }),
|
|
49667
|
+
/* @__PURE__ */ jsxs(CardContent2, { children: [
|
|
49668
|
+
/* @__PURE__ */ jsx("p", { className: "text-2xl font-bold text-gray-900 dark:text-gray-50", children: summary.unhealthyWorkspaces }),
|
|
49669
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: "Requires attention" })
|
|
49670
|
+
] })
|
|
48999
49671
|
] })
|
|
49000
|
-
]
|
|
49001
|
-
|
|
49002
|
-
|
|
49003
|
-
|
|
49004
|
-
|
|
49005
|
-
|
|
49006
|
-
|
|
49007
|
-
|
|
49008
|
-
|
|
49009
|
-
|
|
49010
|
-
|
|
49011
|
-
|
|
49012
|
-
|
|
49013
|
-
|
|
49014
|
-
|
|
49015
|
-
|
|
49016
|
-
|
|
49017
|
-
|
|
49018
|
-
|
|
49019
|
-
|
|
49020
|
-
|
|
49021
|
-
|
|
49672
|
+
]
|
|
49673
|
+
}
|
|
49674
|
+
),
|
|
49675
|
+
/* @__PURE__ */ jsx(
|
|
49676
|
+
motion.div,
|
|
49677
|
+
{
|
|
49678
|
+
initial: { opacity: 0, y: 20 },
|
|
49679
|
+
animate: { opacity: 1, y: 0 },
|
|
49680
|
+
transition: { duration: 0.3, delay: 0.2 },
|
|
49681
|
+
children: /* @__PURE__ */ jsx(
|
|
49682
|
+
HealthStatusGrid,
|
|
49683
|
+
{
|
|
49684
|
+
workspaces,
|
|
49685
|
+
onWorkspaceClick: handleWorkspaceClick,
|
|
49686
|
+
onWorkspaceViewDetails: handleViewDetails,
|
|
49687
|
+
showFilters: true,
|
|
49688
|
+
groupBy
|
|
49689
|
+
}
|
|
49690
|
+
)
|
|
49691
|
+
}
|
|
49692
|
+
)
|
|
49693
|
+
] })
|
|
49694
|
+
] }),
|
|
49695
|
+
/* @__PURE__ */ jsx(
|
|
49696
|
+
WorkspaceUptimeDetailModal_default,
|
|
49697
|
+
{
|
|
49698
|
+
workspace: selectedWorkspace,
|
|
49699
|
+
isOpen: Boolean(selectedWorkspace),
|
|
49700
|
+
onClose: handleCloseDetails
|
|
49701
|
+
}
|
|
49702
|
+
)
|
|
49022
49703
|
] });
|
|
49023
49704
|
};
|
|
49024
49705
|
var WorkspaceHealthView_default = withAuth(WorkspaceHealthView, {
|
|
@@ -52587,4 +53268,4 @@ function shuffleArray(array) {
|
|
|
52587
53268
|
return shuffled;
|
|
52588
53269
|
}
|
|
52589
53270
|
|
|
52590
|
-
export { ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ClipFilterProvider, CompactWorkspaceHealthCard, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EmptyStateMessage, EncouragementOverlay, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, InlineEditableText, InteractiveOnboardingTour, InvitationService, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend6 as Legend, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UserManagementService, UserService, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, authCoreService, authOTPService, authRateLimitService, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createInvitationService, createLinesService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getNextUpdateInterval, getOperationalDate, getS3SignedUrl, getS3VideoSrc, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, identifyCoreUser, initializeCoreMixpanel, isLegacyConfiguration, isPrefetchError, isSafari, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, optifyeAgentClient, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, updateThreadTitle, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useMessages, useMetrics, useNavigation, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useShiftConfig, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, userService, videoPrefetchManager, videoPreloader, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
|
|
53271
|
+
export { ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ClipFilterProvider, CompactWorkspaceHealthCard, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EmptyStateMessage, EncouragementOverlay, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, InlineEditableText, InteractiveOnboardingTour, InvitationService, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend6 as Legend, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UserManagementService, UserService, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, authCoreService, authOTPService, authRateLimitService, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createInvitationService, createLinesService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getNextUpdateInterval, getOperationalDate, getS3SignedUrl, getS3VideoSrc, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, identifyCoreUser, initializeCoreMixpanel, isLegacyConfiguration, isPrefetchError, isSafari, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, optifyeAgentClient, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, updateThreadTitle, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useMessages, useMetrics, useNavigation, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useShiftConfig, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, userService, videoPrefetchManager, videoPreloader, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
|