@optifye/dashboard-core 6.12.5 → 6.12.7
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 +23 -4
- package/dist/index.d.mts +42 -1
- package/dist/index.d.ts +42 -1
- package/dist/index.js +817 -161
- package/dist/index.mjs +818 -163
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5257,46 +5257,83 @@ var dashboardService = {
|
|
|
5257
5257
|
const dbConfig = config.databaseConfig ?? DEFAULT_DATABASE_CONFIG;
|
|
5258
5258
|
const linesTable = getTable(dbConfig, "lines");
|
|
5259
5259
|
const companyId = config.entityConfig?.companyId;
|
|
5260
|
+
const baseLineSelect = `
|
|
5261
|
+
id,
|
|
5262
|
+
line_name,
|
|
5263
|
+
factory_id,
|
|
5264
|
+
factories!lines_factory_id_fkey(factory_name),
|
|
5265
|
+
company_id,
|
|
5266
|
+
companies!lines_company_id_fkey(company_name:name),
|
|
5267
|
+
enable,
|
|
5268
|
+
monitoring_mode,
|
|
5269
|
+
assembly,
|
|
5270
|
+
video_grid_metric_mode,
|
|
5271
|
+
recent_flow_window_minutes
|
|
5272
|
+
`;
|
|
5273
|
+
const lineSelectWithArea = `
|
|
5274
|
+
${baseLineSelect},
|
|
5275
|
+
factory_area_id,
|
|
5276
|
+
factory_line_areas!lines_factory_area_id_factory_id_fkey(
|
|
5277
|
+
area_key,
|
|
5278
|
+
area_name,
|
|
5279
|
+
sort_order,
|
|
5280
|
+
enabled
|
|
5281
|
+
)
|
|
5282
|
+
`;
|
|
5283
|
+
const shouldRetryWithoutFactoryArea = (error) => {
|
|
5284
|
+
const errorText = [
|
|
5285
|
+
error?.message,
|
|
5286
|
+
error?.details,
|
|
5287
|
+
error?.hint,
|
|
5288
|
+
error?.code
|
|
5289
|
+
].filter(Boolean).join(" ").toLowerCase();
|
|
5290
|
+
return errorText.includes("factory_area_id") || errorText.includes("factory_line_areas") || errorText.includes("lines_factory_area_id_factory_id_fkey");
|
|
5291
|
+
};
|
|
5260
5292
|
try {
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
query = query.eq("company_id", companyId);
|
|
5276
|
-
}
|
|
5277
|
-
const { data, error } = await query;
|
|
5293
|
+
const fetchLines = async (selectClause) => {
|
|
5294
|
+
let query = supabase.from(linesTable).select(selectClause).eq("enable", true);
|
|
5295
|
+
if (companyId) {
|
|
5296
|
+
query = query.eq("company_id", companyId);
|
|
5297
|
+
}
|
|
5298
|
+
return await query;
|
|
5299
|
+
};
|
|
5300
|
+
let { data, error } = await fetchLines(lineSelectWithArea);
|
|
5301
|
+
if (error && shouldRetryWithoutFactoryArea(error)) {
|
|
5302
|
+
console.warn("[dashboardService.getAllLines] Factory area metadata unavailable, falling back to line-only metadata:", error);
|
|
5303
|
+
const fallbackResult = await fetchLines(baseLineSelect);
|
|
5304
|
+
data = fallbackResult.data;
|
|
5305
|
+
error = fallbackResult.error;
|
|
5306
|
+
}
|
|
5278
5307
|
if (error) {
|
|
5279
5308
|
console.error("Error fetching all lines:", error);
|
|
5280
5309
|
throw error;
|
|
5281
5310
|
}
|
|
5282
5311
|
if (!data) return [];
|
|
5283
|
-
const transformedLines = data.map((line) =>
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
line.
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5312
|
+
const transformedLines = data.map((line) => {
|
|
5313
|
+
const factoryArea = Array.isArray(line.factory_line_areas) ? line.factory_line_areas[0] : line.factory_line_areas;
|
|
5314
|
+
return {
|
|
5315
|
+
id: line.id,
|
|
5316
|
+
line_name: line.line_name,
|
|
5317
|
+
factory_id: line.factory_id,
|
|
5318
|
+
factory_name: line.factories?.factory_name ?? "N/A",
|
|
5319
|
+
company_id: line.company_id,
|
|
5320
|
+
company_name: line.companies?.company_name ?? "N/A",
|
|
5321
|
+
enable: line.enable ?? true,
|
|
5322
|
+
// Default to true if not specified
|
|
5323
|
+
monitoring_mode: line.monitoring_mode ?? "output",
|
|
5324
|
+
assembly: line.assembly ?? false,
|
|
5325
|
+
video_grid_metric_mode: normalizeVideoGridMetricMode(
|
|
5326
|
+
line.video_grid_metric_mode,
|
|
5327
|
+
line.assembly ?? false
|
|
5328
|
+
),
|
|
5329
|
+
recent_flow_window_minutes: line.recent_flow_window_minutes ?? 7,
|
|
5330
|
+
factory_area_id: line.factory_area_id ?? null,
|
|
5331
|
+
factory_area_key: factoryArea?.area_key ?? null,
|
|
5332
|
+
factory_area_name: factoryArea?.area_name ?? null,
|
|
5333
|
+
factory_area_sort_order: factoryArea?.sort_order ?? null,
|
|
5334
|
+
factory_area_enabled: factoryArea?.enabled ?? null
|
|
5335
|
+
};
|
|
5336
|
+
});
|
|
5300
5337
|
return transformedLines;
|
|
5301
5338
|
} catch (err) {
|
|
5302
5339
|
console.error("Exception in getAllLines:", err);
|
|
@@ -14265,7 +14302,9 @@ var useLeaderboardMetrics = (date, shiftId, limit = 10, filter2 = "all") => {
|
|
|
14265
14302
|
`/api/dashboard/leaderboard?${params.toString()}`
|
|
14266
14303
|
);
|
|
14267
14304
|
let entries = (data.entries || []).slice();
|
|
14268
|
-
entries.sort(
|
|
14305
|
+
entries.sort(
|
|
14306
|
+
(a, b) => (b.leaderboard_value ?? b.efficiency ?? 0) - (a.leaderboard_value ?? a.efficiency ?? 0)
|
|
14307
|
+
);
|
|
14269
14308
|
if (filter2 === "top") {
|
|
14270
14309
|
entries = entries.slice(0, limit);
|
|
14271
14310
|
} else if (filter2 === "bottom") {
|
|
@@ -21902,6 +21941,24 @@ var getConfigurableShortWorkspaceDisplayName = (workspaceId, workspaceConfig, li
|
|
|
21902
21941
|
return fullName;
|
|
21903
21942
|
};
|
|
21904
21943
|
|
|
21944
|
+
// src/lib/utils/efficiencyValidity.ts
|
|
21945
|
+
var MIN_VALID_OUTPUT_EFFICIENCY = 5;
|
|
21946
|
+
var MIN_VALID_UPTIME_EFFICIENCY = 1;
|
|
21947
|
+
var normalizeMonitoringMode = (mode) => String(mode ?? "").trim().toLowerCase() === "uptime" ? "uptime" : "output";
|
|
21948
|
+
var toFiniteNumberOrNull = (value) => {
|
|
21949
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
21950
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
21951
|
+
const parsed = Number(value);
|
|
21952
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
21953
|
+
}
|
|
21954
|
+
return null;
|
|
21955
|
+
};
|
|
21956
|
+
var isValidAggregateEfficiency = (monitoringMode, efficiency) => {
|
|
21957
|
+
const value = toFiniteNumberOrNull(efficiency);
|
|
21958
|
+
if (value === null) return false;
|
|
21959
|
+
return normalizeMonitoringMode(monitoringMode) === "uptime" ? value >= MIN_VALID_UPTIME_EFFICIENCY : value >= MIN_VALID_OUTPUT_EFFICIENCY;
|
|
21960
|
+
};
|
|
21961
|
+
|
|
21905
21962
|
// src/lib/utils/kpis.ts
|
|
21906
21963
|
var toNumber = (value) => {
|
|
21907
21964
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
@@ -21957,7 +22014,9 @@ var buildKPIsFromLineMetricsRow = (row) => {
|
|
|
21957
22014
|
};
|
|
21958
22015
|
var aggregateKPIsFromLineMetricsRows = (rows) => {
|
|
21959
22016
|
if (!rows || rows.length === 0) return createDefaultKPIs();
|
|
21960
|
-
const eligibleRows = rows.filter(
|
|
22017
|
+
const eligibleRows = rows.filter(
|
|
22018
|
+
(row) => isValidAggregateEfficiency(row?.monitoring_mode ?? row?.monitoringMode, row?.avg_efficiency)
|
|
22019
|
+
);
|
|
21961
22020
|
if (eligibleRows.length === 0) return createDefaultKPIs();
|
|
21962
22021
|
const currentOutputSum = eligibleRows.reduce((sum, row) => sum + toNumber(row.current_output), 0);
|
|
21963
22022
|
const lineThresholdSum = eligibleRows.reduce(
|
|
@@ -22009,6 +22068,84 @@ var aggregateKPIsFromLineMetricsRows = (rows) => {
|
|
|
22009
22068
|
};
|
|
22010
22069
|
};
|
|
22011
22070
|
|
|
22071
|
+
// src/lib/utils/kpiHierarchy.ts
|
|
22072
|
+
var FACTORY_LEVEL_MIN_FACTORY_COUNT = 3;
|
|
22073
|
+
var compareText = (left, right) => left.localeCompare(right, void 0, { sensitivity: "base", numeric: true });
|
|
22074
|
+
var compareLinesByName = (left, right) => compareText(left.line_name || "", right.line_name || "");
|
|
22075
|
+
var normalizeAreaSortOrder = (value) => {
|
|
22076
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
22077
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
22078
|
+
const parsed = Number(value);
|
|
22079
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
22080
|
+
}
|
|
22081
|
+
return null;
|
|
22082
|
+
};
|
|
22083
|
+
var getEnabledAreaInfo = (line) => {
|
|
22084
|
+
if (!line.factory_area_id) return null;
|
|
22085
|
+
if (line.factory_area_enabled !== true) return null;
|
|
22086
|
+
if (!line.factory_area_name || line.factory_area_name.trim().length === 0) return null;
|
|
22087
|
+
return {
|
|
22088
|
+
id: line.factory_area_id,
|
|
22089
|
+
areaName: line.factory_area_name,
|
|
22090
|
+
areaKey: line.factory_area_key ?? null,
|
|
22091
|
+
sortOrder: normalizeAreaSortOrder(line.factory_area_sort_order)
|
|
22092
|
+
};
|
|
22093
|
+
};
|
|
22094
|
+
var buildKpiLineHierarchy = (lines) => {
|
|
22095
|
+
const factoryMap = /* @__PURE__ */ new Map();
|
|
22096
|
+
lines.forEach((line) => {
|
|
22097
|
+
const factoryId = line.factory_id || "unknown-factory";
|
|
22098
|
+
let factory = factoryMap.get(factoryId);
|
|
22099
|
+
if (!factory) {
|
|
22100
|
+
factory = {
|
|
22101
|
+
id: factoryId,
|
|
22102
|
+
factoryName: line.factory_name || "Factory",
|
|
22103
|
+
lines: [],
|
|
22104
|
+
areas: [],
|
|
22105
|
+
ungroupedLines: [],
|
|
22106
|
+
areaMap: /* @__PURE__ */ new Map()
|
|
22107
|
+
};
|
|
22108
|
+
factoryMap.set(factoryId, factory);
|
|
22109
|
+
}
|
|
22110
|
+
factory.lines.push(line);
|
|
22111
|
+
const areaInfo = getEnabledAreaInfo(line);
|
|
22112
|
+
if (!areaInfo) {
|
|
22113
|
+
factory.ungroupedLines.push(line);
|
|
22114
|
+
return;
|
|
22115
|
+
}
|
|
22116
|
+
let area = factory.areaMap.get(areaInfo.id);
|
|
22117
|
+
if (!area) {
|
|
22118
|
+
area = {
|
|
22119
|
+
id: areaInfo.id,
|
|
22120
|
+
areaName: areaInfo.areaName,
|
|
22121
|
+
areaKey: areaInfo.areaKey,
|
|
22122
|
+
sortOrder: areaInfo.sortOrder,
|
|
22123
|
+
lines: []
|
|
22124
|
+
};
|
|
22125
|
+
factory.areaMap.set(areaInfo.id, area);
|
|
22126
|
+
factory.areas.push(area);
|
|
22127
|
+
}
|
|
22128
|
+
area.lines.push(line);
|
|
22129
|
+
});
|
|
22130
|
+
const factories = Array.from(factoryMap.values()).map(({ areaMap: _areaMap, ...factory }) => {
|
|
22131
|
+
factory.lines.sort(compareLinesByName);
|
|
22132
|
+
factory.ungroupedLines.sort(compareLinesByName);
|
|
22133
|
+
factory.areas.forEach((area) => area.lines.sort(compareLinesByName));
|
|
22134
|
+
factory.areas.sort((left, right) => {
|
|
22135
|
+
const leftOrder = left.sortOrder ?? Number.POSITIVE_INFINITY;
|
|
22136
|
+
const rightOrder = right.sortOrder ?? Number.POSITIVE_INFINITY;
|
|
22137
|
+
if (leftOrder !== rightOrder) return leftOrder - rightOrder;
|
|
22138
|
+
return compareText(left.areaName, right.areaName);
|
|
22139
|
+
});
|
|
22140
|
+
return factory;
|
|
22141
|
+
});
|
|
22142
|
+
factories.sort((left, right) => compareText(left.factoryName, right.factoryName));
|
|
22143
|
+
return {
|
|
22144
|
+
factories,
|
|
22145
|
+
showFactoryLevel: factories.length >= FACTORY_LEVEL_MIN_FACTORY_COUNT
|
|
22146
|
+
};
|
|
22147
|
+
};
|
|
22148
|
+
|
|
22012
22149
|
// src/lib/utils/awards.ts
|
|
22013
22150
|
var toNumber2 = (value) => {
|
|
22014
22151
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
@@ -37285,8 +37422,8 @@ var HourlyOutputChart = React144__namespace.default.memo(
|
|
|
37285
37422
|
HourlyOutputChart.displayName = "HourlyOutputChart";
|
|
37286
37423
|
|
|
37287
37424
|
// src/components/dashboard/grid/videoGridMetricUtils.ts
|
|
37425
|
+
var VIDEO_GRID_LEGEND_LABEL = "Real-Time efficiency";
|
|
37288
37426
|
var MAP_GRID_LEGEND_LABEL = "Efficiency";
|
|
37289
|
-
var MIXED_VIDEO_GRID_LEGEND_LABEL = "Live Efficiency";
|
|
37290
37427
|
var isFiniteNumber2 = (value) => typeof value === "number" && Number.isFinite(value);
|
|
37291
37428
|
var isVideoGridRecentFlowEnabled = (workspace) => isRecentFlowVideoGridMetricMode(
|
|
37292
37429
|
workspace.video_grid_metric_mode,
|
|
@@ -37298,7 +37435,7 @@ var isVideoGridWipGated = (workspace) => isWipGatedVideoGridMetricMode(
|
|
|
37298
37435
|
);
|
|
37299
37436
|
var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) && isFiniteNumber2(workspace.recent_flow_percent);
|
|
37300
37437
|
var isVideoGridRecentFlowUnavailable = (workspace) => isVideoGridRecentFlowEnabled(workspace) && !hasVideoGridRecentFlow(workspace);
|
|
37301
|
-
var
|
|
37438
|
+
var getRawVideoGridMetricValue = (workspace) => {
|
|
37302
37439
|
const recentFlowPercent = workspace.recent_flow_percent;
|
|
37303
37440
|
if (hasVideoGridRecentFlow(workspace) && isFiniteNumber2(recentFlowPercent)) {
|
|
37304
37441
|
return recentFlowPercent;
|
|
@@ -37310,7 +37447,7 @@ var getVideoGridMetricValue = (workspace) => {
|
|
|
37310
37447
|
};
|
|
37311
37448
|
var hasIncomingWipMapping = (workspace) => Boolean(workspace.incoming_wip_buffer_name);
|
|
37312
37449
|
var getVideoGridBaseColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
|
|
37313
|
-
const metricValue =
|
|
37450
|
+
const metricValue = getRawVideoGridMetricValue(workspace);
|
|
37314
37451
|
if (!isFiniteNumber2(metricValue)) {
|
|
37315
37452
|
return "neutral";
|
|
37316
37453
|
}
|
|
@@ -37334,6 +37471,25 @@ var isLowWipGreenOverride = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
|
|
|
37334
37471
|
}
|
|
37335
37472
|
return isFiniteNumber2(workspace.incoming_wip_current) && workspace.incoming_wip_current <= 1;
|
|
37336
37473
|
};
|
|
37474
|
+
var isHighEfficiencyRedFlowOverride = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
|
|
37475
|
+
if (workspace.scheduled_break_active === true) {
|
|
37476
|
+
return false;
|
|
37477
|
+
}
|
|
37478
|
+
if (workspace.recent_flow_forced_zero_after_shift === true) {
|
|
37479
|
+
return false;
|
|
37480
|
+
}
|
|
37481
|
+
if (!hasVideoGridRecentFlow(workspace) || !isVideoGridWipGated(workspace)) {
|
|
37482
|
+
return false;
|
|
37483
|
+
}
|
|
37484
|
+
if (isLowWipGreenOverride(workspace, legend)) {
|
|
37485
|
+
return false;
|
|
37486
|
+
}
|
|
37487
|
+
if (getVideoGridBaseColorState(workspace, legend) !== "red") {
|
|
37488
|
+
return false;
|
|
37489
|
+
}
|
|
37490
|
+
return isFiniteNumber2(workspace.efficiency) && workspace.efficiency > 100;
|
|
37491
|
+
};
|
|
37492
|
+
var getVideoGridMetricValue = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => isHighEfficiencyRedFlowOverride(workspace, legend) ? workspace.efficiency : getRawVideoGridMetricValue(workspace);
|
|
37337
37493
|
var toMinuteBucket = (minuteBucket) => Number.isFinite(minuteBucket) ? Math.floor(minuteBucket) : Math.floor(Date.now() / 6e4);
|
|
37338
37494
|
var getEffectiveFlowMinuteBucket = (workspace) => {
|
|
37339
37495
|
const effectiveAt = workspace.recent_flow_effective_end_at;
|
|
@@ -37359,7 +37515,7 @@ var getSyntheticLowWipDisplayValue = (workspace, minuteBucket) => {
|
|
|
37359
37515
|
const offset = (hashWorkspaceKey(workspace) % 11 + bucket % 11 + 11) % 11;
|
|
37360
37516
|
return 100 + offset;
|
|
37361
37517
|
};
|
|
37362
|
-
var getVideoGridDisplayValue = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND, minuteBucket) => isLowWipGreenOverride(workspace, legend) ? getSyntheticLowWipDisplayValue(workspace, minuteBucket) : getVideoGridMetricValue(workspace);
|
|
37518
|
+
var getVideoGridDisplayValue = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND, minuteBucket) => isLowWipGreenOverride(workspace, legend) ? getSyntheticLowWipDisplayValue(workspace, minuteBucket) : getVideoGridMetricValue(workspace, legend);
|
|
37363
37519
|
var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
|
|
37364
37520
|
const baseColor = getVideoGridBaseColorState(workspace, legend);
|
|
37365
37521
|
if (!hasVideoGridRecentFlow(workspace)) {
|
|
@@ -37371,15 +37527,18 @@ var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) =>
|
|
|
37371
37527
|
if (baseColor !== "red") {
|
|
37372
37528
|
return baseColor;
|
|
37373
37529
|
}
|
|
37530
|
+
if (isLowWipGreenOverride(workspace, legend)) {
|
|
37531
|
+
return "green";
|
|
37532
|
+
}
|
|
37533
|
+
if (isHighEfficiencyRedFlowOverride(workspace, legend)) {
|
|
37534
|
+
return getEfficiencyColor(workspace.efficiency, legend);
|
|
37535
|
+
}
|
|
37374
37536
|
if (!hasIncomingWipMapping(workspace)) {
|
|
37375
37537
|
return baseColor;
|
|
37376
37538
|
}
|
|
37377
37539
|
if (!isFiniteNumber2(workspace.incoming_wip_current)) {
|
|
37378
37540
|
return "neutral";
|
|
37379
37541
|
}
|
|
37380
|
-
if (isLowWipGreenOverride(workspace, legend)) {
|
|
37381
|
-
return "green";
|
|
37382
|
-
}
|
|
37383
37542
|
return baseColor;
|
|
37384
37543
|
};
|
|
37385
37544
|
var getVideoGridLegendLabel = (workspaces) => {
|
|
@@ -37387,21 +37546,7 @@ var getVideoGridLegendLabel = (workspaces) => {
|
|
|
37387
37546
|
if (visibleWorkspaces.length === 0) {
|
|
37388
37547
|
return MAP_GRID_LEGEND_LABEL;
|
|
37389
37548
|
}
|
|
37390
|
-
|
|
37391
|
-
if (recentFlowEnabledCount === 0) {
|
|
37392
|
-
return MAP_GRID_LEGEND_LABEL;
|
|
37393
|
-
}
|
|
37394
|
-
const recentFlowWindows = new Set(
|
|
37395
|
-
visibleWorkspaces.filter(isVideoGridRecentFlowEnabled).map((workspace) => workspace.recent_flow_window_minutes ?? 7).filter((value) => typeof value === "number" && Number.isFinite(value))
|
|
37396
|
-
);
|
|
37397
|
-
if (recentFlowEnabledCount === visibleWorkspaces.length) {
|
|
37398
|
-
if (recentFlowWindows.size === 1) {
|
|
37399
|
-
const [windowMinutes] = Array.from(recentFlowWindows);
|
|
37400
|
-
return `${windowMinutes} Minute Efficiency`;
|
|
37401
|
-
}
|
|
37402
|
-
return MIXED_VIDEO_GRID_LEGEND_LABEL;
|
|
37403
|
-
}
|
|
37404
|
-
return MIXED_VIDEO_GRID_LEGEND_LABEL;
|
|
37549
|
+
return visibleWorkspaces.some(isVideoGridRecentFlowEnabled) ? VIDEO_GRID_LEGEND_LABEL : MAP_GRID_LEGEND_LABEL;
|
|
37405
37550
|
};
|
|
37406
37551
|
function getTrendArrowAndColor(trend) {
|
|
37407
37552
|
if (trend > 0) {
|
|
@@ -37444,14 +37589,15 @@ var VideoCard = React144__namespace.default.memo(({
|
|
|
37444
37589
|
const showOffline = Boolean(isStreamStale);
|
|
37445
37590
|
const lastSeenText = lastSeenLabel || "Unknown";
|
|
37446
37591
|
const workspaceDisplayName = displayName || workspace.displayName || workspace.workspace_name;
|
|
37447
|
-
const videoGridMetricValue = getVideoGridMetricValue(workspace);
|
|
37592
|
+
const videoGridMetricValue = getVideoGridMetricValue(workspace, effectiveLegend);
|
|
37448
37593
|
const videoGridDisplayValue = getVideoGridDisplayValue(workspace, effectiveLegend, displayMinuteBucket);
|
|
37449
37594
|
const videoGridColorState = getVideoGridColorState(workspace, effectiveLegend);
|
|
37450
37595
|
const isRecentFlowCard = isVideoGridRecentFlowEnabled(workspace);
|
|
37596
|
+
const isHighEfficiencyOverride = isHighEfficiencyRedFlowOverride(workspace, effectiveLegend);
|
|
37451
37597
|
const hasDisplayMetric = typeof videoGridDisplayValue === "number" && Number.isFinite(videoGridDisplayValue);
|
|
37452
37598
|
const hasBarMetric = typeof videoGridMetricValue === "number" && Number.isFinite(videoGridMetricValue);
|
|
37453
37599
|
const shouldRenderMetricBadge = hasDisplayMetric;
|
|
37454
|
-
const badgeTitle = hasVideoGridRecentFlow(workspace) ? `Flow ${Math.round(videoGridDisplayValue ?? 0)}%` : isRecentFlowCard ? "Flow unavailable" : `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%`;
|
|
37600
|
+
const badgeTitle = isHighEfficiencyOverride ? `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%` : hasVideoGridRecentFlow(workspace) ? `Flow ${Math.round(videoGridDisplayValue ?? 0)}%` : isRecentFlowCard ? "Flow unavailable" : `Efficiency ${Math.round(videoGridDisplayValue ?? 0)}%`;
|
|
37455
37601
|
const badgeLabel = `${Math.round(videoGridDisplayValue ?? 0)}%`;
|
|
37456
37602
|
const efficiencyOverlayClass = videoGridColorState === "green" ? "bg-[#00D654]/25" : videoGridColorState === "yellow" ? "bg-[#FFD700]/30" : videoGridColorState === "red" ? "bg-[#FF2D0A]/30" : "bg-transparent";
|
|
37457
37603
|
const efficiencyBarClass = videoGridColorState === "green" ? "bg-[#00AB45]" : videoGridColorState === "yellow" ? "bg-[#FFB020]" : videoGridColorState === "red" ? "bg-[#E34329]" : "bg-gray-500/70";
|
|
@@ -38234,7 +38380,8 @@ var WorkspaceMetricCardsImpl = ({
|
|
|
38234
38380
|
legend,
|
|
38235
38381
|
skuAware,
|
|
38236
38382
|
skuBreakdown,
|
|
38237
|
-
activeSkuId
|
|
38383
|
+
activeSkuId,
|
|
38384
|
+
liveSkuId
|
|
38238
38385
|
}) => {
|
|
38239
38386
|
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
38240
38387
|
const activeSku = React144__namespace.default.useMemo(() => {
|
|
@@ -38243,6 +38390,13 @@ var WorkspaceMetricCardsImpl = ({
|
|
|
38243
38390
|
}
|
|
38244
38391
|
return null;
|
|
38245
38392
|
}, [skuAware, activeSkuId, skuBreakdown]);
|
|
38393
|
+
const displaySku = React144__namespace.default.useMemo(() => {
|
|
38394
|
+
if (activeSku) return activeSku;
|
|
38395
|
+
if (skuAware && !activeSkuId && liveSkuId && skuBreakdown) {
|
|
38396
|
+
return skuBreakdown.find((s) => s.sku_id === liveSkuId) ?? null;
|
|
38397
|
+
}
|
|
38398
|
+
return null;
|
|
38399
|
+
}, [activeSku, skuAware, activeSkuId, liveSkuId, skuBreakdown]);
|
|
38246
38400
|
const pphValue = activeSku ? activeSku.avg_pph : workspace.avg_pph;
|
|
38247
38401
|
const pphThreshold = activeSku ? activeSku.pph_threshold : workspace.pph_threshold;
|
|
38248
38402
|
const cycleValue = activeSku ? activeSku.avg_cycle_time : workspace.avg_cycle_time;
|
|
@@ -38277,7 +38431,7 @@ var WorkspaceMetricCardsImpl = ({
|
|
|
38277
38431
|
/* @__PURE__ */ jsxRuntime.jsxs(Card2, { className: "flex flex-col bg-white shadow-sm h-full min-h-[150px] sm:min-h-0", children: [
|
|
38278
38432
|
/* @__PURE__ */ jsxRuntime.jsxs(CardHeader2, { className: "pb-2 flex-none text-center", children: [
|
|
38279
38433
|
/* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg", children: "PPH" }),
|
|
38280
|
-
|
|
38434
|
+
displaySku && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-blue-600 mt-1 truncate px-2", title: displaySku.sku_code, children: displaySku.sku_code })
|
|
38281
38435
|
] }),
|
|
38282
38436
|
/* @__PURE__ */ jsxRuntime.jsx(CardContent2, { className: "flex-1 flex items-center justify-center py-6 sm:py-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
38283
38437
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-5xl font-bold ${pphValue >= pphThreshold ? "text-green-500" : "text-red-500"}`, children: pphValue.toFixed(1) }),
|
|
@@ -38290,7 +38444,7 @@ var WorkspaceMetricCardsImpl = ({
|
|
|
38290
38444
|
/* @__PURE__ */ jsxRuntime.jsxs(Card2, { className: "flex flex-col bg-white shadow-sm h-full min-h-[150px] sm:min-h-0", children: [
|
|
38291
38445
|
/* @__PURE__ */ jsxRuntime.jsxs(CardHeader2, { className: "pb-2 flex-none text-center", children: [
|
|
38292
38446
|
/* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg", children: "Avg. Cycle Time" }),
|
|
38293
|
-
|
|
38447
|
+
displaySku && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-blue-600 mt-1 truncate px-2", title: displaySku.sku_code, children: displaySku.sku_code })
|
|
38294
38448
|
] }),
|
|
38295
38449
|
/* @__PURE__ */ jsxRuntime.jsx(CardContent2, { className: "flex-1 flex items-center justify-center py-6 sm:py-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
38296
38450
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-5xl font-bold ${cycleValue > (cycleStandard || 0) ? "text-red-500" : "text-green-500"}`, children: cycleValue.toFixed(1) }),
|
|
@@ -43288,6 +43442,21 @@ var parseCycleTime = (value) => {
|
|
|
43288
43442
|
var extractCycleTimeSeconds = (clip) => {
|
|
43289
43443
|
return parseCycleTime(clip?.cycleTimeSeconds) ?? parseCycleTime(clip?.cycle_time_seconds) ?? parseCycleTime(clip?.duration) ?? parseCycleTime(clip?.original_task_metadata?.cycle_time) ?? null;
|
|
43290
43444
|
};
|
|
43445
|
+
var formatDurationLabel = (seconds) => {
|
|
43446
|
+
if (typeof seconds !== "number" || !Number.isFinite(seconds) || seconds <= 0) {
|
|
43447
|
+
return null;
|
|
43448
|
+
}
|
|
43449
|
+
const roundedSeconds = Math.round(seconds);
|
|
43450
|
+
if (roundedSeconds < 60) {
|
|
43451
|
+
return `${roundedSeconds}s`;
|
|
43452
|
+
}
|
|
43453
|
+
const minutes = Math.floor(roundedSeconds / 60);
|
|
43454
|
+
const remainingSeconds = roundedSeconds % 60;
|
|
43455
|
+
if (minutes < 10) {
|
|
43456
|
+
return remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`;
|
|
43457
|
+
}
|
|
43458
|
+
return `${Math.round(roundedSeconds / 60)} min`;
|
|
43459
|
+
};
|
|
43291
43460
|
var getSeverityIcon = (severity, categoryId, cycleTimeSeconds, targetCycleTime, clipId) => {
|
|
43292
43461
|
if (categoryId === "idle_time" || categoryId === "low_value" || categoryId === "longest-idles") {
|
|
43293
43462
|
return null;
|
|
@@ -43363,7 +43532,9 @@ var FileManagerFilters = ({
|
|
|
43363
43532
|
idleTimeVlmEnabled = false,
|
|
43364
43533
|
showPercentileCycleFilters = true,
|
|
43365
43534
|
prefetchedClipMetadata,
|
|
43366
|
-
activeCategoryLoading
|
|
43535
|
+
activeCategoryLoading,
|
|
43536
|
+
idleClipSort = "latest",
|
|
43537
|
+
onIdleClipSortChange
|
|
43367
43538
|
}) => {
|
|
43368
43539
|
const [expandedNodes, setExpandedNodes] = React144.useState(/* @__PURE__ */ new Set());
|
|
43369
43540
|
const [startTime, setStartTime] = React144.useState("");
|
|
@@ -43386,6 +43557,7 @@ var FileManagerFilters = ({
|
|
|
43386
43557
|
const [localClipClassifications, setLocalClipClassifications] = React144.useState({});
|
|
43387
43558
|
const clipMetadataRef = React144.useRef({});
|
|
43388
43559
|
const inFlightMetadataRequestsRef = React144.useRef(/* @__PURE__ */ new Set());
|
|
43560
|
+
const previousIdleClipSortRef = React144.useRef(idleClipSort);
|
|
43389
43561
|
const mergedClipClassifications = React144.useMemo(() => ({
|
|
43390
43562
|
...clipClassifications || {},
|
|
43391
43563
|
...localClipClassifications
|
|
@@ -43393,6 +43565,36 @@ var FileManagerFilters = ({
|
|
|
43393
43565
|
React144.useEffect(() => {
|
|
43394
43566
|
clipMetadataRef.current = clipMetadata;
|
|
43395
43567
|
}, [clipMetadata]);
|
|
43568
|
+
React144.useEffect(() => {
|
|
43569
|
+
if (previousIdleClipSortRef.current === idleClipSort) {
|
|
43570
|
+
return;
|
|
43571
|
+
}
|
|
43572
|
+
previousIdleClipSortRef.current = idleClipSort;
|
|
43573
|
+
setClipMetadata((prev) => {
|
|
43574
|
+
if (!prev.idle_time) {
|
|
43575
|
+
return prev;
|
|
43576
|
+
}
|
|
43577
|
+
const next = { ...prev };
|
|
43578
|
+
delete next.idle_time;
|
|
43579
|
+
return next;
|
|
43580
|
+
});
|
|
43581
|
+
setCategoryPages((prev) => {
|
|
43582
|
+
if (prev.idle_time === void 0) {
|
|
43583
|
+
return prev;
|
|
43584
|
+
}
|
|
43585
|
+
const next = { ...prev };
|
|
43586
|
+
delete next.idle_time;
|
|
43587
|
+
return next;
|
|
43588
|
+
});
|
|
43589
|
+
setCategoryHasMore((prev) => {
|
|
43590
|
+
if (prev.idle_time === void 0) {
|
|
43591
|
+
return prev;
|
|
43592
|
+
}
|
|
43593
|
+
const next = { ...prev };
|
|
43594
|
+
delete next.idle_time;
|
|
43595
|
+
return next;
|
|
43596
|
+
});
|
|
43597
|
+
}, [idleClipSort]);
|
|
43396
43598
|
const isCategoryExternallyManaged = React144.useCallback((categoryId) => {
|
|
43397
43599
|
if (!categoryId) {
|
|
43398
43600
|
return false;
|
|
@@ -43551,6 +43753,7 @@ var FileManagerFilters = ({
|
|
|
43551
43753
|
return null;
|
|
43552
43754
|
}
|
|
43553
43755
|
}, [supabase]);
|
|
43756
|
+
const getMetadataLoadingKey = React144.useCallback((categoryId, page) => `${categoryId}-${page}-${categoryId === "idle_time" ? idleClipSort : "latest"}`, [idleClipSort]);
|
|
43554
43757
|
const fetchClipMetadataPage = React144.useCallback(async (categoryId, page = 1) => {
|
|
43555
43758
|
if (!workspaceId || !date || shift === void 0) {
|
|
43556
43759
|
throw new Error("Missing required params for clip metadata fetch");
|
|
@@ -43570,7 +43773,8 @@ var FileManagerFilters = ({
|
|
|
43570
43773
|
limit: CLIP_METADATA_PAGE_SIZE,
|
|
43571
43774
|
knownTotal: typeof counts?.[categoryId] === "number" ? counts[categoryId] : null,
|
|
43572
43775
|
snapshotDateTime,
|
|
43573
|
-
snapshotClipId
|
|
43776
|
+
snapshotClipId,
|
|
43777
|
+
sort: categoryId === "idle_time" ? idleClipSort : "latest"
|
|
43574
43778
|
}),
|
|
43575
43779
|
redirectReason: "session_expired"
|
|
43576
43780
|
});
|
|
@@ -43578,7 +43782,7 @@ var FileManagerFilters = ({
|
|
|
43578
43782
|
throw new Error(`API error: ${response.status}`);
|
|
43579
43783
|
}
|
|
43580
43784
|
return response.json();
|
|
43581
|
-
}, [workspaceId, date, shift, counts, snapshotDateTime, snapshotClipId, supabase]);
|
|
43785
|
+
}, [workspaceId, date, shift, counts, snapshotDateTime, snapshotClipId, idleClipSort, supabase]);
|
|
43582
43786
|
const seedIdleClassifications = React144.useCallback(async (clips) => {
|
|
43583
43787
|
if (!idleTimeVlmEnabled || clips.length === 0) {
|
|
43584
43788
|
return;
|
|
@@ -43634,7 +43838,7 @@ var FileManagerFilters = ({
|
|
|
43634
43838
|
console.warn("[FileManager] Missing required params for clip metadata fetch");
|
|
43635
43839
|
return;
|
|
43636
43840
|
}
|
|
43637
|
-
const loadingKey =
|
|
43841
|
+
const loadingKey = getMetadataLoadingKey(categoryId, page);
|
|
43638
43842
|
if (inFlightMetadataRequestsRef.current.has(loadingKey)) {
|
|
43639
43843
|
return;
|
|
43640
43844
|
}
|
|
@@ -43662,7 +43866,7 @@ var FileManagerFilters = ({
|
|
|
43662
43866
|
return newSet;
|
|
43663
43867
|
});
|
|
43664
43868
|
}
|
|
43665
|
-
}, [workspaceId, date, shift, fetchClipMetadataPage, idleTimeVlmEnabled, seedIdleClassifications]);
|
|
43869
|
+
}, [workspaceId, date, shift, fetchClipMetadataPage, idleTimeVlmEnabled, seedIdleClassifications, getMetadataLoadingKey]);
|
|
43666
43870
|
const ensureAllIdleTimeClipMetadataLoaded = React144.useCallback(async () => {
|
|
43667
43871
|
if (!workspaceId || !date || shift === void 0) {
|
|
43668
43872
|
return;
|
|
@@ -44036,15 +44240,17 @@ var FileManagerFilters = ({
|
|
|
44036
44240
|
const colorClasses = getColorClasses(category.color);
|
|
44037
44241
|
const clipNodes = filteredClips.map((clip, index) => {
|
|
44038
44242
|
const cycleTime = extractCycleTimeSeconds(clip);
|
|
44243
|
+
const idleDuration = category.id === "idle_time" ? clip.idle_duration_seconds ?? clip.duration : null;
|
|
44244
|
+
const idleDurationLabel = formatDurationLabel(idleDuration);
|
|
44039
44245
|
const baseTimeLabel = formatClipExplorerTimeLabel({
|
|
44040
44246
|
categoryId: category.id,
|
|
44041
44247
|
clipTimestamp: clip.clip_timestamp,
|
|
44042
44248
|
timezone,
|
|
44043
|
-
durationSeconds: clip.duration,
|
|
44249
|
+
durationSeconds: idleDuration ?? clip.duration,
|
|
44044
44250
|
idleStartTime: clip.idle_start_time,
|
|
44045
44251
|
idleEndTime: clip.idle_end_time
|
|
44046
44252
|
});
|
|
44047
|
-
const displayLabel = `${baseTimeLabel}${clip.duration && category.id !== "idle_time" && category.id !== "low_value" ? ` - (${clip.duration.toFixed(1)}s)` : ""}`;
|
|
44253
|
+
const displayLabel = `${baseTimeLabel}${idleDurationLabel && category.id === "idle_time" ? ` - (${idleDurationLabel})` : ""}${clip.duration && category.id !== "idle_time" && category.id !== "low_value" ? ` - (${clip.duration.toFixed(1)}s)` : ""}`;
|
|
44048
44254
|
return {
|
|
44049
44255
|
id: clip.id,
|
|
44050
44256
|
label: displayLabel,
|
|
@@ -44058,7 +44264,7 @@ var FileManagerFilters = ({
|
|
|
44058
44264
|
clipPosition: index + 1,
|
|
44059
44265
|
// Store 1-based position
|
|
44060
44266
|
cycleTimeSeconds: cycleTime,
|
|
44061
|
-
duration: clip.duration,
|
|
44267
|
+
duration: idleDuration ?? clip.duration,
|
|
44062
44268
|
// Store duration for custom badge rendering
|
|
44063
44269
|
cycleItemCount: clip.cycle_item_count ?? null
|
|
44064
44270
|
};
|
|
@@ -44380,11 +44586,11 @@ var FileManagerFilters = ({
|
|
|
44380
44586
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
44381
44587
|
"Loading clips..."
|
|
44382
44588
|
] }) }),
|
|
44383
|
-
loadingCategories.has(
|
|
44589
|
+
loadingCategories.has(getMetadataLoadingKey(node.id, (categoryPages[node.id] || 0) + 1)) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-2 px-3 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center text-sm text-slate-500", children: [
|
|
44384
44590
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin mr-2 h-4 w-4 border-2 border-slate-300 border-t-blue-500 rounded-full" }),
|
|
44385
44591
|
"Loading more clips..."
|
|
44386
44592
|
] }) }),
|
|
44387
|
-
categoryHasMore[node.id] && !loadingCategories.has(
|
|
44593
|
+
categoryHasMore[node.id] && !loadingCategories.has(getMetadataLoadingKey(node.id, (categoryPages[node.id] || 0) + 1)) && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
44388
44594
|
"button",
|
|
44389
44595
|
{
|
|
44390
44596
|
onClick: (e) => {
|
|
@@ -44411,6 +44617,18 @@ var FileManagerFilters = ({
|
|
|
44411
44617
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-bold text-slate-900 tracking-tight", children: "Clips Explorer" }) })
|
|
44412
44618
|
] }),
|
|
44413
44619
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-2", children: [
|
|
44620
|
+
activeFilter === "idle_time" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
44621
|
+
"button",
|
|
44622
|
+
{
|
|
44623
|
+
onClick: () => {
|
|
44624
|
+
onIdleClipSortChange?.(idleClipSort === "latest" ? "idle_duration_desc" : "latest");
|
|
44625
|
+
},
|
|
44626
|
+
className: `p-2 rounded-xl transition-all duration-200 ${idleClipSort === "idle_duration_desc" ? "bg-orange-100 text-orange-600 hover:bg-orange-200 shadow-sm" : "bg-slate-100 text-slate-600 hover:bg-slate-200"}`,
|
|
44627
|
+
title: idleClipSort === "idle_duration_desc" ? "Sort by newest first" : "Sort by longest idle first",
|
|
44628
|
+
"aria-label": idleClipSort === "idle_duration_desc" ? "Sort idle clips by newest first" : "Sort idle clips by longest idle first",
|
|
44629
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownWideNarrow, { className: "h-5 w-5" })
|
|
44630
|
+
}
|
|
44631
|
+
),
|
|
44414
44632
|
activeFilter === "idle_time" && idleTimeVlmEnabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
44415
44633
|
"button",
|
|
44416
44634
|
{
|
|
@@ -44431,8 +44649,8 @@ var FileManagerFilters = ({
|
|
|
44431
44649
|
)
|
|
44432
44650
|
] })
|
|
44433
44651
|
] }),
|
|
44434
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-
|
|
44435
|
-
isTimeFilterActive && startTime && endTime && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center
|
|
44652
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: [
|
|
44653
|
+
isTimeFilterActive && startTime && endTime && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex w-fit items-center gap-2 rounded-full border border-blue-100 bg-blue-50/70 px-2.5 py-1 text-xs text-blue-700 shadow-sm", children: [
|
|
44436
44654
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
|
|
44437
44655
|
"Time: ",
|
|
44438
44656
|
getDisplayValue(startTime),
|
|
@@ -44448,13 +44666,13 @@ var FileManagerFilters = ({
|
|
|
44448
44666
|
setEndTime("");
|
|
44449
44667
|
setIsTimeFilterActive(false);
|
|
44450
44668
|
},
|
|
44451
|
-
className: "
|
|
44669
|
+
className: "rounded-full p-0.5 transition-colors hover:bg-blue-100",
|
|
44452
44670
|
title: "Clear time filter",
|
|
44453
44671
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5" })
|
|
44454
44672
|
}
|
|
44455
44673
|
)
|
|
44456
44674
|
] }),
|
|
44457
|
-
idleLabelFilter && activeFilter === "idle_time" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center
|
|
44675
|
+
idleLabelFilter && activeFilter === "idle_time" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex w-fit items-center gap-2 rounded-full border border-purple-100 bg-purple-50/70 px-2.5 py-1 text-xs text-purple-700 shadow-sm", children: [
|
|
44458
44676
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
|
|
44459
44677
|
"Reason: ",
|
|
44460
44678
|
selectedIdleReasonOption?.displayName || idleLabelFilter.replace(/_/g, " ")
|
|
@@ -44466,11 +44684,27 @@ var FileManagerFilters = ({
|
|
|
44466
44684
|
e.stopPropagation();
|
|
44467
44685
|
setIdleLabelFilter(null);
|
|
44468
44686
|
},
|
|
44469
|
-
className: "
|
|
44687
|
+
className: "rounded-full p-0.5 transition-colors hover:bg-purple-100",
|
|
44470
44688
|
title: "Clear label filter",
|
|
44471
44689
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5" })
|
|
44472
44690
|
}
|
|
44473
44691
|
)
|
|
44692
|
+
] }),
|
|
44693
|
+
activeFilter === "idle_time" && idleClipSort === "idle_duration_desc" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex w-fit items-center gap-2 rounded-full border border-orange-100 bg-orange-50/70 px-2.5 py-1 text-xs text-orange-700 shadow-sm", children: [
|
|
44694
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownWideNarrow, { className: "h-3.5 w-3.5" }),
|
|
44695
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Longest idle first" }),
|
|
44696
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
44697
|
+
"button",
|
|
44698
|
+
{
|
|
44699
|
+
onClick: (e) => {
|
|
44700
|
+
e.stopPropagation();
|
|
44701
|
+
onIdleClipSortChange?.("latest");
|
|
44702
|
+
},
|
|
44703
|
+
className: "rounded-full p-0.5 transition-colors hover:bg-orange-100",
|
|
44704
|
+
title: "Clear idle sort",
|
|
44705
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5" })
|
|
44706
|
+
}
|
|
44707
|
+
)
|
|
44474
44708
|
] })
|
|
44475
44709
|
] })
|
|
44476
44710
|
] }),
|
|
@@ -45234,8 +45468,10 @@ var BottlenecksContent = ({
|
|
|
45234
45468
|
const [clipClassifications, setClipClassifications] = React144.useState({});
|
|
45235
45469
|
const [categoryMetadata, setCategoryMetadata] = React144.useState([]);
|
|
45236
45470
|
const [categoryMetadataCategoryId, setCategoryMetadataCategoryId] = React144.useState(null);
|
|
45471
|
+
const [categoryMetadataSort, setCategoryMetadataSort] = React144.useState(null);
|
|
45237
45472
|
const [currentMetadataIndex, setCurrentMetadataIndex] = React144.useState(0);
|
|
45238
45473
|
const [metadataCache, setMetadataCache] = React144.useState({});
|
|
45474
|
+
const [idleClipSort, setIdleClipSort] = React144.useState("latest");
|
|
45239
45475
|
const invalidateMetadataCache = React144.useCallback((categories) => {
|
|
45240
45476
|
setMetadataCache((prevCache) => {
|
|
45241
45477
|
if (!prevCache || Object.keys(prevCache).length === 0) {
|
|
@@ -45266,6 +45502,7 @@ var BottlenecksContent = ({
|
|
|
45266
45502
|
const [isFullscreen, setIsFullscreen] = React144.useState(false);
|
|
45267
45503
|
const categoryMetadataRef = React144.useRef([]);
|
|
45268
45504
|
const currentMetadataIndexRef = React144.useRef(0);
|
|
45505
|
+
const previousIdleClipSortRef = React144.useRef(idleClipSort);
|
|
45269
45506
|
const clearRetryTimeout = React144.useCallback(() => {
|
|
45270
45507
|
if (retryTimeoutRef.current) {
|
|
45271
45508
|
clearTimeout(retryTimeoutRef.current);
|
|
@@ -45712,9 +45949,13 @@ var BottlenecksContent = ({
|
|
|
45712
45949
|
}
|
|
45713
45950
|
return ["fast-cycles", "slow-cycles", "longest-idles"].includes(categoryId);
|
|
45714
45951
|
}, [isFastSlowClipFiltersEnabled]);
|
|
45952
|
+
const shouldUseMetadataNavigation = React144.useCallback((categoryId) => {
|
|
45953
|
+
return isPercentileCategory(categoryId) || categoryId === "idle_time" && idleClipSort === "idle_duration_desc";
|
|
45954
|
+
}, [idleClipSort, isPercentileCategory]);
|
|
45715
45955
|
const getMetadataCacheKey = React144.useCallback((categoryId) => {
|
|
45716
|
-
|
|
45717
|
-
|
|
45956
|
+
const sortKey = categoryId === "idle_time" ? idleClipSort : "latest";
|
|
45957
|
+
return `${categoryId}-${effectiveDateString}-${effectiveShiftId}-${snapshotDateTime ?? "nosnap"}-${snapshotClipId ?? "nosnap"}-${sortKey}`;
|
|
45958
|
+
}, [effectiveDateString, effectiveShiftId, snapshotDateTime, snapshotClipId, idleClipSort]);
|
|
45718
45959
|
const setVisibleCategoryMetadata = React144.useCallback((categoryId, clips) => {
|
|
45719
45960
|
if (activeFilterRef.current !== categoryId) {
|
|
45720
45961
|
return false;
|
|
@@ -45722,8 +45963,9 @@ var BottlenecksContent = ({
|
|
|
45722
45963
|
categoryMetadataRef.current = clips;
|
|
45723
45964
|
setCategoryMetadata(clips);
|
|
45724
45965
|
setCategoryMetadataCategoryId(clips.length > 0 ? categoryId : null);
|
|
45966
|
+
setCategoryMetadataSort(clips.length > 0 ? categoryId === "idle_time" ? idleClipSort : "latest" : null);
|
|
45725
45967
|
return true;
|
|
45726
|
-
}, []);
|
|
45968
|
+
}, [idleClipSort]);
|
|
45727
45969
|
const applyMetadataSnapshot = React144.useCallback((categoryId, clips, total) => {
|
|
45728
45970
|
if (!clips || clips.length === 0) {
|
|
45729
45971
|
return;
|
|
@@ -45734,11 +45976,11 @@ var BottlenecksContent = ({
|
|
|
45734
45976
|
[cacheKey]: clips
|
|
45735
45977
|
}));
|
|
45736
45978
|
setVisibleCategoryMetadata(categoryId, clips);
|
|
45737
|
-
if (!
|
|
45979
|
+
if (!shouldUseMetadataNavigation(categoryId) && typeof total === "number") {
|
|
45738
45980
|
currentTotalRef.current = total;
|
|
45739
45981
|
setCurrentTotal(total);
|
|
45740
45982
|
}
|
|
45741
|
-
}, [getMetadataCacheKey,
|
|
45983
|
+
}, [getMetadataCacheKey, shouldUseMetadataNavigation, setVisibleCategoryMetadata]);
|
|
45742
45984
|
const getClipTypesForPercentileCategory = React144.useCallback((categoryId) => {
|
|
45743
45985
|
switch (categoryId) {
|
|
45744
45986
|
case "fast-cycles":
|
|
@@ -45764,6 +46006,7 @@ var BottlenecksContent = ({
|
|
|
45764
46006
|
}
|
|
45765
46007
|
setCategoryMetadata([]);
|
|
45766
46008
|
setCategoryMetadataCategoryId(null);
|
|
46009
|
+
setCategoryMetadataSort(null);
|
|
45767
46010
|
categoryMetadataRef.current = [];
|
|
45768
46011
|
updateActiveFilter(fallbackFilter);
|
|
45769
46012
|
}, [isFastSlowClipFiltersEnabled, activeFilter, dynamicCounts, clipTypes, updateActiveFilter]);
|
|
@@ -45811,6 +46054,7 @@ var BottlenecksContent = ({
|
|
|
45811
46054
|
if (!isFastSlowClipFiltersEnabled && (categoryId === "fast-cycles" || categoryId === "slow-cycles")) {
|
|
45812
46055
|
setCategoryMetadata([]);
|
|
45813
46056
|
setCategoryMetadataCategoryId(null);
|
|
46057
|
+
setCategoryMetadataSort(null);
|
|
45814
46058
|
categoryMetadataRef.current = [];
|
|
45815
46059
|
return;
|
|
45816
46060
|
}
|
|
@@ -45881,7 +46125,8 @@ var BottlenecksContent = ({
|
|
|
45881
46125
|
limit: 100,
|
|
45882
46126
|
knownTotal: mergedCounts[categoryId] ?? null,
|
|
45883
46127
|
snapshotDateTime,
|
|
45884
|
-
snapshotClipId
|
|
46128
|
+
snapshotClipId,
|
|
46129
|
+
sort: categoryId === "idle_time" ? idleClipSort : "latest"
|
|
45885
46130
|
}),
|
|
45886
46131
|
redirectReason: "session_expired"
|
|
45887
46132
|
});
|
|
@@ -45960,6 +46205,7 @@ var BottlenecksContent = ({
|
|
|
45960
46205
|
if (activeFilterRef.current === categoryId) {
|
|
45961
46206
|
setCategoryMetadata([]);
|
|
45962
46207
|
setCategoryMetadataCategoryId(null);
|
|
46208
|
+
setCategoryMetadataSort(null);
|
|
45963
46209
|
categoryMetadataRef.current = [];
|
|
45964
46210
|
}
|
|
45965
46211
|
}
|
|
@@ -45968,7 +46214,26 @@ var BottlenecksContent = ({
|
|
|
45968
46214
|
} finally {
|
|
45969
46215
|
setIsCategoryLoading(false);
|
|
45970
46216
|
}
|
|
45971
|
-
}, [workspaceId, effectiveDateString, effectiveShiftId, getMetadataCacheKey, isPercentileCategory, isFastSlowClipFiltersEnabled, metadataCache, s3ClipsService, clearLoadingState, isEffectiveShiftReady, snapshotDateTime, snapshotClipId, supabase, setVisibleCategoryMetadata]);
|
|
46217
|
+
}, [workspaceId, effectiveDateString, effectiveShiftId, getMetadataCacheKey, isPercentileCategory, isFastSlowClipFiltersEnabled, metadataCache, s3ClipsService, clearLoadingState, isEffectiveShiftReady, snapshotDateTime, snapshotClipId, idleClipSort, supabase, setVisibleCategoryMetadata]);
|
|
46218
|
+
React144.useEffect(() => {
|
|
46219
|
+
if (previousIdleClipSortRef.current === idleClipSort) {
|
|
46220
|
+
return;
|
|
46221
|
+
}
|
|
46222
|
+
previousIdleClipSortRef.current = idleClipSort;
|
|
46223
|
+
if (activeFilterRef.current !== "idle_time") {
|
|
46224
|
+
return;
|
|
46225
|
+
}
|
|
46226
|
+
setCategoryMetadata([]);
|
|
46227
|
+
setCategoryMetadataCategoryId(null);
|
|
46228
|
+
setCategoryMetadataSort(null);
|
|
46229
|
+
categoryMetadataRef.current = [];
|
|
46230
|
+
setCurrentMetadataIndex(0);
|
|
46231
|
+
currentMetadataIndexRef.current = 0;
|
|
46232
|
+
setCurrentPosition(0);
|
|
46233
|
+
currentPositionRef.current = 0;
|
|
46234
|
+
setIsCategoryLoading(true);
|
|
46235
|
+
void loadCategoryMetadata("idle_time", true, true);
|
|
46236
|
+
}, [idleClipSort, loadCategoryMetadata]);
|
|
45972
46237
|
React144.useEffect(() => {
|
|
45973
46238
|
if (previousFilterRef.current !== activeFilter) {
|
|
45974
46239
|
console.log(`Filter changed from ${previousFilterRef.current} to ${activeFilter} - resetting to first video`);
|
|
@@ -45979,6 +46244,7 @@ var BottlenecksContent = ({
|
|
|
45979
46244
|
loadingCategoryRef.current = null;
|
|
45980
46245
|
setCategoryMetadata([]);
|
|
45981
46246
|
setCategoryMetadataCategoryId(null);
|
|
46247
|
+
setCategoryMetadataSort(null);
|
|
45982
46248
|
setCurrentMetadataIndex(0);
|
|
45983
46249
|
categoryMetadataRef.current = [];
|
|
45984
46250
|
currentMetadataIndexRef.current = 0;
|
|
@@ -46077,7 +46343,7 @@ var BottlenecksContent = ({
|
|
|
46077
46343
|
}
|
|
46078
46344
|
if (metadataArray.length === 0) {
|
|
46079
46345
|
console.warn(`[BottlenecksContent] No metadata available for category ${categoryId} after refresh`);
|
|
46080
|
-
if (!
|
|
46346
|
+
if (!shouldUseMetadataNavigation(categoryId)) {
|
|
46081
46347
|
const resolvedPosition = typeof position === "number" ? position : 1;
|
|
46082
46348
|
currentPositionRef.current = resolvedPosition;
|
|
46083
46349
|
setCurrentPosition(resolvedPosition);
|
|
@@ -46090,7 +46356,7 @@ var BottlenecksContent = ({
|
|
|
46090
46356
|
const clickedClipIndex = metadataArray.findIndex((clip) => clip.clipId === clipId);
|
|
46091
46357
|
if (clickedClipIndex === -1) {
|
|
46092
46358
|
console.warn(`[BottlenecksContent] Clip ${clipId} not found after metadata refresh`);
|
|
46093
|
-
if (!
|
|
46359
|
+
if (!shouldUseMetadataNavigation(categoryId)) {
|
|
46094
46360
|
const resolvedPosition = typeof position === "number" ? position : 1;
|
|
46095
46361
|
currentPositionRef.current = resolvedPosition;
|
|
46096
46362
|
setCurrentPosition(resolvedPosition);
|
|
@@ -46102,7 +46368,7 @@ var BottlenecksContent = ({
|
|
|
46102
46368
|
}
|
|
46103
46369
|
setCurrentMetadataIndex(clickedClipIndex);
|
|
46104
46370
|
currentMetadataIndexRef.current = clickedClipIndex;
|
|
46105
|
-
if (!
|
|
46371
|
+
if (!shouldUseMetadataNavigation(categoryId)) {
|
|
46106
46372
|
const position2 = clickedClipIndex + 1;
|
|
46107
46373
|
currentPositionRef.current = position2;
|
|
46108
46374
|
setCurrentPosition(position2);
|
|
@@ -46132,7 +46398,7 @@ var BottlenecksContent = ({
|
|
|
46132
46398
|
clearLoadingState();
|
|
46133
46399
|
}
|
|
46134
46400
|
}
|
|
46135
|
-
}, [workspaceId, s3ClipsService, updateActiveFilter, clearLoadingState, clearRetryTimeout, loadCategoryMetadata, applyMetadataSnapshot, mergedCounts,
|
|
46401
|
+
}, [workspaceId, s3ClipsService, updateActiveFilter, clearLoadingState, clearRetryTimeout, loadCategoryMetadata, applyMetadataSnapshot, mergedCounts, shouldUseMetadataNavigation]);
|
|
46136
46402
|
const restartCurrentClipPlayback = React144.useCallback(() => {
|
|
46137
46403
|
if (!currentClipId) {
|
|
46138
46404
|
return;
|
|
@@ -46153,7 +46419,7 @@ var BottlenecksContent = ({
|
|
|
46153
46419
|
return;
|
|
46154
46420
|
}
|
|
46155
46421
|
const activeCategory = activeFilterRef.current;
|
|
46156
|
-
if (!activeCategory || activeCategory === "all" ||
|
|
46422
|
+
if (!activeCategory || activeCategory === "all" || shouldUseMetadataNavigation(activeCategory)) {
|
|
46157
46423
|
return;
|
|
46158
46424
|
}
|
|
46159
46425
|
let cancelled = false;
|
|
@@ -46186,7 +46452,7 @@ var BottlenecksContent = ({
|
|
|
46186
46452
|
}, [
|
|
46187
46453
|
newClipsNotification,
|
|
46188
46454
|
s3ClipsService,
|
|
46189
|
-
|
|
46455
|
+
shouldUseMetadataNavigation,
|
|
46190
46456
|
currentClipId,
|
|
46191
46457
|
invalidateMetadataCache,
|
|
46192
46458
|
loadAndPlayClipById,
|
|
@@ -46238,7 +46504,7 @@ var BottlenecksContent = ({
|
|
|
46238
46504
|
}
|
|
46239
46505
|
}
|
|
46240
46506
|
try {
|
|
46241
|
-
if (!
|
|
46507
|
+
if (!shouldUseMetadataNavigation(currentFilter)) {
|
|
46242
46508
|
if (!s3ClipsService || !workspaceId || !currentClipId) {
|
|
46243
46509
|
throw new Error("S3 clips service not available");
|
|
46244
46510
|
}
|
|
@@ -46338,7 +46604,7 @@ var BottlenecksContent = ({
|
|
|
46338
46604
|
} else {
|
|
46339
46605
|
const firstClipMeta = metadataArray[0];
|
|
46340
46606
|
if (firstClipMeta?.clipId && firstClipMeta.clipId !== currentClipId) {
|
|
46341
|
-
console.log(`[handleNext] Reached end of ${currentFilter}, looping back to
|
|
46607
|
+
console.log(`[handleNext] Reached end of ${currentFilter}, looping back to first metadata clip ${firstClipMeta.clipId}`);
|
|
46342
46608
|
await loadAndPlayClipById(firstClipMeta.clipId, currentFilter, 1, {
|
|
46343
46609
|
clips: metadataArray,
|
|
46344
46610
|
total: metadataArray.length
|
|
@@ -46364,7 +46630,7 @@ var BottlenecksContent = ({
|
|
|
46364
46630
|
});
|
|
46365
46631
|
clearLoadingState();
|
|
46366
46632
|
}
|
|
46367
|
-
}, [clearLoadingState, clearRetryTimeout, s3ClipsService, loadCategoryMetadata, loadAndPlayClipById,
|
|
46633
|
+
}, [clearLoadingState, clearRetryTimeout, s3ClipsService, loadCategoryMetadata, loadAndPlayClipById, shouldUseMetadataNavigation, workspaceId, currentClipId, effectiveDateString, effectiveShiftId, snapshotDateTime, snapshotClipId, mergedCounts]);
|
|
46368
46634
|
const handlePrevious = React144.useCallback(async () => {
|
|
46369
46635
|
if (!isMountedRef.current || navigationLockRef.current) return;
|
|
46370
46636
|
const currentFilter = activeFilterRef.current;
|
|
@@ -46383,7 +46649,7 @@ var BottlenecksContent = ({
|
|
|
46383
46649
|
}
|
|
46384
46650
|
}
|
|
46385
46651
|
try {
|
|
46386
|
-
if (!
|
|
46652
|
+
if (!shouldUseMetadataNavigation(currentFilter)) {
|
|
46387
46653
|
if (!s3ClipsService || !workspaceId || !currentClipId) {
|
|
46388
46654
|
throw new Error("S3 clips service not available");
|
|
46389
46655
|
}
|
|
@@ -46468,7 +46734,7 @@ var BottlenecksContent = ({
|
|
|
46468
46734
|
});
|
|
46469
46735
|
clearLoadingState();
|
|
46470
46736
|
}
|
|
46471
|
-
}, [clearLoadingState, clearRetryTimeout, s3ClipsService, loadCategoryMetadata,
|
|
46737
|
+
}, [clearLoadingState, clearRetryTimeout, s3ClipsService, loadCategoryMetadata, shouldUseMetadataNavigation, workspaceId, currentClipId, effectiveDateString, effectiveShiftId, snapshotDateTime, snapshotClipId, mergedCounts]);
|
|
46472
46738
|
const currentVideo = React144.useMemo(() => {
|
|
46473
46739
|
if (!filteredVideos || filteredVideos.length === 0 || currentIndex >= filteredVideos.length) {
|
|
46474
46740
|
return null;
|
|
@@ -46535,22 +46801,22 @@ var BottlenecksContent = ({
|
|
|
46535
46801
|
}
|
|
46536
46802
|
}, [currentVideo?.id, isShareLoading, supabase, workspaceId, workspaceName]);
|
|
46537
46803
|
React144.useMemo(() => {
|
|
46538
|
-
if (
|
|
46804
|
+
if (shouldUseMetadataNavigation(activeFilter)) {
|
|
46539
46805
|
return categoryMetadata.length;
|
|
46540
46806
|
}
|
|
46541
46807
|
return currentTotal || mergedCounts[activeFilter] || 0;
|
|
46542
|
-
}, [activeFilter, categoryMetadata.length, currentTotal, mergedCounts,
|
|
46808
|
+
}, [activeFilter, categoryMetadata.length, currentTotal, mergedCounts, shouldUseMetadataNavigation]);
|
|
46543
46809
|
React144.useMemo(() => {
|
|
46544
|
-
if (
|
|
46810
|
+
if (shouldUseMetadataNavigation(activeFilter)) {
|
|
46545
46811
|
return categoryMetadata.length > 0 ? currentMetadataIndex + 1 : 0;
|
|
46546
46812
|
}
|
|
46547
46813
|
return currentPosition;
|
|
46548
|
-
}, [activeFilter, categoryMetadata.length, currentMetadataIndex, currentPosition,
|
|
46549
|
-
const prefetchedExplorerMetadata = React144.useMemo(() => buildPrefetchedExplorerMetadata(
|
|
46814
|
+
}, [activeFilter, categoryMetadata.length, currentMetadataIndex, currentPosition, shouldUseMetadataNavigation]);
|
|
46815
|
+
const prefetchedExplorerMetadata = React144.useMemo(() => activeFilter === "idle_time" && categoryMetadataSort !== idleClipSort ? void 0 : buildPrefetchedExplorerMetadata(
|
|
46550
46816
|
activeFilter,
|
|
46551
46817
|
categoryMetadataCategoryId,
|
|
46552
46818
|
categoryMetadata
|
|
46553
|
-
), [activeFilter, categoryMetadata, categoryMetadataCategoryId]);
|
|
46819
|
+
), [activeFilter, categoryMetadata, categoryMetadataCategoryId, categoryMetadataSort, idleClipSort]);
|
|
46554
46820
|
const classificationClipIds = React144.useMemo(() => {
|
|
46555
46821
|
if (!idleTimeVlmEnabled) {
|
|
46556
46822
|
return [];
|
|
@@ -47299,7 +47565,12 @@ var BottlenecksContent = ({
|
|
|
47299
47565
|
showPercentileCycleFilters: isFastSlowClipFiltersEnabled,
|
|
47300
47566
|
prefetchedClipMetadata: prefetchedExplorerMetadata,
|
|
47301
47567
|
activeCategoryLoading: isCategoryLoading,
|
|
47568
|
+
idleClipSort,
|
|
47569
|
+
onIdleClipSortChange: setIdleClipSort,
|
|
47302
47570
|
onFilterChange: (filterId) => {
|
|
47571
|
+
if (filterId !== "idle_time") {
|
|
47572
|
+
setIdleClipSort("latest");
|
|
47573
|
+
}
|
|
47303
47574
|
updateActiveFilter(filterId);
|
|
47304
47575
|
const category = categoriesToShow.find((cat) => cat.type === filterId);
|
|
47305
47576
|
if (category) {
|
|
@@ -49222,6 +49493,11 @@ var LineHistoryCalendar = ({
|
|
|
49222
49493
|
return calendar;
|
|
49223
49494
|
}, [data, month, year, configuredTimezone]);
|
|
49224
49495
|
const hasRealData = (shift) => {
|
|
49496
|
+
if (isUptimeMode) {
|
|
49497
|
+
if (shift.hasData === true) return true;
|
|
49498
|
+
const efficiency = Number(shift.avg_efficiency);
|
|
49499
|
+
return shift.total_workspaces > 0 || shift.underperforming_workspaces > 0 || (shift.output || 0) > 0 || (shift.available_time_seconds || 0) > 0 || (shift.active_time_seconds || 0) > 0 || (shift.idle_time_seconds || 0) > 0 || Number.isFinite(efficiency) && efficiency > 0;
|
|
49500
|
+
}
|
|
49225
49501
|
if (shift.hasData !== void 0) return shift.hasData;
|
|
49226
49502
|
return shift.total_workspaces > 0 || shift.avg_efficiency > 0 || shift.underperforming_workspaces > 0;
|
|
49227
49503
|
};
|
|
@@ -49854,13 +50130,18 @@ var LineMonthlyHistory = ({
|
|
|
49854
50130
|
enabled: !!lineId && idleTimeVlmEnabled
|
|
49855
50131
|
});
|
|
49856
50132
|
const hasRealData = (shift) => {
|
|
50133
|
+
if (isUptimeMode) {
|
|
50134
|
+
if (shift.hasData === true) return true;
|
|
50135
|
+
const efficiency = Number(shift.avg_efficiency);
|
|
50136
|
+
return shift.total_workspaces > 0 || shift.underperforming_workspaces > 0 || (shift.output || 0) > 0 || (shift.idealOutput || 0) > 0 || (shift.idle_time_seconds || 0) > 0 || (shift.active_time_seconds || 0) > 0 || (shift.available_time_seconds || 0) > 0 || Number.isFinite(efficiency) && efficiency > 0;
|
|
50137
|
+
}
|
|
49857
50138
|
if (shift.hasData !== void 0) return shift.hasData;
|
|
49858
50139
|
return shift.avg_efficiency > 0 || shift.underperforming_workspaces > 0 || shift.total_workspaces > 0 || (shift.output || 0) > 0 || (shift.idealOutput || 0) > 0 || (shift.idle_time_seconds || 0) > 0 || (shift.active_time_seconds || 0) > 0 || (shift.available_time_seconds || 0) > 0;
|
|
49859
50140
|
};
|
|
49860
50141
|
const averages = (analysisMonthlyData || []).reduce(
|
|
49861
50142
|
(acc, day) => {
|
|
49862
50143
|
const shiftData = getShiftData2(day, selectedShiftId);
|
|
49863
|
-
if (!shiftData || shiftData
|
|
50144
|
+
if (!shiftData || !isValidAggregateEfficiency(isUptimeMode ? "uptime" : "output", shiftData.avg_efficiency)) {
|
|
49864
50145
|
return acc;
|
|
49865
50146
|
}
|
|
49866
50147
|
return {
|
|
@@ -49889,7 +50170,9 @@ var LineMonthlyHistory = ({
|
|
|
49889
50170
|
const avgOutput = outputAverages.count > 0 ? outputAverages.output / outputAverages.count : 0;
|
|
49890
50171
|
const uptimeSummary = React144.useMemo(() => {
|
|
49891
50172
|
if (!isUptimeMode) return null;
|
|
49892
|
-
const validDays = (analysisMonthlyData || []).map((day) => getShiftData2(day, selectedShiftId)).filter(
|
|
50173
|
+
const validDays = (analysisMonthlyData || []).map((day) => getShiftData2(day, selectedShiftId)).filter(
|
|
50174
|
+
(shiftData) => shiftData && hasRealData(shiftData) && isValidAggregateEfficiency("uptime", shiftData.avg_efficiency)
|
|
50175
|
+
).map((shiftData) => ({ shiftData, totals: getUptimeTotals(shiftData) }));
|
|
49893
50176
|
if (!validDays.length) {
|
|
49894
50177
|
return { avgUtilization: 0, avgIdleTime: 0, avgDailyStoppages: 0 };
|
|
49895
50178
|
}
|
|
@@ -50037,7 +50320,9 @@ var LineMonthlyHistory = ({
|
|
|
50037
50320
|
}, [chartData.yAxisMax, chartData.lastSetTarget]);
|
|
50038
50321
|
const pieChartData = React144.useMemo(() => {
|
|
50039
50322
|
if (!isUptimeMode) return [];
|
|
50040
|
-
const validShifts = (analysisMonthlyData || []).map((day) => getShiftData2(day, selectedShiftId)).filter(
|
|
50323
|
+
const validShifts = (analysisMonthlyData || []).map((day) => getShiftData2(day, selectedShiftId)).filter(
|
|
50324
|
+
(shift) => shift && hasRealData(shift) && isValidAggregateEfficiency("uptime", shift.avg_efficiency)
|
|
50325
|
+
);
|
|
50041
50326
|
if (!validShifts.length) return [];
|
|
50042
50327
|
const efficiencyValues = validShifts.map((shift) => Number.isFinite(shift.avg_efficiency) ? Number(shift.avg_efficiency) : null).filter((value) => value !== null);
|
|
50043
50328
|
if (!efficiencyValues.length) return [];
|
|
@@ -50647,7 +50932,9 @@ var LineMonthlyPdfGenerator = ({
|
|
|
50647
50932
|
const productiveSeconds = activeSecondsRaw > 0 ? Math.min(activeSecondsRaw, availableSeconds) : Math.max(availableSeconds - idleSeconds, 0);
|
|
50648
50933
|
return { availableSeconds, productiveSeconds, idleSeconds };
|
|
50649
50934
|
};
|
|
50650
|
-
const validShifts = validDays.map((day) => getLineShiftData2(day, selectedShiftId)).filter(
|
|
50935
|
+
const validShifts = validDays.map((day) => getLineShiftData2(day, selectedShiftId)).filter(
|
|
50936
|
+
(shift) => hasShiftData(shift) && isValidAggregateEfficiency(isUptimeMode ? "uptime" : "output", shift.avg_efficiency)
|
|
50937
|
+
);
|
|
50651
50938
|
const monthlyMetrics = validShifts.length > 0 ? isUptimeMode ? (() => {
|
|
50652
50939
|
let utilizationSum = 0;
|
|
50653
50940
|
let idleTimeSum = 0;
|
|
@@ -52632,7 +52919,10 @@ var WorkspaceMonthlyHistory = ({
|
|
|
52632
52919
|
return ticks.filter((v) => v >= 0 && v <= max * 1.05).sort((a, b) => a - b);
|
|
52633
52920
|
}, [chartData.yAxisMax, chartData.lastSetTarget, isUptimeMode]);
|
|
52634
52921
|
const pieChartData = React144.useMemo(() => {
|
|
52635
|
-
const
|
|
52922
|
+
const aggregateMode = isUptimeMode ? "uptime" : "output";
|
|
52923
|
+
const validShifts = analysisMonthlyData.map((d) => getShiftData(d, selectedShiftId)).filter(
|
|
52924
|
+
(shift) => shift && hasRealData(shift) && isValidAggregateEfficiency(aggregateMode, shift.efficiency)
|
|
52925
|
+
);
|
|
52636
52926
|
if (validShifts.length === 0) return [];
|
|
52637
52927
|
const efficiencyValues = validShifts.map((shift) => Number.isFinite(shift.efficiency) ? Number(shift.efficiency) : null).filter((value) => value !== null);
|
|
52638
52928
|
if (!efficiencyValues.length) return [];
|
|
@@ -52643,10 +52933,10 @@ var WorkspaceMonthlyHistory = ({
|
|
|
52643
52933
|
{ name: "Productive", value: productivePercent },
|
|
52644
52934
|
{ name: "Idle", value: idlePercent }
|
|
52645
52935
|
];
|
|
52646
|
-
}, [analysisMonthlyData, selectedShiftId,
|
|
52936
|
+
}, [analysisMonthlyData, selectedShiftId, isUptimeMode]);
|
|
52647
52937
|
const metrics2 = React144.useMemo(() => {
|
|
52648
52938
|
const validShifts = analysisMonthlyData.map((d) => getShiftData(d, selectedShiftId)).filter(hasRealData);
|
|
52649
|
-
const filteredShifts = isUptimeMode ? validShifts
|
|
52939
|
+
const filteredShifts = isUptimeMode ? validShifts.filter((shift) => isValidAggregateEfficiency("uptime", shift.efficiency)) : validShifts.filter((shift) => isValidAggregateEfficiency("output", shift.efficiency));
|
|
52650
52940
|
if (filteredShifts.length === 0) return null;
|
|
52651
52941
|
const totalEfficiency = filteredShifts.reduce((sum, shift) => sum + (shift.efficiency || 0), 0);
|
|
52652
52942
|
const totalUtilization = filteredShifts.reduce(
|
|
@@ -53866,7 +54156,7 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
53866
54156
|
const shift = getShiftData(dayData, selectedShiftId);
|
|
53867
54157
|
return { dayData, shift };
|
|
53868
54158
|
}).filter(({ shift }) => hasShiftData(shift)).sort((left, right) => getDayDateKey(right.dayData).localeCompare(getDayDateKey(left.dayData)));
|
|
53869
|
-
const filteredShifts = isUptimeMode ? validShifts
|
|
54159
|
+
const filteredShifts = isUptimeMode ? validShifts.filter((shift) => isValidAggregateEfficiency("uptime", shift.efficiency)) : validShifts.filter((shift) => isValidAggregateEfficiency("output", shift.efficiency));
|
|
53870
54160
|
const monthlyMetrics = filteredShifts.length > 0 ? isUptimeMode ? (() => {
|
|
53871
54161
|
const totalIdleTime = filteredShifts.reduce((sum, shift) => sum + shift.idleTime, 0);
|
|
53872
54162
|
const totalCycleTime = filteredShifts.reduce((sum, shift) => sum + shift.cycleTime, 0);
|
|
@@ -54136,7 +54426,8 @@ var WorkspaceCycleTimeMetricCards = ({
|
|
|
54136
54426
|
idleTimeData,
|
|
54137
54427
|
skuAware,
|
|
54138
54428
|
skuBreakdown,
|
|
54139
|
-
activeSkuId
|
|
54429
|
+
activeSkuId,
|
|
54430
|
+
liveSkuId
|
|
54140
54431
|
}) => {
|
|
54141
54432
|
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
54142
54433
|
const activeSku = React144__namespace.default.useMemo(() => {
|
|
@@ -54145,6 +54436,13 @@ var WorkspaceCycleTimeMetricCards = ({
|
|
|
54145
54436
|
}
|
|
54146
54437
|
return null;
|
|
54147
54438
|
}, [skuAware, activeSkuId, skuBreakdown]);
|
|
54439
|
+
const displaySku = React144__namespace.default.useMemo(() => {
|
|
54440
|
+
if (activeSku) return activeSku;
|
|
54441
|
+
if (skuAware && !activeSkuId && liveSkuId && skuBreakdown) {
|
|
54442
|
+
return skuBreakdown.find((s) => s.sku_id === liveSkuId) ?? null;
|
|
54443
|
+
}
|
|
54444
|
+
return null;
|
|
54445
|
+
}, [activeSku, skuAware, activeSkuId, liveSkuId, skuBreakdown]);
|
|
54148
54446
|
const cycleValue = activeSku ? activeSku.avg_cycle_time : workspace.avg_cycle_time;
|
|
54149
54447
|
const cycleStandard = activeSku ? activeSku.ideal_cycle_time : workspace.ideal_cycle_time;
|
|
54150
54448
|
const efficiencyValue = workspace.avg_efficiency || 0;
|
|
@@ -54174,7 +54472,7 @@ var WorkspaceCycleTimeMetricCards = ({
|
|
|
54174
54472
|
/* @__PURE__ */ jsxRuntime.jsxs(Card2, { className: "flex flex-col bg-white shadow-sm border border-gray-200 h-full min-h-[150px] sm:min-h-0 rounded-xl", children: [
|
|
54175
54473
|
/* @__PURE__ */ jsxRuntime.jsxs(CardHeader2, { className: "pb-1 pt-5 flex-none text-center", children: [
|
|
54176
54474
|
/* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-[15px] font-bold text-gray-900 tracking-wide", children: "Cycle Time (s)" }),
|
|
54177
|
-
|
|
54475
|
+
displaySku && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-blue-600 mt-1 truncate px-2", title: displaySku.sku_code, children: displaySku.sku_code })
|
|
54178
54476
|
] }),
|
|
54179
54477
|
/* @__PURE__ */ jsxRuntime.jsxs(CardContent2, { className: "flex-1 flex flex-col items-center justify-center pb-6", children: [
|
|
54180
54478
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-5xl font-bold tracking-tight ${cycleValue > (cycleStandard || 0) ? "text-red-500" : "text-[#34C759]"}`, children: cycleValue.toFixed(1) }),
|
|
@@ -67038,7 +67336,15 @@ var KPIDetailView = ({
|
|
|
67038
67336
|
const fallbackTimes = resolveMonthlyShiftTimes(metric.shift_id);
|
|
67039
67337
|
const resolvedShiftStart = metric.shift_start || fallbackTimes.start;
|
|
67040
67338
|
const resolvedShiftEnd = metric.shift_end || fallbackTimes.end;
|
|
67041
|
-
const
|
|
67339
|
+
const coerceOptionalNumber2 = (value) => {
|
|
67340
|
+
if (value === void 0 || value === null || value === "") return null;
|
|
67341
|
+
const parsed = Number(value);
|
|
67342
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
67343
|
+
};
|
|
67344
|
+
const metricActiveTimeSeconds = coerceOptionalNumber2(metric.active_time_seconds);
|
|
67345
|
+
const metricIdleTimeSeconds = coerceOptionalNumber2(metric.idle_time_seconds);
|
|
67346
|
+
const metricAvailableTimeSeconds = coerceOptionalNumber2(metric.available_time_seconds);
|
|
67347
|
+
const hasBackendUptimeSeconds = isUptimeMode && (metricActiveTimeSeconds !== null || metricIdleTimeSeconds !== null || metricAvailableTimeSeconds !== null);
|
|
67042
67348
|
const uptimeSeries2 = isUptimeMode && !hasBackendUptimeSeconds ? buildUptimeSeries({
|
|
67043
67349
|
idleTimeHourly: metric.idle_time_hourly || {},
|
|
67044
67350
|
shiftStart: resolvedShiftStart || void 0,
|
|
@@ -67046,9 +67352,13 @@ var KPIDetailView = ({
|
|
|
67046
67352
|
shiftDate: metric.date,
|
|
67047
67353
|
timezone: configuredTimezone
|
|
67048
67354
|
}) : null;
|
|
67049
|
-
const idleTimeSeconds = isUptimeMode ? hasBackendUptimeSeconds ?
|
|
67050
|
-
const activeTimeSeconds = isUptimeMode ? hasBackendUptimeSeconds ?
|
|
67051
|
-
const availableTimeSeconds = isUptimeMode ? hasBackendUptimeSeconds ?
|
|
67355
|
+
const idleTimeSeconds = isUptimeMode ? hasBackendUptimeSeconds ? metricIdleTimeSeconds ?? 0 : (uptimeSeries2?.idleMinutes || 0) * 60 : 0;
|
|
67356
|
+
const activeTimeSeconds = isUptimeMode ? hasBackendUptimeSeconds ? metricActiveTimeSeconds ?? 0 : (uptimeSeries2?.activeMinutes || 0) * 60 : 0;
|
|
67357
|
+
const availableTimeSeconds = isUptimeMode ? hasBackendUptimeSeconds ? metricAvailableTimeSeconds ?? activeTimeSeconds + idleTimeSeconds : (uptimeSeries2?.availableMinutes || 0) * 60 : 0;
|
|
67358
|
+
const metricAvgEfficiency = Number(metric.avg_efficiency);
|
|
67359
|
+
const metricTotalWorkspaces = Number(metric.total_workspaces || 0);
|
|
67360
|
+
const metricCurrentOutput = Number(metric.current_output || 0);
|
|
67361
|
+
const hasUptimeMetricData = isUptimeMode && (availableTimeSeconds > 0 || metricTotalWorkspaces > 0 || metricCurrentOutput > 0 || Number.isFinite(metricAvgEfficiency) && metricAvgEfficiency > 0);
|
|
67052
67362
|
const computedUptimeEfficiency = (() => {
|
|
67053
67363
|
const availableMinutes = availableTimeSeconds / 60;
|
|
67054
67364
|
if (!availableMinutes || availableMinutes <= 0) return 0;
|
|
@@ -67068,7 +67378,7 @@ var KPIDetailView = ({
|
|
|
67068
67378
|
targetOutput: Number(metric.line_threshold ?? metric.ideal_output ?? 0),
|
|
67069
67379
|
compliance_percentage: 95 + Math.random() * 5,
|
|
67070
67380
|
// Mock data: random value between 95-100%
|
|
67071
|
-
hasData: isUptimeMode ?
|
|
67381
|
+
hasData: isUptimeMode ? hasUptimeMetricData : true,
|
|
67072
67382
|
idle_time_seconds: idleTimeSeconds,
|
|
67073
67383
|
active_time_seconds: activeTimeSeconds,
|
|
67074
67384
|
available_time_seconds: availableTimeSeconds,
|
|
@@ -68252,6 +68562,9 @@ var KPIDetailView = ({
|
|
|
68252
68562
|
var KPIDetailViewWithDisplayNames = withSelectedLineDisplayNames(KPIDetailView);
|
|
68253
68563
|
var KPIDetailView_default = KPIDetailViewWithDisplayNames;
|
|
68254
68564
|
var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
|
|
68565
|
+
var KPI_FACTORY_QUERY_PARAM = "factory_id";
|
|
68566
|
+
var KPI_FACTORY_AREA_QUERY_PARAM = "factory_area_id";
|
|
68567
|
+
var getSingleQueryValue = (value) => typeof value === "string" && value.length > 0 ? value : void 0;
|
|
68255
68568
|
var resolveCompanyId = (...candidates) => candidates.find(isNonEmptyString);
|
|
68256
68569
|
var parseTimeToMinutes3 = (value) => {
|
|
68257
68570
|
if (!value) return null;
|
|
@@ -68288,7 +68601,9 @@ var getMonthDateInfo = (timezone) => {
|
|
|
68288
68601
|
var createKpisOverviewUrl = ({
|
|
68289
68602
|
tab,
|
|
68290
68603
|
date,
|
|
68291
|
-
shift
|
|
68604
|
+
shift,
|
|
68605
|
+
factoryId,
|
|
68606
|
+
factoryAreaId
|
|
68292
68607
|
}) => {
|
|
68293
68608
|
const params = new URLSearchParams();
|
|
68294
68609
|
if (tab) {
|
|
@@ -68300,6 +68615,12 @@ var createKpisOverviewUrl = ({
|
|
|
68300
68615
|
if (typeof shift === "number" && Number.isFinite(shift)) {
|
|
68301
68616
|
params.set("shift", shift.toString());
|
|
68302
68617
|
}
|
|
68618
|
+
if (!tab && factoryId) {
|
|
68619
|
+
params.set(KPI_FACTORY_QUERY_PARAM, factoryId);
|
|
68620
|
+
}
|
|
68621
|
+
if (!tab && factoryId && factoryAreaId) {
|
|
68622
|
+
params.set(KPI_FACTORY_AREA_QUERY_PARAM, factoryAreaId);
|
|
68623
|
+
}
|
|
68303
68624
|
const queryString = params.toString();
|
|
68304
68625
|
return queryString ? `/kpis?${queryString}` : "/kpis";
|
|
68305
68626
|
};
|
|
@@ -68821,6 +69142,101 @@ var LineCard = ({
|
|
|
68821
69142
|
}
|
|
68822
69143
|
);
|
|
68823
69144
|
};
|
|
69145
|
+
var KpiGroupCard = ({
|
|
69146
|
+
title,
|
|
69147
|
+
subtitle,
|
|
69148
|
+
kpis,
|
|
69149
|
+
isLoading,
|
|
69150
|
+
error,
|
|
69151
|
+
isUptimeMode,
|
|
69152
|
+
onClick
|
|
69153
|
+
}) => {
|
|
69154
|
+
const isOnTrack = React144__namespace.default.useMemo(() => {
|
|
69155
|
+
if (!kpis) return null;
|
|
69156
|
+
return isEfficiencyOnTrack(kpis.efficiency.value);
|
|
69157
|
+
}, [kpis]);
|
|
69158
|
+
const outputTarget = Number(kpis?.outputProgress?.target ?? 0);
|
|
69159
|
+
const outputCurrent = Number(kpis?.outputProgress?.current ?? 0);
|
|
69160
|
+
const progressPercent = outputTarget > 0 ? Math.min(outputCurrent / outputTarget * 100, 100) : 0;
|
|
69161
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69162
|
+
motion.div,
|
|
69163
|
+
{
|
|
69164
|
+
initial: { opacity: 0, y: 20 },
|
|
69165
|
+
animate: { opacity: 1, y: 0 },
|
|
69166
|
+
transition: { duration: 0.3 },
|
|
69167
|
+
onClick,
|
|
69168
|
+
className: "relative bg-white border border-gray-200/80 shadow-sm hover:shadow-lg \n rounded-xl p-4 sm:p-5 md:p-6 transition-all duration-200 cursor-pointer \n hover:scale-[1.01] active:scale-[0.99] group",
|
|
69169
|
+
children: [
|
|
69170
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 sm:mb-5 md:mb-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-start gap-2 sm:gap-3", children: [
|
|
69171
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
69172
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
69173
|
+
FittingTitle,
|
|
69174
|
+
{
|
|
69175
|
+
title,
|
|
69176
|
+
className: "text-[10px] sm:text-xs md:text-sm"
|
|
69177
|
+
}
|
|
69178
|
+
),
|
|
69179
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs font-medium text-gray-500", children: subtitle })
|
|
69180
|
+
] }),
|
|
69181
|
+
!isUptimeMode && kpis && isOnTrack !== null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1.5 px-2.5 sm:px-3 py-1 sm:py-1.5 rounded-full text-xs font-medium flex-shrink-0 ${isOnTrack ? "bg-emerald-100 text-emerald-700 border border-emerald-200" : "bg-red-100 text-red-700 border border-red-200"}`, style: { minWidth: "fit-content" }, children: [
|
|
69182
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-2 h-2 rounded-full ${isOnTrack ? "bg-emerald-500" : "bg-red-500"} animate-pulse` }),
|
|
69183
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: isOnTrack ? "On Track" : "Behind" })
|
|
69184
|
+
] })
|
|
69185
|
+
] }) }),
|
|
69186
|
+
isLoading && !kpis && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
69187
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse", children: [
|
|
69188
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 bg-gray-200 rounded w-1/3 mb-2" }),
|
|
69189
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-8 bg-gray-200 rounded w-1/2" })
|
|
69190
|
+
] }),
|
|
69191
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse", children: [
|
|
69192
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 bg-gray-200 rounded w-1/3 mb-2" }),
|
|
69193
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-8 bg-gray-200 rounded w-3/4" })
|
|
69194
|
+
] }),
|
|
69195
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse", children: [
|
|
69196
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 bg-gray-200 rounded w-1/3 mb-2" }),
|
|
69197
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-8 bg-gray-200 rounded w-1/2" })
|
|
69198
|
+
] })
|
|
69199
|
+
] }),
|
|
69200
|
+
error && !kpis && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Unable to load metrics" }) }),
|
|
69201
|
+
kpis && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 sm:space-y-5 pb-8 sm:pb-10", children: [
|
|
69202
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
69203
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-medium text-gray-500 uppercase tracking-wider mb-1.5 sm:mb-2", children: isUptimeMode ? "Utilization" : "Efficiency" }),
|
|
69204
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline justify-between", children: [
|
|
69205
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-2xl sm:text-3xl font-semibold text-gray-900", children: [
|
|
69206
|
+
kpis.efficiency.value.toFixed(1),
|
|
69207
|
+
"%"
|
|
69208
|
+
] }),
|
|
69209
|
+
kpis.efficiency.change !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `text-xs sm:text-sm font-medium ${kpis.efficiency.change > 0 ? "text-emerald-600" : "text-red-600"}`, children: [
|
|
69210
|
+
kpis.efficiency.change > 0 ? "+" : "",
|
|
69211
|
+
kpis.efficiency.change.toFixed(1),
|
|
69212
|
+
"%"
|
|
69213
|
+
] })
|
|
69214
|
+
] })
|
|
69215
|
+
] }),
|
|
69216
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
69217
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-medium text-gray-500 uppercase tracking-wider mb-1.5 sm:mb-2", children: isUptimeMode ? "Stoppages" : "Output Progress" }),
|
|
69218
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline justify-between mb-2 sm:mb-3", children: [
|
|
69219
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `${isUptimeMode ? "text-2xl sm:text-3xl font-bold text-red-600" : "text-xl sm:text-2xl font-semibold text-gray-900"}`, children: kpis.outputProgress.current }),
|
|
69220
|
+
!isUptimeMode && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs sm:text-sm text-gray-500 font-medium", children: [
|
|
69221
|
+
"/ ",
|
|
69222
|
+
kpis.outputProgress.target,
|
|
69223
|
+
" units"
|
|
69224
|
+
] })
|
|
69225
|
+
] }),
|
|
69226
|
+
!isUptimeMode && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full bg-gray-200 rounded-full h-2 sm:h-2.5", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
69227
|
+
"div",
|
|
69228
|
+
{
|
|
69229
|
+
className: "bg-blue-600 h-2 sm:h-2.5 rounded-full transition-all duration-500 ease-out",
|
|
69230
|
+
style: { width: `${progressPercent}%` }
|
|
69231
|
+
}
|
|
69232
|
+
) })
|
|
69233
|
+
] })
|
|
69234
|
+
] }),
|
|
69235
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-3 right-3 sm:bottom-4 sm:right-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 sm:p-2.5 rounded-full bg-gray-50 group-hover:bg-blue-50 transition-colors shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsx(outline.ArrowRightIcon, { className: "w-4 h-4 sm:w-5 sm:h-5 text-gray-400 group-hover:text-blue-600 transition-colors" }) }) })
|
|
69236
|
+
]
|
|
69237
|
+
}
|
|
69238
|
+
);
|
|
69239
|
+
};
|
|
68824
69240
|
var KPIsOverviewView = ({
|
|
68825
69241
|
companyId,
|
|
68826
69242
|
navigate,
|
|
@@ -68986,6 +69402,20 @@ var KPIsOverviewView = ({
|
|
|
68986
69402
|
const effectiveLeaderboardDate = selectedLeaderboardDate || currentShiftDate;
|
|
68987
69403
|
const effectiveLeaderboardShiftId = Number.isFinite(selectedLeaderboardShiftId) ? selectedLeaderboardShiftId : currentShiftId;
|
|
68988
69404
|
const isHistoricalLeaderboardDaily = activeTab === "leaderboard" && timeRange === "today" && (effectiveLeaderboardDate !== currentShiftDate || effectiveLeaderboardShiftId !== currentShiftId);
|
|
69405
|
+
const selectedFactoryIdFromUrl = getSingleQueryValue(router$1.query[KPI_FACTORY_QUERY_PARAM]);
|
|
69406
|
+
const selectedFactoryAreaIdFromUrl = getSingleQueryValue(router$1.query[KPI_FACTORY_AREA_QUERY_PARAM]);
|
|
69407
|
+
const kpiLineHierarchy = React144__namespace.default.useMemo(
|
|
69408
|
+
() => buildKpiLineHierarchy(linesForView),
|
|
69409
|
+
[linesForView]
|
|
69410
|
+
);
|
|
69411
|
+
const selectedFactoryNode = React144__namespace.default.useMemo(
|
|
69412
|
+
() => kpiLineHierarchy.showFactoryLevel && selectedFactoryIdFromUrl ? kpiLineHierarchy.factories.find((factory) => factory.id === selectedFactoryIdFromUrl) : void 0,
|
|
69413
|
+
[kpiLineHierarchy, selectedFactoryIdFromUrl]
|
|
69414
|
+
);
|
|
69415
|
+
const selectedFactoryAreaNode = React144__namespace.default.useMemo(
|
|
69416
|
+
() => selectedFactoryNode && selectedFactoryAreaIdFromUrl ? selectedFactoryNode.areas.find((area) => area.id === selectedFactoryAreaIdFromUrl) : void 0,
|
|
69417
|
+
[selectedFactoryNode, selectedFactoryAreaIdFromUrl]
|
|
69418
|
+
);
|
|
68989
69419
|
React144.useEffect(() => {
|
|
68990
69420
|
if (!router$1.isReady) return;
|
|
68991
69421
|
const tabQuery = router$1.query.tab;
|
|
@@ -69013,20 +69443,27 @@ var KPIsOverviewView = ({
|
|
|
69013
69443
|
]);
|
|
69014
69444
|
React144.useEffect(() => {
|
|
69015
69445
|
if (!router$1.isReady || !hasHydratedLeaderboardRouteState) return;
|
|
69446
|
+
if (activeTab === "today" && loading) return;
|
|
69016
69447
|
const expectedTab = activeTab === "leaderboard" ? "leaderboard" : void 0;
|
|
69017
69448
|
const expectedDate = activeTab === "leaderboard" && timeRange === "today" && isHistoricalLeaderboardDaily ? effectiveLeaderboardDate : void 0;
|
|
69018
69449
|
const expectedShift = expectedDate !== void 0 ? effectiveLeaderboardShiftId.toString() : void 0;
|
|
69450
|
+
const expectedFactory = activeTab === "today" && selectedFactoryNode ? selectedFactoryNode.id : void 0;
|
|
69451
|
+
const expectedFactoryArea = activeTab === "today" && selectedFactoryNode && selectedFactoryAreaNode ? selectedFactoryAreaNode.id : void 0;
|
|
69019
69452
|
const currentTab = typeof router$1.query.tab === "string" ? router$1.query.tab : void 0;
|
|
69020
69453
|
const currentDateQuery = typeof router$1.query.date === "string" ? router$1.query.date : void 0;
|
|
69021
69454
|
const currentShiftQuery = typeof router$1.query.shift === "string" ? router$1.query.shift : void 0;
|
|
69022
|
-
|
|
69455
|
+
const currentFactoryQuery = getSingleQueryValue(router$1.query[KPI_FACTORY_QUERY_PARAM]);
|
|
69456
|
+
const currentFactoryAreaQuery = getSingleQueryValue(router$1.query[KPI_FACTORY_AREA_QUERY_PARAM]);
|
|
69457
|
+
if (currentTab === expectedTab && currentDateQuery === expectedDate && currentShiftQuery === expectedShift && currentFactoryQuery === expectedFactory && currentFactoryAreaQuery === expectedFactoryArea) {
|
|
69023
69458
|
return;
|
|
69024
69459
|
}
|
|
69025
69460
|
void router$1.replace(
|
|
69026
69461
|
createKpisOverviewUrl({
|
|
69027
69462
|
tab: expectedTab === "leaderboard" ? "leaderboard" : void 0,
|
|
69028
69463
|
date: expectedDate,
|
|
69029
|
-
shift: expectedShift !== void 0 ? Number.parseInt(expectedShift, 10) : void 0
|
|
69464
|
+
shift: expectedShift !== void 0 ? Number.parseInt(expectedShift, 10) : void 0,
|
|
69465
|
+
factoryId: expectedFactory,
|
|
69466
|
+
factoryAreaId: expectedFactoryArea
|
|
69030
69467
|
}),
|
|
69031
69468
|
void 0,
|
|
69032
69469
|
{ shallow: true }
|
|
@@ -69038,7 +69475,10 @@ var KPIsOverviewView = ({
|
|
|
69038
69475
|
effectiveLeaderboardDate,
|
|
69039
69476
|
effectiveLeaderboardShiftId,
|
|
69040
69477
|
hasHydratedLeaderboardRouteState,
|
|
69041
|
-
isHistoricalLeaderboardDaily
|
|
69478
|
+
isHistoricalLeaderboardDaily,
|
|
69479
|
+
loading,
|
|
69480
|
+
selectedFactoryNode,
|
|
69481
|
+
selectedFactoryAreaNode
|
|
69042
69482
|
]);
|
|
69043
69483
|
const factoryViewId = entityConfig.factoryViewId || "factory";
|
|
69044
69484
|
const {
|
|
@@ -69050,13 +69490,42 @@ var KPIsOverviewView = ({
|
|
|
69050
69490
|
userAccessibleLineIds: metricsLineIds
|
|
69051
69491
|
});
|
|
69052
69492
|
const defaultKPIs = React144__namespace.default.useMemo(() => createDefaultKPIs(), []);
|
|
69053
|
-
const
|
|
69493
|
+
const lineModeById = React144__namespace.default.useMemo(() => {
|
|
69494
|
+
const map = /* @__PURE__ */ new Map();
|
|
69495
|
+
linesForView.forEach((line) => {
|
|
69496
|
+
map.set(line.id, line.monitoring_mode ?? "output");
|
|
69497
|
+
});
|
|
69498
|
+
return map;
|
|
69499
|
+
}, [linesForView]);
|
|
69500
|
+
const lineMetricRowsByLineId = React144__namespace.default.useMemo(() => {
|
|
69054
69501
|
const map = /* @__PURE__ */ new Map();
|
|
69055
69502
|
lineMetrics.forEach((row) => {
|
|
69056
|
-
if (row?.line_id)
|
|
69503
|
+
if (!row?.line_id) return;
|
|
69504
|
+
const monitoringMode = lineModeById.get(row.line_id);
|
|
69505
|
+
map.set(
|
|
69506
|
+
row.line_id,
|
|
69507
|
+
monitoringMode ? { ...row, monitoring_mode: monitoringMode } : row
|
|
69508
|
+
);
|
|
69057
69509
|
});
|
|
69058
69510
|
return map;
|
|
69059
|
-
}, [lineMetrics]);
|
|
69511
|
+
}, [lineMetrics, lineModeById]);
|
|
69512
|
+
const kpisByLineId = React144__namespace.default.useMemo(() => {
|
|
69513
|
+
const map = /* @__PURE__ */ new Map();
|
|
69514
|
+
lineMetricRowsByLineId.forEach((row, lineId) => {
|
|
69515
|
+
map.set(lineId, buildKPIsFromLineMetricsRow(row));
|
|
69516
|
+
});
|
|
69517
|
+
return map;
|
|
69518
|
+
}, [lineMetricRowsByLineId]);
|
|
69519
|
+
const getLineCardKpis = React144__namespace.default.useCallback((line) => {
|
|
69520
|
+
if (metricsError) return null;
|
|
69521
|
+
return kpisByLineId.get(line.id) ?? (metricsLoading ? null : defaultKPIs);
|
|
69522
|
+
}, [defaultKPIs, kpisByLineId, metricsError, metricsLoading]);
|
|
69523
|
+
const getAggregateCardKpis = React144__namespace.default.useCallback((cardLines) => {
|
|
69524
|
+
if (metricsError) return null;
|
|
69525
|
+
const rows = cardLines.map((line) => lineMetricRowsByLineId.get(line.id)).filter(Boolean);
|
|
69526
|
+
if (metricsLoading && rows.length === 0) return null;
|
|
69527
|
+
return aggregateKPIsFromLineMetricsRows(rows);
|
|
69528
|
+
}, [lineMetricRowsByLineId, metricsError, metricsLoading]);
|
|
69060
69529
|
const supervisorLineIds = React144__namespace.default.useMemo(
|
|
69061
69530
|
() => (leaderboardLines.length > 0 ? leaderboardLines : lines).map((l) => l.id),
|
|
69062
69531
|
[leaderboardLines, lines]
|
|
@@ -69260,6 +69729,20 @@ var KPIsOverviewView = ({
|
|
|
69260
69729
|
if (activeTab !== "leaderboard" || timeRange !== "today") return;
|
|
69261
69730
|
fetchDailyLeaderboard();
|
|
69262
69731
|
}, [activeTab, timeRange, fetchDailyLeaderboard]);
|
|
69732
|
+
const navigateTodayHierarchy = React144.useCallback((factoryId, factoryAreaId) => {
|
|
69733
|
+
void router$1.push(
|
|
69734
|
+
createKpisOverviewUrl({ factoryId, factoryAreaId }),
|
|
69735
|
+
void 0,
|
|
69736
|
+
{ shallow: true }
|
|
69737
|
+
);
|
|
69738
|
+
}, [router$1]);
|
|
69739
|
+
const lineDetailReturnTo = React144__namespace.default.useMemo(() => {
|
|
69740
|
+
if (activeTab !== "today" || !selectedFactoryNode) return void 0;
|
|
69741
|
+
return createKpisOverviewUrl({
|
|
69742
|
+
factoryId: selectedFactoryNode.id,
|
|
69743
|
+
factoryAreaId: selectedFactoryAreaNode?.id
|
|
69744
|
+
});
|
|
69745
|
+
}, [activeTab, selectedFactoryNode, selectedFactoryAreaNode]);
|
|
69263
69746
|
const formatTopPerformerWeek = (periodStart, periodEnd) => {
|
|
69264
69747
|
const dateToUse = periodStart ? /* @__PURE__ */ new Date(`${periodStart}T00:00:00`) : /* @__PURE__ */ new Date();
|
|
69265
69748
|
if (Number.isNaN(dateToUse.getTime())) {
|
|
@@ -69346,7 +69829,8 @@ var KPIsOverviewView = ({
|
|
|
69346
69829
|
);
|
|
69347
69830
|
return;
|
|
69348
69831
|
}
|
|
69349
|
-
|
|
69832
|
+
const returnToQuery = lineDetailReturnTo ? `?returnTo=${encodeURIComponent(lineDetailReturnTo)}` : "";
|
|
69833
|
+
navigation.navigate(`/kpis/${line.id}${returnToQuery}`);
|
|
69350
69834
|
};
|
|
69351
69835
|
const handleBackClick = React144.useCallback(() => {
|
|
69352
69836
|
trackCoreEvent("Back Button Clicked", {
|
|
@@ -69415,6 +69899,70 @@ var KPIsOverviewView = ({
|
|
|
69415
69899
|
}
|
|
69416
69900
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
69417
69901
|
};
|
|
69902
|
+
const renderLineCard = (line) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
69903
|
+
LineCard,
|
|
69904
|
+
{
|
|
69905
|
+
line,
|
|
69906
|
+
kpis: getLineCardKpis(line),
|
|
69907
|
+
isLoading: metricsLoading,
|
|
69908
|
+
error: metricsError,
|
|
69909
|
+
onClick: (kpis) => handleLineClick(line, kpis),
|
|
69910
|
+
supervisorEnabled,
|
|
69911
|
+
supervisorName: supervisorNamesByLineId.get(line.id) || null,
|
|
69912
|
+
supervisors: supervisorsByLineId?.get(line.id)
|
|
69913
|
+
},
|
|
69914
|
+
line.id
|
|
69915
|
+
);
|
|
69916
|
+
const renderGroupCard = ({
|
|
69917
|
+
key,
|
|
69918
|
+
title,
|
|
69919
|
+
subtitle,
|
|
69920
|
+
lines: cardLines,
|
|
69921
|
+
onClick
|
|
69922
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
69923
|
+
KpiGroupCard,
|
|
69924
|
+
{
|
|
69925
|
+
title,
|
|
69926
|
+
subtitle,
|
|
69927
|
+
kpis: getAggregateCardKpis(cardLines),
|
|
69928
|
+
isLoading: metricsLoading,
|
|
69929
|
+
error: metricsError,
|
|
69930
|
+
isUptimeMode: viewType === "machine",
|
|
69931
|
+
onClick
|
|
69932
|
+
},
|
|
69933
|
+
key
|
|
69934
|
+
);
|
|
69935
|
+
const renderTodayCards = () => {
|
|
69936
|
+
if (!kpiLineHierarchy.showFactoryLevel) {
|
|
69937
|
+
return linesForView.map(renderLineCard);
|
|
69938
|
+
}
|
|
69939
|
+
if (selectedFactoryNode && selectedFactoryAreaNode) {
|
|
69940
|
+
return selectedFactoryAreaNode.lines.map(renderLineCard);
|
|
69941
|
+
}
|
|
69942
|
+
if (selectedFactoryNode) {
|
|
69943
|
+
return [
|
|
69944
|
+
...selectedFactoryNode.areas.map(
|
|
69945
|
+
(area) => renderGroupCard({
|
|
69946
|
+
key: `area-${area.id}`,
|
|
69947
|
+
title: area.areaName,
|
|
69948
|
+
subtitle: `${area.lines.length} ${area.lines.length === 1 ? "line" : "lines"}`,
|
|
69949
|
+
lines: area.lines,
|
|
69950
|
+
onClick: () => navigateTodayHierarchy(selectedFactoryNode.id, area.id)
|
|
69951
|
+
})
|
|
69952
|
+
),
|
|
69953
|
+
...selectedFactoryNode.ungroupedLines.map(renderLineCard)
|
|
69954
|
+
];
|
|
69955
|
+
}
|
|
69956
|
+
return kpiLineHierarchy.factories.map(
|
|
69957
|
+
(factory) => renderGroupCard({
|
|
69958
|
+
key: `factory-${factory.id}`,
|
|
69959
|
+
title: factory.factoryName,
|
|
69960
|
+
subtitle: `${factory.lines.length} ${factory.lines.length === 1 ? "line" : "lines"}`,
|
|
69961
|
+
lines: factory.lines,
|
|
69962
|
+
onClick: () => navigateTodayHierarchy(factory.id)
|
|
69963
|
+
})
|
|
69964
|
+
);
|
|
69965
|
+
};
|
|
69418
69966
|
if (loading || isShiftConfigLoading) {
|
|
69419
69967
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingPage, { message: "Loading production lines..." });
|
|
69420
69968
|
}
|
|
@@ -69847,23 +70395,34 @@ var KPIsOverviewView = ({
|
|
|
69847
70395
|
] })
|
|
69848
70396
|
] })
|
|
69849
70397
|
] }) }),
|
|
69850
|
-
/* @__PURE__ */ jsxRuntime.jsx("main", { className: `flex-1 p-3 sm:p-4 md:p-6 bg-slate-50 ${activeTab === "leaderboard" ? "overflow-hidden flex flex-col" : "overflow-y-auto"}`, children: activeTab === "today" ? (
|
|
69851
|
-
/*
|
|
69852
|
-
|
|
69853
|
-
|
|
69854
|
-
|
|
69855
|
-
|
|
69856
|
-
|
|
69857
|
-
|
|
69858
|
-
|
|
69859
|
-
|
|
69860
|
-
|
|
69861
|
-
|
|
69862
|
-
|
|
69863
|
-
|
|
69864
|
-
|
|
69865
|
-
|
|
69866
|
-
|
|
70398
|
+
/* @__PURE__ */ jsxRuntime.jsx("main", { className: `flex-1 p-3 sm:p-4 md:p-6 bg-slate-50 ${activeTab === "leaderboard" ? "overflow-hidden flex flex-col" : "overflow-y-auto"}`, children: activeTab === "today" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3 sm:space-y-4", children: [
|
|
70399
|
+
kpiLineHierarchy.showFactoryLevel && selectedFactoryNode && /* @__PURE__ */ jsxRuntime.jsxs("nav", { className: "flex flex-wrap items-center gap-2 text-sm", "aria-label": "KPI hierarchy", children: [
|
|
70400
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
70401
|
+
"button",
|
|
70402
|
+
{
|
|
70403
|
+
type: "button",
|
|
70404
|
+
onClick: () => navigateTodayHierarchy(),
|
|
70405
|
+
className: "font-medium text-gray-500 hover:text-blue-600 transition-colors",
|
|
70406
|
+
children: "Factories"
|
|
70407
|
+
}
|
|
70408
|
+
),
|
|
70409
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-300", children: "/" }),
|
|
70410
|
+
selectedFactoryAreaNode ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
70411
|
+
"button",
|
|
70412
|
+
{
|
|
70413
|
+
type: "button",
|
|
70414
|
+
onClick: () => navigateTodayHierarchy(selectedFactoryNode.id),
|
|
70415
|
+
className: "font-medium text-gray-500 hover:text-blue-600 transition-colors",
|
|
70416
|
+
children: selectedFactoryNode.factoryName
|
|
70417
|
+
}
|
|
70418
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-gray-900", children: selectedFactoryNode.factoryName }),
|
|
70419
|
+
selectedFactoryAreaNode && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
70420
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-300", children: "/" }),
|
|
70421
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-gray-900", children: selectedFactoryAreaNode.areaName })
|
|
70422
|
+
] })
|
|
70423
|
+
] }),
|
|
70424
|
+
/* @__PURE__ */ jsxRuntime.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: renderTodayCards() })
|
|
70425
|
+
] }) : showLeaderboardLoader ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex flex-col items-center justify-center bg-white rounded-2xl border border-gray-100 shadow-sm m-2 sm:m-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
69867
70426
|
OptifyeLogoLoader_default,
|
|
69868
70427
|
{
|
|
69869
70428
|
size: "lg",
|
|
@@ -69910,6 +70469,27 @@ var AnimatedEfficiency = React144.memo(({ value }) => {
|
|
|
69910
70469
|
return prevProps.value === nextProps.value;
|
|
69911
70470
|
});
|
|
69912
70471
|
AnimatedEfficiency.displayName = "AnimatedEfficiency";
|
|
70472
|
+
var getWorkspaceLeaderboardMetricValue = (workspace) => {
|
|
70473
|
+
if (workspace.monitoring_mode === "output") {
|
|
70474
|
+
return toFiniteNumber(workspace.efficiency);
|
|
70475
|
+
}
|
|
70476
|
+
if (workspace.leaderboard_metric_kind === "recent_flow_shift_average") {
|
|
70477
|
+
return toFiniteNumber(workspace.leaderboard_value);
|
|
70478
|
+
}
|
|
70479
|
+
return toFiniteNumber(workspace.leaderboard_value) ?? toFiniteNumber(workspace.efficiency);
|
|
70480
|
+
};
|
|
70481
|
+
var getWorkspaceDisplayedMetricValue = (workspace) => getWorkspaceLeaderboardMetricValue(workspace);
|
|
70482
|
+
var getWorkspaceLeaderboardMetricLabel = (workspace, defaultLabel) => workspace.monitoring_mode !== "output" && workspace.leaderboard_metric_kind === "recent_flow_shift_average" ? "Avg Flow" : defaultLabel;
|
|
70483
|
+
var renderWorkspaceLeaderboardMetric = (workspace, isAssemblyMode) => {
|
|
70484
|
+
if (isAssemblyMode) {
|
|
70485
|
+
return /* @__PURE__ */ jsxRuntime.jsx(CycleTimeComparison, { workspace });
|
|
70486
|
+
}
|
|
70487
|
+
const displayedMetricValue = getWorkspaceDisplayedMetricValue(workspace);
|
|
70488
|
+
if (displayedMetricValue === null) {
|
|
70489
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: "--" });
|
|
70490
|
+
}
|
|
70491
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AnimatedEfficiency, { value: displayedMetricValue });
|
|
70492
|
+
};
|
|
69913
70493
|
var HeaderRibbon = React144.memo(({
|
|
69914
70494
|
currentDate,
|
|
69915
70495
|
currentMobileDate,
|
|
@@ -69988,13 +70568,13 @@ var MobileWorkspaceCard = React144.memo(({
|
|
|
69988
70568
|
] })
|
|
69989
70569
|
] }),
|
|
69990
70570
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-right", children: [
|
|
69991
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-bold text-gray-900 text-lg flex justify-end", children:
|
|
69992
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children: metricLabel })
|
|
70571
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-bold text-gray-900 text-lg flex justify-end", children: renderWorkspaceLeaderboardMetric(workspace, isAssemblyMode) }),
|
|
70572
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children: getWorkspaceLeaderboardMetricLabel(workspace, metricLabel) })
|
|
69993
70573
|
] })
|
|
69994
70574
|
] })
|
|
69995
70575
|
}
|
|
69996
70576
|
), (prevProps, nextProps) => {
|
|
69997
|
-
return prevProps.metricLabel === nextProps.metricLabel && prevProps.isAssemblyMode === nextProps.isAssemblyMode && prevProps.rank === nextProps.rank && prevProps.cardClass === nextProps.cardClass && prevProps.isClickable === nextProps.isClickable && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.ideal_cycle_time === nextProps.workspace.ideal_cycle_time && prevProps.workspace.action_count === nextProps.workspace.action_count && prevProps.workspace.action_threshold === nextProps.workspace.action_threshold && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
|
|
70577
|
+
return prevProps.metricLabel === nextProps.metricLabel && prevProps.isAssemblyMode === nextProps.isAssemblyMode && prevProps.rank === nextProps.rank && prevProps.cardClass === nextProps.cardClass && prevProps.isClickable === nextProps.isClickable && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.leaderboard_value === nextProps.workspace.leaderboard_value && prevProps.workspace.leaderboard_metric_kind === nextProps.workspace.leaderboard_metric_kind && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.ideal_cycle_time === nextProps.workspace.ideal_cycle_time && prevProps.workspace.action_count === nextProps.workspace.action_count && prevProps.workspace.action_threshold === nextProps.workspace.action_threshold && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
|
|
69998
70578
|
});
|
|
69999
70579
|
MobileWorkspaceCard.displayName = "MobileWorkspaceCard";
|
|
70000
70580
|
var DesktopWorkspaceRow = React144.memo(({
|
|
@@ -70021,11 +70601,11 @@ var DesktopWorkspaceRow = React144.memo(({
|
|
|
70021
70601
|
] }) }),
|
|
70022
70602
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium", children: workspace.displayName }) }),
|
|
70023
70603
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium", children: workspace.lineName }) }),
|
|
70024
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: `px-3 py-2.5 sm:p-4 text-sm sm:text-base font-medium ${isAssemblyMode ? "" : "whitespace-nowrap"}`, children: isAssemblyMode ?
|
|
70604
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: `px-3 py-2.5 sm:p-4 text-sm sm:text-base font-medium ${isAssemblyMode ? "" : "whitespace-nowrap"}`, children: isAssemblyMode ? renderWorkspaceLeaderboardMetric(workspace, true) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col", children: renderWorkspaceLeaderboardMetric(workspace, false) }) })
|
|
70025
70605
|
]
|
|
70026
70606
|
}
|
|
70027
70607
|
), (prevProps, nextProps) => {
|
|
70028
|
-
return prevProps.index === nextProps.index && prevProps.rowClass === nextProps.rowClass && prevProps.isClickable === nextProps.isClickable && prevProps.isAssemblyMode === nextProps.isAssemblyMode && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.ideal_cycle_time === nextProps.workspace.ideal_cycle_time && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
|
|
70608
|
+
return prevProps.index === nextProps.index && prevProps.rowClass === nextProps.rowClass && prevProps.isClickable === nextProps.isClickable && prevProps.isAssemblyMode === nextProps.isAssemblyMode && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.leaderboard_value === nextProps.workspace.leaderboard_value && prevProps.workspace.leaderboard_metric_kind === nextProps.workspace.leaderboard_metric_kind && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.ideal_cycle_time === nextProps.workspace.ideal_cycle_time && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
|
|
70029
70609
|
});
|
|
70030
70610
|
DesktopWorkspaceRow.displayName = "DesktopWorkspaceRow";
|
|
70031
70611
|
var LeaderboardDetailView = React144.memo(({
|
|
@@ -70124,6 +70704,8 @@ var LeaderboardDetailView = React144.memo(({
|
|
|
70124
70704
|
const [monthlyError, setMonthlyError] = React144.useState(null);
|
|
70125
70705
|
const todayRequestKeyRef = React144.useRef(null);
|
|
70126
70706
|
const monthlyRequestKeyRef = React144.useRef(null);
|
|
70707
|
+
const monthlyLoadKeyRef = React144.useRef(null);
|
|
70708
|
+
const monthlyLoadPromiseRef = React144.useRef(null);
|
|
70127
70709
|
const leaderboardUpdateQueuedRef = React144.useRef(false);
|
|
70128
70710
|
const leaderboardUpdateTimerRef = React144.useRef(null);
|
|
70129
70711
|
const leaderboardViewTrackedRef = React144.useRef(null);
|
|
@@ -70398,6 +70980,9 @@ var LeaderboardDetailView = React144.memo(({
|
|
|
70398
70980
|
trend: 0,
|
|
70399
70981
|
predicted_output: 0,
|
|
70400
70982
|
efficiency: entry.efficiency || 0,
|
|
70983
|
+
avg_recent_flow: toFiniteNumber(entry.avg_recent_flow),
|
|
70984
|
+
leaderboard_value: toFiniteNumber(entry.leaderboard_value),
|
|
70985
|
+
leaderboard_metric_kind: entry.leaderboard_metric_kind ?? "efficiency",
|
|
70401
70986
|
action_threshold: entry.total_day_output || 0,
|
|
70402
70987
|
displayName: entry.workspace_display_name,
|
|
70403
70988
|
monitoring_mode: entry.monitoring_mode ?? "output"
|
|
@@ -70428,7 +71013,10 @@ var LeaderboardDetailView = React144.memo(({
|
|
|
70428
71013
|
searchParams.set("monitoring_mode", viewType === "machine" ? "uptime" : "output");
|
|
70429
71014
|
const data = await fetchBackendJson(
|
|
70430
71015
|
supabase,
|
|
70431
|
-
`/api/dashboard/leaderboard?${searchParams.toString()}
|
|
71016
|
+
`/api/dashboard/leaderboard?${searchParams.toString()}`,
|
|
71017
|
+
{
|
|
71018
|
+
timeoutMs: params.startDate && params.endDate ? 3e4 : void 0
|
|
71019
|
+
}
|
|
70432
71020
|
);
|
|
70433
71021
|
return data.entries || [];
|
|
70434
71022
|
}, [supabase, entityConfig.companyId, configuredLineIds, viewType]);
|
|
@@ -70506,15 +71094,21 @@ var LeaderboardDetailView = React144.memo(({
|
|
|
70506
71094
|
setMonthlyLoading(true);
|
|
70507
71095
|
setMonthlyError(null);
|
|
70508
71096
|
try {
|
|
70509
|
-
const
|
|
70510
|
-
|
|
70511
|
-
|
|
70512
|
-
|
|
70513
|
-
|
|
71097
|
+
const loadPromise = monthlyLoadPromiseRef.current && monthlyLoadKeyRef.current === requestKey ? monthlyLoadPromiseRef.current : (async () => {
|
|
71098
|
+
const entries = await fetchLeaderboardEntries({
|
|
71099
|
+
startDate: normalizedRange.startKey,
|
|
71100
|
+
endDate: normalizedRange.endKey,
|
|
71101
|
+
shiftId: monthlyShiftId
|
|
71102
|
+
});
|
|
71103
|
+
return mapEntriesToWorkspaces(entries, normalizedRange.endKey, monthlyShiftId);
|
|
71104
|
+
})();
|
|
71105
|
+
monthlyLoadKeyRef.current = requestKey;
|
|
71106
|
+
monthlyLoadPromiseRef.current = loadPromise;
|
|
71107
|
+
const workspaces = await loadPromise;
|
|
70514
71108
|
if (monthlyRequestKeyRef.current !== requestKey) {
|
|
70515
71109
|
return;
|
|
70516
71110
|
}
|
|
70517
|
-
setMonthlyEntries(
|
|
71111
|
+
setMonthlyEntries(workspaces);
|
|
70518
71112
|
} catch (err) {
|
|
70519
71113
|
console.error("[LeaderboardDetailView] Error fetching monthly leaderboard:", err);
|
|
70520
71114
|
if (monthlyRequestKeyRef.current !== requestKey) {
|
|
@@ -70523,6 +71117,9 @@ var LeaderboardDetailView = React144.memo(({
|
|
|
70523
71117
|
setMonthlyError({ message: err.message, code: err.code || "FETCH_ERROR" });
|
|
70524
71118
|
setMonthlyEntries([]);
|
|
70525
71119
|
} finally {
|
|
71120
|
+
if (monthlyLoadKeyRef.current === requestKey && monthlyLoadPromiseRef.current) {
|
|
71121
|
+
monthlyLoadPromiseRef.current = null;
|
|
71122
|
+
}
|
|
70526
71123
|
if (monthlyRequestKeyRef.current === requestKey) {
|
|
70527
71124
|
setMonthlyLoading(false);
|
|
70528
71125
|
}
|
|
@@ -70535,6 +71132,46 @@ var LeaderboardDetailView = React144.memo(({
|
|
|
70535
71132
|
monthlyShiftId,
|
|
70536
71133
|
lineKey
|
|
70537
71134
|
]);
|
|
71135
|
+
React144.useEffect(() => {
|
|
71136
|
+
if (activeTab !== "today") {
|
|
71137
|
+
return;
|
|
71138
|
+
}
|
|
71139
|
+
const requestKey = `${normalizedRange.startKey}|${normalizedRange.endKey}|${monthlyShiftId}|${lineKey}|${viewType}`;
|
|
71140
|
+
let cancelled = false;
|
|
71141
|
+
const loadPromise = monthlyLoadPromiseRef.current && monthlyLoadKeyRef.current === requestKey ? monthlyLoadPromiseRef.current : (async () => {
|
|
71142
|
+
const entries = await fetchLeaderboardEntries({
|
|
71143
|
+
startDate: normalizedRange.startKey,
|
|
71144
|
+
endDate: normalizedRange.endKey,
|
|
71145
|
+
shiftId: monthlyShiftId
|
|
71146
|
+
});
|
|
71147
|
+
return mapEntriesToWorkspaces(entries, normalizedRange.endKey, monthlyShiftId);
|
|
71148
|
+
})();
|
|
71149
|
+
monthlyLoadKeyRef.current = requestKey;
|
|
71150
|
+
monthlyLoadPromiseRef.current = loadPromise;
|
|
71151
|
+
loadPromise.then((workspaces) => {
|
|
71152
|
+
if (cancelled) {
|
|
71153
|
+
return;
|
|
71154
|
+
}
|
|
71155
|
+
setMonthlyEntries(workspaces);
|
|
71156
|
+
}).catch(() => {
|
|
71157
|
+
}).finally(() => {
|
|
71158
|
+
if (!cancelled && monthlyLoadKeyRef.current === requestKey && monthlyLoadPromiseRef.current === loadPromise) {
|
|
71159
|
+
monthlyLoadPromiseRef.current = null;
|
|
71160
|
+
}
|
|
71161
|
+
});
|
|
71162
|
+
return () => {
|
|
71163
|
+
cancelled = true;
|
|
71164
|
+
};
|
|
71165
|
+
}, [
|
|
71166
|
+
activeTab,
|
|
71167
|
+
fetchLeaderboardEntries,
|
|
71168
|
+
mapEntriesToWorkspaces,
|
|
71169
|
+
normalizedRange.endKey,
|
|
71170
|
+
normalizedRange.startKey,
|
|
71171
|
+
monthlyShiftId,
|
|
71172
|
+
lineKey,
|
|
71173
|
+
viewType
|
|
71174
|
+
]);
|
|
70538
71175
|
React144.useEffect(() => {
|
|
70539
71176
|
if (activeTab === "today") {
|
|
70540
71177
|
fetchTodayLeaderboard();
|
|
@@ -70669,6 +71306,9 @@ var LeaderboardDetailView = React144.memo(({
|
|
|
70669
71306
|
total_workspaces: workspacesLengthRef.current,
|
|
70670
71307
|
// Use ref instead of state to avoid dependency
|
|
70671
71308
|
metric_context: viewType === "machine" ? "machine" : outputCategory,
|
|
71309
|
+
leaderboard_value: getWorkspaceLeaderboardMetricValue(workspace),
|
|
71310
|
+
leaderboard_metric_kind: workspace.leaderboard_metric_kind ?? "efficiency",
|
|
71311
|
+
avg_recent_flow: workspace.avg_recent_flow ?? null,
|
|
70672
71312
|
efficiency: workspace.efficiency,
|
|
70673
71313
|
action_count: workspace.action_count,
|
|
70674
71314
|
action_threshold: workspace.action_threshold,
|
|
@@ -70749,9 +71389,12 @@ var LeaderboardDetailView = React144.memo(({
|
|
|
70749
71389
|
if (ratioB === null) return -1;
|
|
70750
71390
|
return sortAscending ? ratioA - ratioB : ratioB - ratioA;
|
|
70751
71391
|
}
|
|
70752
|
-
const
|
|
70753
|
-
const
|
|
70754
|
-
|
|
71392
|
+
const metricA = getWorkspaceLeaderboardMetricValue(a);
|
|
71393
|
+
const metricB = getWorkspaceLeaderboardMetricValue(b);
|
|
71394
|
+
if (metricA === null && metricB === null) return 0;
|
|
71395
|
+
if (metricA === null) return 1;
|
|
71396
|
+
if (metricB === null) return -1;
|
|
71397
|
+
return sortAscending ? metricA - metricB : metricB - metricA;
|
|
70755
71398
|
});
|
|
70756
71399
|
}, [workspaceDisplayData, sortAscending, selectedLineFilter, selectedShiftFilter, activeTab, viewType, isAssemblyMode]);
|
|
70757
71400
|
const loading = activeTab === "today" ? todayLoading : monthlyLoading;
|
|
@@ -70780,6 +71423,8 @@ var LeaderboardDetailView = React144.memo(({
|
|
|
70780
71423
|
workspace_count: sortedWorkspaces.length,
|
|
70781
71424
|
top_workspace_id: topWorkspace?.workspace_uuid ?? null,
|
|
70782
71425
|
top_workspace_name: topWorkspace?.workspace_name ?? null,
|
|
71426
|
+
top_leaderboard_value: topWorkspace ? getWorkspaceLeaderboardMetricValue(topWorkspace) : null,
|
|
71427
|
+
top_leaderboard_metric_kind: topWorkspace?.leaderboard_metric_kind ?? null,
|
|
70783
71428
|
top_efficiency: topWorkspace?.efficiency ?? null,
|
|
70784
71429
|
top_avg_cycle_time: topWorkspace?.avg_cycle_time ?? null,
|
|
70785
71430
|
top_ideal_cycle_time: topWorkspace?.ideal_cycle_time ?? null,
|
|
@@ -75925,7 +76570,11 @@ var WorkspaceDetailView = ({
|
|
|
75925
76570
|
workspace,
|
|
75926
76571
|
legend: efficiencyLegend,
|
|
75927
76572
|
layout: "stack",
|
|
75928
|
-
idleTimeData: idleTimeVlmEnabled ? idleTimeData : void 0
|
|
76573
|
+
idleTimeData: idleTimeVlmEnabled ? idleTimeData : void 0,
|
|
76574
|
+
skuAware: isSkuAware,
|
|
76575
|
+
skuBreakdown: isSkuAware ? realSkuBreakdown : void 0,
|
|
76576
|
+
activeSkuId,
|
|
76577
|
+
liveSkuId: isHistoricView ? null : liveSkuId
|
|
75929
76578
|
}
|
|
75930
76579
|
) : /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
75931
76580
|
WorkspaceMetricCards,
|
|
@@ -75935,7 +76584,8 @@ var WorkspaceDetailView = ({
|
|
|
75935
76584
|
className: "flex-1",
|
|
75936
76585
|
skuAware: isSkuAware,
|
|
75937
76586
|
skuBreakdown: isSkuAware ? realSkuBreakdown : void 0,
|
|
75938
|
-
activeSkuId
|
|
76587
|
+
activeSkuId,
|
|
76588
|
+
liveSkuId: isHistoricView ? null : liveSkuId
|
|
75939
76589
|
}
|
|
75940
76590
|
) })
|
|
75941
76591
|
] }),
|
|
@@ -76078,7 +76728,11 @@ var WorkspaceDetailView = ({
|
|
|
76078
76728
|
legend: efficiencyLegend,
|
|
76079
76729
|
layout: "grid",
|
|
76080
76730
|
className: desktopBottomSectionClass,
|
|
76081
|
-
idleTimeData: idleTimeVlmEnabled ? idleTimeData : void 0
|
|
76731
|
+
idleTimeData: idleTimeVlmEnabled ? idleTimeData : void 0,
|
|
76732
|
+
skuAware: isSkuAware,
|
|
76733
|
+
skuBreakdown: isSkuAware ? realSkuBreakdown : void 0,
|
|
76734
|
+
activeSkuId,
|
|
76735
|
+
liveSkuId: isHistoricView ? null : liveSkuId
|
|
76082
76736
|
}
|
|
76083
76737
|
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
76084
76738
|
WorkspaceMetricCards,
|
|
@@ -76088,7 +76742,8 @@ var WorkspaceDetailView = ({
|
|
|
76088
76742
|
className: "flex-1",
|
|
76089
76743
|
skuAware: isSkuAware,
|
|
76090
76744
|
skuBreakdown: isSkuAware ? realSkuBreakdown : void 0,
|
|
76091
|
-
activeSkuId
|
|
76745
|
+
activeSkuId,
|
|
76746
|
+
liveSkuId: isHistoricView ? null : liveSkuId
|
|
76092
76747
|
}
|
|
76093
76748
|
) })
|
|
76094
76749
|
] })
|
|
@@ -85376,6 +86031,7 @@ exports.authRateLimitService = authRateLimitService;
|
|
|
85376
86031
|
exports.awardsService = awardsService;
|
|
85377
86032
|
exports.buildDateKey = buildDateKey;
|
|
85378
86033
|
exports.buildKPIsFromLineMetricsRow = buildKPIsFromLineMetricsRow;
|
|
86034
|
+
exports.buildKpiLineHierarchy = buildKpiLineHierarchy;
|
|
85379
86035
|
exports.buildLineSkuBreakdown = buildLineSkuBreakdown;
|
|
85380
86036
|
exports.buildShiftGroupsKey = buildShiftGroupsKey;
|
|
85381
86037
|
exports.canRoleAccessDashboardPath = canRoleAccessDashboardPath;
|