@optifye/dashboard-core 6.11.4 → 6.11.6
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 +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +763 -254
- package/dist/index.mjs +765 -257
- package/package.json +9 -1
package/dist/index.js
CHANGED
|
@@ -652,6 +652,17 @@ var getMonthKeyBounds = (year, monthIndex) => {
|
|
|
652
652
|
const endKey = buildDateKey(year, monthIndex, lastDay);
|
|
653
653
|
return { startKey, endKey };
|
|
654
654
|
};
|
|
655
|
+
var getCurrentWeekToDateRange = (timezone, now4 = /* @__PURE__ */ new Date()) => {
|
|
656
|
+
const todayKey = dateFnsTz.formatInTimeZone(now4, timezone || "UTC", "yyyy-MM-dd");
|
|
657
|
+
const todayDate = dateFns.parseISO(`${todayKey}T00:00:00`);
|
|
658
|
+
const dayOfWeek = dateFns.getDay(todayDate);
|
|
659
|
+
const daysSinceMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
|
|
660
|
+
const weekStart = dateFns.subDays(todayDate, daysSinceMonday);
|
|
661
|
+
return {
|
|
662
|
+
startKey: dateFns.format(weekStart, "yyyy-MM-dd"),
|
|
663
|
+
endKey: dateFns.format(todayDate, "yyyy-MM-dd")
|
|
664
|
+
};
|
|
665
|
+
};
|
|
655
666
|
var normalizeDateKeyRange = (startKey, endKey, minKey, maxKey) => {
|
|
656
667
|
const clampedStart = startKey < minKey ? minKey : startKey > maxKey ? maxKey : startKey;
|
|
657
668
|
const clampedEnd = endKey < minKey ? minKey : endKey > maxKey ? maxKey : endKey;
|
|
@@ -2710,6 +2721,45 @@ var workspaceService = {
|
|
|
2710
2721
|
}
|
|
2711
2722
|
}
|
|
2712
2723
|
};
|
|
2724
|
+
|
|
2725
|
+
// src/lib/utils/workspaceHealthSummary.ts
|
|
2726
|
+
var computeWorkspaceHealthSummary = (data, lastUpdated = (/* @__PURE__ */ new Date()).toISOString()) => {
|
|
2727
|
+
const totalWorkspaces = data.length;
|
|
2728
|
+
const healthyWorkspaces = data.filter((workspace) => workspace.status === "healthy").length;
|
|
2729
|
+
const unhealthyWorkspaces = data.filter((workspace) => workspace.status === "unhealthy").length;
|
|
2730
|
+
const warningWorkspaces = data.filter((workspace) => workspace.status === "warning").length;
|
|
2731
|
+
const workspacesWithUptime = data.filter(
|
|
2732
|
+
(workspace) => workspace.hasUptimeData && workspace.uptimePercentage !== void 0 && workspace.uptimeDetails !== void 0
|
|
2733
|
+
);
|
|
2734
|
+
const workspacesWithoutUptimeData = totalWorkspaces - workspacesWithUptime.length;
|
|
2735
|
+
let uptimePercentage = null;
|
|
2736
|
+
let totalDowntimeMinutes;
|
|
2737
|
+
if (workspacesWithUptime.length > 0) {
|
|
2738
|
+
const totalUptime = workspacesWithUptime.reduce(
|
|
2739
|
+
(sum, workspace) => sum + (workspace.uptimePercentage || 0),
|
|
2740
|
+
0
|
|
2741
|
+
);
|
|
2742
|
+
uptimePercentage = totalUptime / workspacesWithUptime.length;
|
|
2743
|
+
totalDowntimeMinutes = workspacesWithUptime.reduce((sum, workspace) => {
|
|
2744
|
+
if (!workspace.uptimeDetails) {
|
|
2745
|
+
return sum;
|
|
2746
|
+
}
|
|
2747
|
+
return sum + Math.max(0, workspace.uptimeDetails.expectedMinutes - workspace.uptimeDetails.actualMinutes);
|
|
2748
|
+
}, 0);
|
|
2749
|
+
}
|
|
2750
|
+
return {
|
|
2751
|
+
totalWorkspaces,
|
|
2752
|
+
healthyWorkspaces,
|
|
2753
|
+
unhealthyWorkspaces,
|
|
2754
|
+
warningWorkspaces,
|
|
2755
|
+
uptimePercentage,
|
|
2756
|
+
workspacesWithoutUptimeData,
|
|
2757
|
+
totalDowntimeMinutes,
|
|
2758
|
+
lastUpdated
|
|
2759
|
+
};
|
|
2760
|
+
};
|
|
2761
|
+
|
|
2762
|
+
// src/lib/services/workspaceHealthService.ts
|
|
2713
2763
|
var DATA_PROCESSING_DELAY_MINUTES = 5;
|
|
2714
2764
|
var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
2715
2765
|
constructor() {
|
|
@@ -2849,6 +2899,24 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2849
2899
|
}
|
|
2850
2900
|
return "down";
|
|
2851
2901
|
}
|
|
2902
|
+
hasCompletedTimelineData(completedMinutes, shiftStartDate, outputHourly, outputArray, timezone) {
|
|
2903
|
+
if (completedMinutes <= 0) {
|
|
2904
|
+
return false;
|
|
2905
|
+
}
|
|
2906
|
+
for (let minuteIndex = 0; minuteIndex < completedMinutes; minuteIndex++) {
|
|
2907
|
+
const minuteDate = dateFns.addMinutes(shiftStartDate, minuteIndex);
|
|
2908
|
+
const hourKey = dateFnsTz.formatInTimeZone(minuteDate, timezone, "H");
|
|
2909
|
+
const minuteKey = Number.parseInt(dateFnsTz.formatInTimeZone(minuteDate, timezone, "m"), 10);
|
|
2910
|
+
const hourBucket = outputHourly[hourKey];
|
|
2911
|
+
if (Array.isArray(hourBucket) && hourBucket[minuteKey] !== void 0) {
|
|
2912
|
+
return true;
|
|
2913
|
+
}
|
|
2914
|
+
if (minuteIndex < outputArray.length) {
|
|
2915
|
+
return true;
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
return false;
|
|
2919
|
+
}
|
|
2852
2920
|
async getWorkspaceHealthStatus(options = {}) {
|
|
2853
2921
|
const supabase = _getSupabaseInstance();
|
|
2854
2922
|
if (!supabase) throw new Error("Supabase client not initialized");
|
|
@@ -2903,11 +2971,15 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2903
2971
|
if (uptimeDetails) {
|
|
2904
2972
|
return {
|
|
2905
2973
|
...workspace,
|
|
2974
|
+
hasUptimeData: true,
|
|
2906
2975
|
uptimePercentage: uptimeDetails.percentage,
|
|
2907
2976
|
uptimeDetails
|
|
2908
2977
|
};
|
|
2909
2978
|
}
|
|
2910
|
-
return
|
|
2979
|
+
return {
|
|
2980
|
+
...workspace,
|
|
2981
|
+
hasUptimeData: false
|
|
2982
|
+
};
|
|
2911
2983
|
});
|
|
2912
2984
|
let filteredData = dataWithUptime;
|
|
2913
2985
|
try {
|
|
@@ -3039,6 +3111,33 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
3039
3111
|
const record = Array.isArray(data) && data.length > 0 ? data[0] : null;
|
|
3040
3112
|
const outputHourly = this.normalizeOutputHourly(record?.output_hourly || {});
|
|
3041
3113
|
const outputArray = Array.isArray(record?.output_array) ? record.output_array : [];
|
|
3114
|
+
const hasData = Boolean(
|
|
3115
|
+
record && this.hasCompletedTimelineData(
|
|
3116
|
+
completedMinutes,
|
|
3117
|
+
shiftStartDate,
|
|
3118
|
+
outputHourly,
|
|
3119
|
+
outputArray,
|
|
3120
|
+
timezone
|
|
3121
|
+
)
|
|
3122
|
+
);
|
|
3123
|
+
if (!hasData) {
|
|
3124
|
+
return {
|
|
3125
|
+
shiftId: queryShiftId,
|
|
3126
|
+
shiftLabel,
|
|
3127
|
+
shiftStart: dateFnsTz.formatInTimeZone(shiftStartDate, timezone, "yyyy-MM-dd'T'HH:mm:ssXXX"),
|
|
3128
|
+
shiftEnd: dateFnsTz.formatInTimeZone(shiftEndDate, timezone, "yyyy-MM-dd'T'HH:mm:ssXXX"),
|
|
3129
|
+
totalMinutes,
|
|
3130
|
+
completedMinutes,
|
|
3131
|
+
uptimeMinutes: 0,
|
|
3132
|
+
downtimeMinutes: 0,
|
|
3133
|
+
pendingMinutes,
|
|
3134
|
+
uptimePercentage: 0,
|
|
3135
|
+
hasData: false,
|
|
3136
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3137
|
+
points: [],
|
|
3138
|
+
downtimeSegments: []
|
|
3139
|
+
};
|
|
3140
|
+
}
|
|
3042
3141
|
const points = [];
|
|
3043
3142
|
let uptimeMinutes = 0;
|
|
3044
3143
|
let downtimeMinutes = 0;
|
|
@@ -3124,6 +3223,7 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
3124
3223
|
downtimeMinutes,
|
|
3125
3224
|
pendingMinutes,
|
|
3126
3225
|
uptimePercentage,
|
|
3226
|
+
hasData: true,
|
|
3127
3227
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3128
3228
|
points,
|
|
3129
3229
|
downtimeSegments: filteredSegments
|
|
@@ -3152,37 +3252,7 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
3152
3252
|
async getHealthSummary(lineId, companyId) {
|
|
3153
3253
|
this.clearCache();
|
|
3154
3254
|
const workspaces = await this.getWorkspaceHealthStatus({ lineId, companyId });
|
|
3155
|
-
|
|
3156
|
-
const healthyWorkspaces = workspaces.filter((w) => w.status === "healthy").length;
|
|
3157
|
-
const unhealthyWorkspaces = workspaces.filter((w) => w.status === "unhealthy").length;
|
|
3158
|
-
const warningWorkspaces = workspaces.filter((w) => w.status === "warning").length;
|
|
3159
|
-
let uptimePercentage = 0;
|
|
3160
|
-
let totalDowntimeMinutes = 0;
|
|
3161
|
-
if (totalWorkspaces > 0) {
|
|
3162
|
-
const workspacesWithUptime = workspaces.filter((w) => w.uptimePercentage !== void 0 && w.uptimeDetails !== void 0);
|
|
3163
|
-
if (workspacesWithUptime.length > 0) {
|
|
3164
|
-
const totalUptime = workspacesWithUptime.reduce((sum, w) => sum + (w.uptimePercentage || 0), 0);
|
|
3165
|
-
uptimePercentage = totalUptime / workspacesWithUptime.length;
|
|
3166
|
-
totalDowntimeMinutes = workspacesWithUptime.reduce((sum, w) => {
|
|
3167
|
-
if (w.uptimeDetails) {
|
|
3168
|
-
const downtime = Math.max(0, w.uptimeDetails.expectedMinutes - w.uptimeDetails.actualMinutes);
|
|
3169
|
-
return sum + downtime;
|
|
3170
|
-
}
|
|
3171
|
-
return sum;
|
|
3172
|
-
}, 0);
|
|
3173
|
-
} else {
|
|
3174
|
-
uptimePercentage = healthyWorkspaces / totalWorkspaces * 100;
|
|
3175
|
-
}
|
|
3176
|
-
}
|
|
3177
|
-
return {
|
|
3178
|
-
totalWorkspaces,
|
|
3179
|
-
healthyWorkspaces,
|
|
3180
|
-
unhealthyWorkspaces,
|
|
3181
|
-
warningWorkspaces,
|
|
3182
|
-
uptimePercentage,
|
|
3183
|
-
totalDowntimeMinutes,
|
|
3184
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
3185
|
-
};
|
|
3255
|
+
return computeWorkspaceHealthSummary(workspaces);
|
|
3186
3256
|
}
|
|
3187
3257
|
async getHealthMetrics(workspaceId, startDate, endDate) {
|
|
3188
3258
|
const supabase = _getSupabaseInstance();
|
|
@@ -3221,7 +3291,8 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
3221
3291
|
...data,
|
|
3222
3292
|
status,
|
|
3223
3293
|
timeSinceLastUpdate,
|
|
3224
|
-
isStale
|
|
3294
|
+
isStale,
|
|
3295
|
+
hasUptimeData: false
|
|
3225
3296
|
};
|
|
3226
3297
|
}
|
|
3227
3298
|
getStatusPriority(status) {
|
|
@@ -15965,7 +16036,8 @@ var useWorkspaceHealthById = (workspaceId, options) => {
|
|
|
15965
16036
|
...healthData,
|
|
15966
16037
|
status,
|
|
15967
16038
|
timeSinceLastUpdate,
|
|
15968
|
-
isStale: !lastUpdate || now4.getTime() - lastUpdate.getTime() > 15 * 6e4
|
|
16039
|
+
isStale: !lastUpdate || now4.getTime() - lastUpdate.getTime() > 15 * 6e4,
|
|
16040
|
+
hasUptimeData: false
|
|
15969
16041
|
};
|
|
15970
16042
|
setWorkspace(workspaceWithStatus);
|
|
15971
16043
|
} else {
|
|
@@ -48017,14 +48089,11 @@ var WorkspaceHealthCard = ({
|
|
|
48017
48089
|
};
|
|
48018
48090
|
const getDowntimeConfig = (uptimeDetails) => {
|
|
48019
48091
|
if (!uptimeDetails) {
|
|
48020
|
-
|
|
48021
|
-
|
|
48022
|
-
|
|
48023
|
-
|
|
48024
|
-
|
|
48025
|
-
};
|
|
48026
|
-
}
|
|
48027
|
-
return { text: "--", className: "text-slate-400", label: "Total Downtime" };
|
|
48092
|
+
return {
|
|
48093
|
+
text: "--",
|
|
48094
|
+
className: "text-slate-400",
|
|
48095
|
+
label: "Uptime Data"
|
|
48096
|
+
};
|
|
48028
48097
|
}
|
|
48029
48098
|
const downtimeMinutes = Math.max(0, uptimeDetails.expectedMinutes - uptimeDetails.actualMinutes);
|
|
48030
48099
|
if (downtimeMinutes === 0) {
|
|
@@ -48083,7 +48152,7 @@ var WorkspaceHealthCard = ({
|
|
|
48083
48152
|
] })
|
|
48084
48153
|
] }),
|
|
48085
48154
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 pt-3 border-t border-slate-100 dark:border-slate-800", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
48086
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-slate-500 uppercase tracking-wide", children:
|
|
48155
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-slate-500 uppercase tracking-wide", children: downtimeConfig.label }),
|
|
48087
48156
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx("text-sm font-semibold", downtimeConfig.className), children: downtimeConfig.text })
|
|
48088
48157
|
] }) })
|
|
48089
48158
|
] }),
|
|
@@ -48106,8 +48175,8 @@ var CompactWorkspaceHealthCard = ({
|
|
|
48106
48175
|
className = "",
|
|
48107
48176
|
onViewDetails
|
|
48108
48177
|
}) => {
|
|
48109
|
-
const downtimeMinutes = workspace.uptimeDetails ? Math.max(0, workspace.uptimeDetails.expectedMinutes - workspace.uptimeDetails.actualMinutes) : null;
|
|
48110
|
-
const downtimeLabel = downtimeMinutes === null ? "No downtime data" : downtimeMinutes === 0 ? "No downtime" : `${downtimeMinutes} min down`;
|
|
48178
|
+
const downtimeMinutes = workspace.hasUptimeData && workspace.uptimeDetails ? Math.max(0, workspace.uptimeDetails.expectedMinutes - workspace.uptimeDetails.actualMinutes) : null;
|
|
48179
|
+
const downtimeLabel = !workspace.hasUptimeData ? "Uptime data unavailable" : downtimeMinutes === null ? "No downtime data" : downtimeMinutes === 0 ? "No downtime" : `${downtimeMinutes} min down`;
|
|
48111
48180
|
const getStatusConfig = () => {
|
|
48112
48181
|
switch (workspace.status) {
|
|
48113
48182
|
case "healthy":
|
|
@@ -48176,7 +48245,7 @@ var CompactWorkspaceHealthCard = ({
|
|
|
48176
48245
|
] })
|
|
48177
48246
|
] }),
|
|
48178
48247
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
48179
|
-
workspace.uptimePercentage !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
48248
|
+
workspace.hasUptimeData && workspace.uptimePercentage !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
48180
48249
|
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs font-medium text-gray-600 dark:text-gray-400", children: [
|
|
48181
48250
|
workspace.uptimePercentage.toFixed(1),
|
|
48182
48251
|
"%"
|
|
@@ -48184,6 +48253,7 @@ var CompactWorkspaceHealthCard = ({
|
|
|
48184
48253
|
downtimeMinutes !== null && downtimeMinutes > 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-400 dark:text-gray-400", children: "\u2022" }),
|
|
48185
48254
|
downtimeLabel && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: downtimeLabel })
|
|
48186
48255
|
] }),
|
|
48256
|
+
!workspace.hasUptimeData && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Uptime data unavailable" }),
|
|
48187
48257
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: workspace.timeSinceLastUpdate }),
|
|
48188
48258
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("h-2 w-2 rounded-full", config.dot) }),
|
|
48189
48259
|
onViewDetails && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -49756,7 +49826,28 @@ var SideNavBar = React141.memo(({
|
|
|
49756
49826
|
const [isSettingsOpen, setIsSettingsOpen] = React141.useState(false);
|
|
49757
49827
|
const settingsTriggerRef = React141.useRef(null);
|
|
49758
49828
|
const [isAlertsOpen, setIsAlertsOpen] = React141.useState(false);
|
|
49759
|
-
const [alertsCount, setAlertsCount] = React141.useState(
|
|
49829
|
+
const [alertsCount, setAlertsCount] = React141.useState(null);
|
|
49830
|
+
const [lastViewedCount, setLastViewedCount] = React141.useState(() => {
|
|
49831
|
+
if (typeof window !== "undefined") {
|
|
49832
|
+
return parseInt(localStorage.getItem("lastViewedAlertsCount") || "0", 10);
|
|
49833
|
+
}
|
|
49834
|
+
return 0;
|
|
49835
|
+
});
|
|
49836
|
+
React141.useEffect(() => {
|
|
49837
|
+
if (alertsCount === null) return;
|
|
49838
|
+
setLastViewedCount((prev) => {
|
|
49839
|
+
if (isAlertsOpen) {
|
|
49840
|
+
localStorage.setItem("lastViewedAlertsCount", alertsCount.toString());
|
|
49841
|
+
return alertsCount;
|
|
49842
|
+
}
|
|
49843
|
+
if (alertsCount < prev) {
|
|
49844
|
+
localStorage.setItem("lastViewedAlertsCount", alertsCount.toString());
|
|
49845
|
+
return alertsCount;
|
|
49846
|
+
}
|
|
49847
|
+
return prev;
|
|
49848
|
+
});
|
|
49849
|
+
}, [alertsCount, isAlertsOpen]);
|
|
49850
|
+
const unreadCount = alertsCount !== null ? Math.max(0, alertsCount - lastViewedCount) : 0;
|
|
49760
49851
|
const alertsTriggerRef = React141.useRef(null);
|
|
49761
49852
|
const alertsCompanyId = entityConfig.companyId || user?.company_id;
|
|
49762
49853
|
const showAlertsButton = (role === "supervisor" || role === "optifye") && !!alertsCompanyId && !!supabase;
|
|
@@ -50045,10 +50136,7 @@ var SideNavBar = React141.memo(({
|
|
|
50045
50136
|
children: [
|
|
50046
50137
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
50047
50138
|
/* @__PURE__ */ jsxRuntime.jsx(outline.BellIcon, { className: "w-5 h-5 mb-1" }),
|
|
50048
|
-
|
|
50049
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75" }),
|
|
50050
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex rounded-full h-2.5 w-2.5 bg-red-500" })
|
|
50051
|
-
] })
|
|
50139
|
+
unreadCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-1.5 -right-1.5 flex h-4 min-w-[16px] items-center justify-center rounded-full bg-red-500 px-1 text-[9px] font-bold text-white shadow-sm ring-2 ring-white", children: unreadCount > 99 ? "99+" : unreadCount })
|
|
50052
50140
|
] }),
|
|
50053
50141
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight mt-1", children: "Alerts" })
|
|
50054
50142
|
]
|
|
@@ -50200,10 +50288,7 @@ var SideNavBar = React141.memo(({
|
|
|
50200
50288
|
children: [
|
|
50201
50289
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
50202
50290
|
/* @__PURE__ */ jsxRuntime.jsx(outline.BellIcon, { className: getIconClass("/alerts") }),
|
|
50203
|
-
|
|
50204
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75" }),
|
|
50205
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex rounded-full h-2.5 w-2.5 bg-red-500" })
|
|
50206
|
-
] })
|
|
50291
|
+
unreadCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-1.5 -right-1.5 flex h-4 min-w-[16px] items-center justify-center rounded-full bg-red-500 px-1 text-[9px] font-bold text-white shadow-sm ring-2 ring-white", children: unreadCount > 99 ? "99+" : unreadCount })
|
|
50207
50292
|
] }),
|
|
50208
50293
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-medium ml-3", children: "Alerts" })
|
|
50209
50294
|
]
|
|
@@ -50331,7 +50416,7 @@ var SideNavBar = React141.memo(({
|
|
|
50331
50416
|
onClose: () => setIsAlertsOpen(false),
|
|
50332
50417
|
triggerRef: alertsTriggerRef,
|
|
50333
50418
|
companyId: alertsCompanyId,
|
|
50334
|
-
alertsCount,
|
|
50419
|
+
alertsCount: alertsCount ?? 0,
|
|
50335
50420
|
onAlertsLoaded: setAlertsCount
|
|
50336
50421
|
}
|
|
50337
50422
|
)
|
|
@@ -57380,6 +57465,7 @@ var WEEKDAYS4 = ["S", "M", "T", "W", "T", "F", "S"];
|
|
|
57380
57465
|
var MonthlyRangeFilter = ({
|
|
57381
57466
|
month,
|
|
57382
57467
|
year,
|
|
57468
|
+
timezone,
|
|
57383
57469
|
value,
|
|
57384
57470
|
onChange,
|
|
57385
57471
|
onMonthNavigate,
|
|
@@ -57387,32 +57473,34 @@ var MonthlyRangeFilter = ({
|
|
|
57387
57473
|
variant = "default",
|
|
57388
57474
|
showLabel = true
|
|
57389
57475
|
}) => {
|
|
57390
|
-
const
|
|
57476
|
+
const todayKey = React141.useMemo(
|
|
57477
|
+
() => dateFnsTz.formatInTimeZone(/* @__PURE__ */ new Date(), timezone || "UTC", "yyyy-MM-dd"),
|
|
57478
|
+
[timezone]
|
|
57479
|
+
);
|
|
57480
|
+
const todayDate = React141.useMemo(() => parseDateKeyToDate(todayKey), [todayKey]);
|
|
57481
|
+
const presets = React141.useMemo(() => [
|
|
57391
57482
|
{
|
|
57392
|
-
label: "
|
|
57393
|
-
getValue: () => (
|
|
57394
|
-
start: dateFns.startOfDay(dateFns.subDays(/* @__PURE__ */ new Date(), 6)),
|
|
57395
|
-
end: dateFns.endOfDay(/* @__PURE__ */ new Date())
|
|
57396
|
-
})
|
|
57483
|
+
label: "This Week",
|
|
57484
|
+
getValue: () => getCurrentWeekToDateRange(timezone)
|
|
57397
57485
|
},
|
|
57398
57486
|
{
|
|
57399
57487
|
label: "Last Month",
|
|
57400
57488
|
getValue: () => {
|
|
57401
|
-
const lastMonth = dateFns.subMonths(
|
|
57489
|
+
const lastMonth = dateFns.subMonths(todayDate, 1);
|
|
57402
57490
|
return {
|
|
57403
|
-
|
|
57404
|
-
|
|
57491
|
+
startKey: dateFns.format(dateFns.startOfMonth(lastMonth), "yyyy-MM-dd"),
|
|
57492
|
+
endKey: dateFns.format(dateFns.endOfMonth(lastMonth), "yyyy-MM-dd")
|
|
57405
57493
|
};
|
|
57406
57494
|
}
|
|
57407
57495
|
},
|
|
57408
57496
|
{
|
|
57409
57497
|
label: "This Month",
|
|
57410
57498
|
getValue: () => ({
|
|
57411
|
-
|
|
57412
|
-
|
|
57499
|
+
startKey: dateFns.format(dateFns.startOfMonth(todayDate), "yyyy-MM-dd"),
|
|
57500
|
+
endKey: dateFns.format(todayDate, "yyyy-MM-dd")
|
|
57413
57501
|
})
|
|
57414
57502
|
}
|
|
57415
|
-
];
|
|
57503
|
+
], [timezone, todayDate]);
|
|
57416
57504
|
const monthBounds = React141.useMemo(() => getMonthKeyBounds(year, month), [year, month]);
|
|
57417
57505
|
const normalizedRange = React141.useMemo(() => {
|
|
57418
57506
|
return normalizeDateKeyRange(value.startKey, value.endKey, monthBounds.startKey, monthBounds.endKey);
|
|
@@ -57433,15 +57521,15 @@ var MonthlyRangeFilter = ({
|
|
|
57433
57521
|
const [rangeEnd, setRangeEnd] = React141.useState(parseDateKeyToDate(normalizedRange.endKey));
|
|
57434
57522
|
const [selecting, setSelecting] = React141.useState(false);
|
|
57435
57523
|
const [activePreset, setActivePreset] = React141.useState(null);
|
|
57436
|
-
const today = React141.useMemo(() => dateFns.endOfDay(
|
|
57524
|
+
const today = React141.useMemo(() => dateFns.endOfDay(todayDate), [todayDate]);
|
|
57437
57525
|
React141.useEffect(() => {
|
|
57438
57526
|
setCalendarMonth(month);
|
|
57439
57527
|
setCalendarYear(year);
|
|
57440
57528
|
}, [month, year]);
|
|
57441
57529
|
React141.useEffect(() => {
|
|
57442
57530
|
if (isOpen) {
|
|
57443
|
-
const start = parseDateKeyToDate(
|
|
57444
|
-
const end = parseDateKeyToDate(
|
|
57531
|
+
const start = parseDateKeyToDate(value.startKey);
|
|
57532
|
+
const end = parseDateKeyToDate(value.endKey);
|
|
57445
57533
|
setRangeStart(start);
|
|
57446
57534
|
setRangeEnd(end);
|
|
57447
57535
|
setSelecting(false);
|
|
@@ -57449,11 +57537,11 @@ var MonthlyRangeFilter = ({
|
|
|
57449
57537
|
setCalendarYear(year);
|
|
57450
57538
|
const match = presets.find((p) => {
|
|
57451
57539
|
const val = p.getValue();
|
|
57452
|
-
return
|
|
57540
|
+
return val.startKey === value.startKey && val.endKey === value.endKey;
|
|
57453
57541
|
});
|
|
57454
57542
|
setActivePreset(match ? match.label : "Custom");
|
|
57455
57543
|
}
|
|
57456
|
-
}, [isOpen,
|
|
57544
|
+
}, [isOpen, month, presets, value.endKey, value.startKey, year]);
|
|
57457
57545
|
React141.useEffect(() => {
|
|
57458
57546
|
const handleClickOutside = (event) => {
|
|
57459
57547
|
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
@@ -57483,7 +57571,9 @@ var MonthlyRangeFilter = ({
|
|
|
57483
57571
|
}
|
|
57484
57572
|
};
|
|
57485
57573
|
const handlePresetClick = (preset) => {
|
|
57486
|
-
const {
|
|
57574
|
+
const { startKey, endKey } = preset.getValue();
|
|
57575
|
+
const start = parseDateKeyToDate(startKey);
|
|
57576
|
+
const end = parseDateKeyToDate(endKey);
|
|
57487
57577
|
setRangeStart(start);
|
|
57488
57578
|
setRangeEnd(end);
|
|
57489
57579
|
setSelecting(false);
|
|
@@ -57523,8 +57613,7 @@ var MonthlyRangeFilter = ({
|
|
|
57523
57613
|
const nextMonthDate = dateFns.addMonths(new Date(calendarYear, calendarMonth), 1);
|
|
57524
57614
|
const newMonth = nextMonthDate.getMonth();
|
|
57525
57615
|
const newYear = nextMonthDate.getFullYear();
|
|
57526
|
-
|
|
57527
|
-
if (newYear > currentDate.getFullYear() || newYear === currentDate.getFullYear() && newMonth > currentDate.getMonth()) {
|
|
57616
|
+
if (newYear > todayDate.getFullYear() || newYear === todayDate.getFullYear() && newMonth > todayDate.getMonth()) {
|
|
57528
57617
|
return;
|
|
57529
57618
|
}
|
|
57530
57619
|
setCalendarMonth(newMonth);
|
|
@@ -57532,7 +57621,7 @@ var MonthlyRangeFilter = ({
|
|
|
57532
57621
|
onMonthNavigate?.(newMonth, newYear);
|
|
57533
57622
|
};
|
|
57534
57623
|
const canGoPrevious = !(calendarYear === 2023 && calendarMonth === 0);
|
|
57535
|
-
const canGoNext = !(calendarYear ===
|
|
57624
|
+
const canGoNext = !(calendarYear === todayDate.getFullYear() && calendarMonth === todayDate.getMonth());
|
|
57536
57625
|
const monthDate = React141.useMemo(() => new Date(calendarYear, calendarMonth), [calendarYear, calendarMonth]);
|
|
57537
57626
|
const calendarDays = React141.useMemo(() => {
|
|
57538
57627
|
const start = dateFns.startOfMonth(monthDate);
|
|
@@ -66713,7 +66802,8 @@ var useWorkspaceHealth = (options) => {
|
|
|
66713
66802
|
healthyWorkspaces: 0,
|
|
66714
66803
|
unhealthyWorkspaces: 0,
|
|
66715
66804
|
warningWorkspaces: 0,
|
|
66716
|
-
uptimePercentage:
|
|
66805
|
+
uptimePercentage: null,
|
|
66806
|
+
workspacesWithoutUptimeData: 0,
|
|
66717
66807
|
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
66718
66808
|
});
|
|
66719
66809
|
const [loading, setLoading] = React141.useState(true);
|
|
@@ -66721,36 +66811,10 @@ var useWorkspaceHealth = (options) => {
|
|
|
66721
66811
|
const isFetchingRef = React141.useRef(false);
|
|
66722
66812
|
const refreshIntervalRef = React141.useRef(null);
|
|
66723
66813
|
const healthTable = databaseConfig?.tables?.workspace_health || "workspace_health_status";
|
|
66724
|
-
const computeSummary = React141.useCallback(
|
|
66725
|
-
|
|
66726
|
-
|
|
66727
|
-
|
|
66728
|
-
const warning6 = data.filter((w) => w.status === "warning").length;
|
|
66729
|
-
let uptimePercentage = total > 0 ? healthy / total * 100 : 100;
|
|
66730
|
-
let totalDowntimeMinutes;
|
|
66731
|
-
const withUptime = data.filter(
|
|
66732
|
-
(w) => w.uptimePercentage !== void 0 && w.uptimeDetails !== void 0
|
|
66733
|
-
);
|
|
66734
|
-
if (withUptime.length > 0) {
|
|
66735
|
-
const totalUptime = withUptime.reduce((sum, w) => sum + (w.uptimePercentage || 0), 0);
|
|
66736
|
-
uptimePercentage = totalUptime / withUptime.length;
|
|
66737
|
-
totalDowntimeMinutes = withUptime.reduce((sum, w) => {
|
|
66738
|
-
if (w.uptimeDetails) {
|
|
66739
|
-
return sum + Math.max(0, w.uptimeDetails.expectedMinutes - w.uptimeDetails.actualMinutes);
|
|
66740
|
-
}
|
|
66741
|
-
return sum;
|
|
66742
|
-
}, 0);
|
|
66743
|
-
}
|
|
66744
|
-
return {
|
|
66745
|
-
totalWorkspaces: total,
|
|
66746
|
-
healthyWorkspaces: healthy,
|
|
66747
|
-
unhealthyWorkspaces: unhealthy,
|
|
66748
|
-
warningWorkspaces: warning6,
|
|
66749
|
-
uptimePercentage,
|
|
66750
|
-
totalDowntimeMinutes,
|
|
66751
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
66752
|
-
};
|
|
66753
|
-
}, []);
|
|
66814
|
+
const computeSummary = React141.useCallback(
|
|
66815
|
+
(data) => computeWorkspaceHealthSummary(data),
|
|
66816
|
+
[]
|
|
66817
|
+
);
|
|
66754
66818
|
const fetchWorkspacesHealth = React141.useCallback(async () => {
|
|
66755
66819
|
if (isFetchingRef.current) return;
|
|
66756
66820
|
if (isShiftConfigLoading) {
|
|
@@ -66905,7 +66969,7 @@ var UptimeTimelineStrip = ({
|
|
|
66905
66969
|
shiftEnd,
|
|
66906
66970
|
timezone,
|
|
66907
66971
|
className = "",
|
|
66908
|
-
uptimePercentage =
|
|
66972
|
+
uptimePercentage = null,
|
|
66909
66973
|
downtimeMinutes = 0
|
|
66910
66974
|
}) => {
|
|
66911
66975
|
const segments = React141.useMemo(() => {
|
|
@@ -66970,7 +67034,7 @@ var UptimeTimelineStrip = ({
|
|
|
66970
67034
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full rounded-xl border border-dashed border-gray-200 bg-gray-50/50 p-6 text-center text-sm text-gray-600", children: "No uptime data available for this shift yet." });
|
|
66971
67035
|
}
|
|
66972
67036
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `relative w-full ${className}`, children: [
|
|
66973
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center mb-3 text-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-900 font-semibold", children: [
|
|
67037
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center mb-3 text-sm", children: typeof uptimePercentage === "number" ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-900 font-semibold", children: [
|
|
66974
67038
|
uptimePercentage.toFixed(1),
|
|
66975
67039
|
" % uptime ",
|
|
66976
67040
|
downtimeMinutes > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-600 font-normal", children: [
|
|
@@ -66978,7 +67042,7 @@ var UptimeTimelineStrip = ({
|
|
|
66978
67042
|
formatDowntimeLabel(downtimeMinutes),
|
|
66979
67043
|
")"
|
|
66980
67044
|
] })
|
|
66981
|
-
] }) }),
|
|
67045
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-600 font-medium", children: "Uptime data unavailable" }) }),
|
|
66982
67046
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex h-4 overflow-hidden rounded-lg border border-gray-200 shadow-sm bg-white", children: segments.map((segment, index) => {
|
|
66983
67047
|
const startDate = new Date(segment.startTimestamp);
|
|
66984
67048
|
const endDate = new Date(segment.endTimestamp);
|
|
@@ -67099,7 +67163,8 @@ var WorkspaceUptimeDetailModal = ({
|
|
|
67099
67163
|
const downtimeSegments = timeline?.downtimeSegments || [];
|
|
67100
67164
|
downtimeSegments.length;
|
|
67101
67165
|
const downtimeMinutes = timeline?.downtimeMinutes ?? 0;
|
|
67102
|
-
const
|
|
67166
|
+
const hasTimelineData = Boolean(timeline?.hasData);
|
|
67167
|
+
const uptimePercentage = hasTimelineData ? timeline?.uptimePercentage ?? workspace?.uptimePercentage ?? null : null;
|
|
67103
67168
|
const allInterruptionsSorted = React141.useMemo(
|
|
67104
67169
|
() => [...downtimeSegments].sort(
|
|
67105
67170
|
(a, b) => new Date(b.startTime).getTime() - new Date(a.startTime).getTime()
|
|
@@ -67221,7 +67286,7 @@ var WorkspaceUptimeDetailModal = ({
|
|
|
67221
67286
|
shiftEnd: timeline?.shiftEnd || (/* @__PURE__ */ new Date()).toISOString(),
|
|
67222
67287
|
timezone,
|
|
67223
67288
|
uptimePercentage,
|
|
67224
|
-
downtimeMinutes
|
|
67289
|
+
downtimeMinutes: hasTimelineData ? downtimeMinutes : 0
|
|
67225
67290
|
}
|
|
67226
67291
|
),
|
|
67227
67292
|
loading && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm text-gray-600 mt-4", children: [
|
|
@@ -67231,7 +67296,7 @@ var WorkspaceUptimeDetailModal = ({
|
|
|
67231
67296
|
] }),
|
|
67232
67297
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pt-4", children: [
|
|
67233
67298
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-semibold text-gray-900 uppercase tracking-wider mb-3", children: "Downtime Logs" }),
|
|
67234
|
-
downtimeSegments.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-gray-100 bg-gray-50/50 px-5 py-4 text-center", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-600", children: "No downtime events recorded for this shift." }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
67299
|
+
!hasTimelineData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-gray-100 bg-gray-50/50 px-5 py-4 text-center", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-600", children: "No uptime data available for this shift." }) }) : downtimeSegments.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-gray-100 bg-gray-50/50 px-5 py-4 text-center", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-600", children: "No downtime events recorded for this shift." }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
67235
67300
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
67236
67301
|
"div",
|
|
67237
67302
|
{
|
|
@@ -67356,6 +67421,7 @@ var WorkspaceHealthView = ({
|
|
|
67356
67421
|
}
|
|
67357
67422
|
};
|
|
67358
67423
|
const getUptimeColor = (percentage) => {
|
|
67424
|
+
if (percentage === null) return "text-gray-500 dark:text-gray-400";
|
|
67359
67425
|
if (percentage >= 97) return "text-green-600 dark:text-green-400";
|
|
67360
67426
|
if (percentage >= 90) return "text-yellow-600 dark:text-yellow-400";
|
|
67361
67427
|
return "text-red-600 dark:text-red-400";
|
|
@@ -67465,13 +67531,16 @@ var WorkspaceHealthView = ({
|
|
|
67465
67531
|
/* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-3", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-sm font-medium text-gray-500 dark:text-gray-400", children: "System Availability" }) }),
|
|
67466
67532
|
/* @__PURE__ */ jsxRuntime.jsxs(CardContent2, { children: [
|
|
67467
67533
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2", children: [
|
|
67468
|
-
/* @__PURE__ */ jsxRuntime.
|
|
67469
|
-
|
|
67470
|
-
"%"
|
|
67471
|
-
] }),
|
|
67472
|
-
summary.uptimePercentage >= 97 ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingUp, { className: "h-5 w-5 text-green-500" }) : summary.uptimePercentage >= 90 ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Activity, { className: "h-5 w-5 text-yellow-500" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingDown, { className: "h-5 w-5 text-red-500" })
|
|
67534
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx("text-3xl font-bold", getUptimeColor(summary.uptimePercentage)), children: summary.uptimePercentage === null ? "No data" : `${summary.uptimePercentage.toFixed(1)}%` }),
|
|
67535
|
+
summary.uptimePercentage === null ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Activity, { className: "h-5 w-5 text-gray-400" }) : summary.uptimePercentage >= 97 ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingUp, { className: "h-5 w-5 text-green-500" }) : summary.uptimePercentage >= 90 ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Activity, { className: "h-5 w-5 text-yellow-500" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingDown, { className: "h-5 w-5 text-red-500" })
|
|
67473
67536
|
] }),
|
|
67474
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: "Overall system uptime today" })
|
|
67537
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: summary.uptimePercentage === null ? "Uptime metrics unavailable for visible workspaces" : "Overall system uptime today" }),
|
|
67538
|
+
summary.workspacesWithoutUptimeData > 0 && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-amber-600 mt-1", children: [
|
|
67539
|
+
summary.workspacesWithoutUptimeData,
|
|
67540
|
+
" workspace",
|
|
67541
|
+
summary.workspacesWithoutUptimeData === 1 ? "" : "s",
|
|
67542
|
+
" missing uptime data"
|
|
67543
|
+
] })
|
|
67475
67544
|
] })
|
|
67476
67545
|
] }),
|
|
67477
67546
|
/* @__PURE__ */ jsxRuntime.jsxs(Card2, { className: "bg-white", children: [
|
|
@@ -69117,6 +69186,155 @@ Please ensure:
|
|
|
69117
69186
|
var AuthenticatedTicketsView = withAuth(React141__namespace.default.memo(TicketsView));
|
|
69118
69187
|
var TicketsView_default = TicketsView;
|
|
69119
69188
|
|
|
69189
|
+
// src/lib/utils/improvementDisplay.ts
|
|
69190
|
+
var LINE_WIDE_ISSUE_LABEL = "Line-wide issue";
|
|
69191
|
+
var UNKNOWN_LINE_LABEL = "Unknown line";
|
|
69192
|
+
var UNKNOWN_WORKSTATION_LABEL = "Unknown workstation";
|
|
69193
|
+
var UNASSIGNED_SUPERVISOR_LABEL = "Unassigned";
|
|
69194
|
+
var normalizeLabel = (value) => {
|
|
69195
|
+
if (typeof value !== "string") return void 0;
|
|
69196
|
+
const trimmed = value.trim();
|
|
69197
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
69198
|
+
};
|
|
69199
|
+
var toFiniteNumber = (value) => {
|
|
69200
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
69201
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
69202
|
+
const parsed = Number(value);
|
|
69203
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
69204
|
+
}
|
|
69205
|
+
return null;
|
|
69206
|
+
};
|
|
69207
|
+
var normalizeSupervisorNames = (supervisors) => {
|
|
69208
|
+
if (!supervisors) return [];
|
|
69209
|
+
if (typeof supervisors === "string") {
|
|
69210
|
+
const label = normalizeLabel(supervisors);
|
|
69211
|
+
return label ? [label] : [];
|
|
69212
|
+
}
|
|
69213
|
+
return supervisors.map((supervisor) => {
|
|
69214
|
+
if (typeof supervisor === "string") {
|
|
69215
|
+
return normalizeLabel(supervisor);
|
|
69216
|
+
}
|
|
69217
|
+
return normalizeLabel(supervisor?.displayName);
|
|
69218
|
+
}).filter((name) => !!name);
|
|
69219
|
+
};
|
|
69220
|
+
var formatImprovementTicketNumber = (issueNumber) => {
|
|
69221
|
+
if (typeof issueNumber !== "number" || !Number.isFinite(issueNumber)) {
|
|
69222
|
+
return null;
|
|
69223
|
+
}
|
|
69224
|
+
return `#${issueNumber}`;
|
|
69225
|
+
};
|
|
69226
|
+
var formatImprovementPieceGain = (pcsGain) => {
|
|
69227
|
+
const rounded = Math.round(pcsGain);
|
|
69228
|
+
return `+${rounded.toLocaleString("en-US")} pcs / day`;
|
|
69229
|
+
};
|
|
69230
|
+
var getPositiveImprovementGain = ({
|
|
69231
|
+
estimated_gain_pieces
|
|
69232
|
+
}) => {
|
|
69233
|
+
const issueGain = toFiniteNumber(estimated_gain_pieces);
|
|
69234
|
+
return {
|
|
69235
|
+
pcsGain: issueGain !== null && issueGain > 0 ? issueGain : null
|
|
69236
|
+
};
|
|
69237
|
+
};
|
|
69238
|
+
var getImprovementDisplayMetadata = ({
|
|
69239
|
+
location,
|
|
69240
|
+
line,
|
|
69241
|
+
workspaceId,
|
|
69242
|
+
supervisors
|
|
69243
|
+
}) => {
|
|
69244
|
+
const supervisorNames = normalizeSupervisorNames(supervisors);
|
|
69245
|
+
const workstationLabel = workspaceId ? normalizeLabel(location) ?? UNKNOWN_WORKSTATION_LABEL : LINE_WIDE_ISSUE_LABEL;
|
|
69246
|
+
const lineLabel = normalizeLabel(line) ?? UNKNOWN_LINE_LABEL;
|
|
69247
|
+
const supervisorLabel = supervisorNames.length > 0 ? supervisorNames.join(", ") : UNASSIGNED_SUPERVISOR_LABEL;
|
|
69248
|
+
return {
|
|
69249
|
+
workstationLabel,
|
|
69250
|
+
lineLabel,
|
|
69251
|
+
supervisorLabel,
|
|
69252
|
+
metadataLabel: [workstationLabel, lineLabel, supervisorLabel].join(" \xB7 ")
|
|
69253
|
+
};
|
|
69254
|
+
};
|
|
69255
|
+
var toFiniteNumber2 = (value) => {
|
|
69256
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
69257
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
69258
|
+
const parsed = Number(value);
|
|
69259
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
69260
|
+
}
|
|
69261
|
+
return null;
|
|
69262
|
+
};
|
|
69263
|
+
var getImprovementGainSummary = (recommendation) => {
|
|
69264
|
+
const { pcsGain } = getPositiveImprovementGain(recommendation);
|
|
69265
|
+
if (pcsGain !== null) {
|
|
69266
|
+
return {
|
|
69267
|
+
primary: formatImprovementPieceGain(pcsGain)
|
|
69268
|
+
};
|
|
69269
|
+
}
|
|
69270
|
+
return null;
|
|
69271
|
+
};
|
|
69272
|
+
var needsTargetReadjustment = (recommendation) => {
|
|
69273
|
+
if (recommendation.targets_need_reassignment === true) return true;
|
|
69274
|
+
const metrics2 = recommendation.metrics || {};
|
|
69275
|
+
return metrics2.targets_need_reassignment_current === true;
|
|
69276
|
+
};
|
|
69277
|
+
var compareImprovementRecommendationPriority = (left, right) => {
|
|
69278
|
+
const leftIndustrial = left.industrial_eng_bottleneck ? 1 : 0;
|
|
69279
|
+
const rightIndustrial = right.industrial_eng_bottleneck ? 1 : 0;
|
|
69280
|
+
if (leftIndustrial !== rightIndustrial) {
|
|
69281
|
+
return rightIndustrial - leftIndustrial;
|
|
69282
|
+
}
|
|
69283
|
+
const leftGain = toFiniteNumber2(left.estimated_gain_pieces);
|
|
69284
|
+
const rightGain = toFiniteNumber2(right.estimated_gain_pieces);
|
|
69285
|
+
if (leftGain !== rightGain) {
|
|
69286
|
+
if (leftGain === null) return 1;
|
|
69287
|
+
if (rightGain === null) return -1;
|
|
69288
|
+
return rightGain - leftGain;
|
|
69289
|
+
}
|
|
69290
|
+
const leftRatio = toFiniteNumber2(left.gain_to_target_ratio);
|
|
69291
|
+
const rightRatio = toFiniteNumber2(right.gain_to_target_ratio);
|
|
69292
|
+
if (leftRatio !== rightRatio) {
|
|
69293
|
+
if (leftRatio === null) return 1;
|
|
69294
|
+
if (rightRatio === null) return -1;
|
|
69295
|
+
return rightRatio - leftRatio;
|
|
69296
|
+
}
|
|
69297
|
+
return (left.issue_number || Number.MAX_SAFE_INTEGER) - (right.issue_number || Number.MAX_SAFE_INTEGER);
|
|
69298
|
+
};
|
|
69299
|
+
var ImprovementRecommendationSignals = ({
|
|
69300
|
+
recommendation,
|
|
69301
|
+
className
|
|
69302
|
+
}) => {
|
|
69303
|
+
const gainSummary = getImprovementGainSummary(recommendation);
|
|
69304
|
+
const showTargetReadjustment = needsTargetReadjustment(recommendation);
|
|
69305
|
+
if (!gainSummary && !showTargetReadjustment) {
|
|
69306
|
+
return null;
|
|
69307
|
+
}
|
|
69308
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: className || "flex flex-wrap items-center gap-x-4 gap-y-3", children: [
|
|
69309
|
+
gainSummary && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69310
|
+
"span",
|
|
69311
|
+
{
|
|
69312
|
+
"data-testid": "improvement-gain-chip",
|
|
69313
|
+
className: "inline-flex items-center gap-1.5 rounded-full border border-emerald-200 bg-emerald-50 px-3 py-1.5 text-sm font-medium text-emerald-700 shadow-sm",
|
|
69314
|
+
children: [
|
|
69315
|
+
/* @__PURE__ */ jsxRuntime.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "lucide lucide-trending-up w-4 h-4", children: [
|
|
69316
|
+
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "22 7 13.5 15.5 8.5 10.5 2 17" }),
|
|
69317
|
+
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "16 7 22 7 22 13" })
|
|
69318
|
+
] }),
|
|
69319
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", children: gainSummary.primary })
|
|
69320
|
+
]
|
|
69321
|
+
}
|
|
69322
|
+
),
|
|
69323
|
+
showTargetReadjustment && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69324
|
+
"span",
|
|
69325
|
+
{
|
|
69326
|
+
"data-testid": "targets-readjustment-chip",
|
|
69327
|
+
className: "inline-flex items-center gap-1.5 rounded-full border border-amber-200 bg-white px-3 py-1.5 text-sm font-medium text-amber-700 shadow-sm",
|
|
69328
|
+
children: [
|
|
69329
|
+
/* @__PURE__ */ jsxRuntime.jsx(outline.CalendarIcon, { className: "h-4 w-4 text-amber-600" }),
|
|
69330
|
+
"Targets need readjustment"
|
|
69331
|
+
]
|
|
69332
|
+
}
|
|
69333
|
+
)
|
|
69334
|
+
] });
|
|
69335
|
+
};
|
|
69336
|
+
var ImprovementRecommendationSignals_default = ImprovementRecommendationSignals;
|
|
69337
|
+
|
|
69120
69338
|
// src/lib/api/s3-clips-parser.ts
|
|
69121
69339
|
function parseS3Uri(s3Uri, sopCategories) {
|
|
69122
69340
|
const path = new URL(s3Uri).pathname;
|
|
@@ -69294,6 +69512,24 @@ var buildInitials = (name) => {
|
|
|
69294
69512
|
const second = parts.length > 1 ? parts[1]?.[0] || "" : "";
|
|
69295
69513
|
return `${first}${second}`.toUpperCase();
|
|
69296
69514
|
};
|
|
69515
|
+
var getQueryParam = (value) => {
|
|
69516
|
+
if (typeof value === "string") {
|
|
69517
|
+
const trimmed = value.trim();
|
|
69518
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
69519
|
+
}
|
|
69520
|
+
if (Array.isArray(value)) {
|
|
69521
|
+
const firstValue = value[0];
|
|
69522
|
+
return getQueryParam(firstValue);
|
|
69523
|
+
}
|
|
69524
|
+
return null;
|
|
69525
|
+
};
|
|
69526
|
+
var getQueryParamFromAsPath = (asPath, key) => {
|
|
69527
|
+
if (!asPath || !asPath.includes("?")) return null;
|
|
69528
|
+
const queryString = asPath.split("?")[1]?.split("#")[0];
|
|
69529
|
+
if (!queryString) return null;
|
|
69530
|
+
const value = new URLSearchParams(queryString).get(key);
|
|
69531
|
+
return getQueryParam(value ?? void 0);
|
|
69532
|
+
};
|
|
69297
69533
|
var ClipVideoCarousel = ({ clips, clipsService }) => {
|
|
69298
69534
|
const [currentIndex, setCurrentIndex] = React141.useState(0);
|
|
69299
69535
|
const [videos, setVideos] = React141.useState([]);
|
|
@@ -69615,6 +69851,7 @@ var EvidenceCarousel = ({ evidence, clipsService }) => {
|
|
|
69615
69851
|
};
|
|
69616
69852
|
var ImprovementCenterView = () => {
|
|
69617
69853
|
const { navigate } = useNavigation();
|
|
69854
|
+
const router$1 = router.useRouter();
|
|
69618
69855
|
const supabase = useSupabase();
|
|
69619
69856
|
const { user } = useAuth();
|
|
69620
69857
|
const dashboardConfig = useDashboardConfig();
|
|
@@ -69625,6 +69862,7 @@ var ImprovementCenterView = () => {
|
|
|
69625
69862
|
const [selectedShift, setSelectedShift] = React141.useState("all");
|
|
69626
69863
|
const [selectedWeeksRange, setSelectedWeeksRange] = React141.useState("all");
|
|
69627
69864
|
const [selectedMemberId, setSelectedMemberId] = React141.useState("all");
|
|
69865
|
+
const [selectedSortBy, setSelectedSortBy] = React141.useState("all");
|
|
69628
69866
|
const [recommendations, setRecommendations] = React141.useState([]);
|
|
69629
69867
|
const [isLoading, setIsLoading] = React141.useState(false);
|
|
69630
69868
|
const [loadError, setLoadError] = React141.useState(null);
|
|
@@ -69663,14 +69901,6 @@ var ImprovementCenterView = () => {
|
|
|
69663
69901
|
if (day % 10 === 3) return "rd";
|
|
69664
69902
|
return "th";
|
|
69665
69903
|
};
|
|
69666
|
-
const formatOpenedDate = (firstSeenAt) => {
|
|
69667
|
-
if (!firstSeenAt) return void 0;
|
|
69668
|
-
const zoned = toZonedDate(firstSeenAt);
|
|
69669
|
-
if (!zoned) return void 0;
|
|
69670
|
-
const day = zoned.getDate();
|
|
69671
|
-
const month = zoned.toLocaleString("en-US", { month: "short" });
|
|
69672
|
-
return `${day}${getDaySuffix(day)} ${month}`;
|
|
69673
|
-
};
|
|
69674
69904
|
const formatMonthDay = (date) => {
|
|
69675
69905
|
const month = date.toLocaleString("en-US", { month: "short" });
|
|
69676
69906
|
return `${month} ${date.getDate()}`;
|
|
@@ -69752,6 +69982,9 @@ var ImprovementCenterView = () => {
|
|
|
69752
69982
|
return map;
|
|
69753
69983
|
}, [companyLines, configuredLines]);
|
|
69754
69984
|
const companyId = user?.company_id || entityConfig.companyId;
|
|
69985
|
+
const focusIssueId = React141.useMemo(() => {
|
|
69986
|
+
return getQueryParam(router$1.query.focusIssueId) || getQueryParamFromAsPath(router$1.asPath, "focusIssueId");
|
|
69987
|
+
}, [router$1.asPath, router$1.query.focusIssueId]);
|
|
69755
69988
|
const clipsService = React141.useMemo(() => {
|
|
69756
69989
|
try {
|
|
69757
69990
|
return new S3ClipsSupabaseService(dashboardConfig);
|
|
@@ -69759,6 +69992,11 @@ var ImprovementCenterView = () => {
|
|
|
69759
69992
|
return null;
|
|
69760
69993
|
}
|
|
69761
69994
|
}, [dashboardConfig]);
|
|
69995
|
+
const { supervisorsByLineId } = useSupervisorsByLineIds(scopeLineIds, {
|
|
69996
|
+
enabled: !!companyId && scopeLineIds.length > 0,
|
|
69997
|
+
companyId,
|
|
69998
|
+
useBackend: true
|
|
69999
|
+
});
|
|
69762
70000
|
React141.useEffect(() => {
|
|
69763
70001
|
let cancelled = false;
|
|
69764
70002
|
const loadTeamMembers = async () => {
|
|
@@ -69870,8 +70108,17 @@ var ImprovementCenterView = () => {
|
|
|
69870
70108
|
const teamMembersById = React141.useMemo(() => {
|
|
69871
70109
|
return new Map(teamMembers.map((member) => [member.id, member]));
|
|
69872
70110
|
}, [teamMembers]);
|
|
70111
|
+
const getRecommendationDisplayMetadata = React141__namespace.default.useCallback((rec) => {
|
|
70112
|
+
const supervisors = rec.line_id ? supervisorsByLineId.get(rec.line_id) || [] : [];
|
|
70113
|
+
return getImprovementDisplayMetadata({
|
|
70114
|
+
location: rec.location,
|
|
70115
|
+
line: rec.line,
|
|
70116
|
+
workspaceId: rec.workspace_id,
|
|
70117
|
+
supervisors
|
|
70118
|
+
});
|
|
70119
|
+
}, [supervisorsByLineId]);
|
|
69873
70120
|
const filteredRecommendations = React141.useMemo(() => {
|
|
69874
|
-
|
|
70121
|
+
const sortedRecommendations = recommendations.filter((rec) => {
|
|
69875
70122
|
if (selectedLineId !== "all" && rec.line_id !== selectedLineId) return false;
|
|
69876
70123
|
if (selectedStatus === "resolved" && rec.ticket_status !== "solved") return false;
|
|
69877
70124
|
if (selectedStatus === "unresolved" && rec.ticket_status === "solved") return false;
|
|
@@ -69885,12 +70132,44 @@ var ImprovementCenterView = () => {
|
|
|
69885
70132
|
if (selectedMemberId !== "all" && !(rec.assigned_user_ids?.includes(selectedMemberId) || rec.assigned_to_user_id === selectedMemberId)) return false;
|
|
69886
70133
|
return true;
|
|
69887
70134
|
}).sort((a, b) => {
|
|
69888
|
-
|
|
69889
|
-
|
|
69890
|
-
|
|
69891
|
-
|
|
70135
|
+
if (selectedSortBy === "highest_to_lowest") {
|
|
70136
|
+
const gainA = toFiniteNumber2(a.estimated_gain_pieces) || 0;
|
|
70137
|
+
const gainB = toFiniteNumber2(b.estimated_gain_pieces) || 0;
|
|
70138
|
+
if (gainA !== gainB) {
|
|
70139
|
+
return gainB - gainA;
|
|
70140
|
+
}
|
|
70141
|
+
} else if (selectedSortBy === "lowest_to_highest") {
|
|
70142
|
+
const gainA = toFiniteNumber2(a.estimated_gain_pieces) || 0;
|
|
70143
|
+
const gainB = toFiniteNumber2(b.estimated_gain_pieces) || 0;
|
|
70144
|
+
if (gainA !== gainB) {
|
|
70145
|
+
return gainA - gainB;
|
|
70146
|
+
}
|
|
70147
|
+
}
|
|
70148
|
+
return compareImprovementRecommendationPriority(a, b);
|
|
69892
70149
|
});
|
|
69893
|
-
|
|
70150
|
+
if (!focusIssueId) {
|
|
70151
|
+
return sortedRecommendations;
|
|
70152
|
+
}
|
|
70153
|
+
const focusedIndex = sortedRecommendations.findIndex((rec) => rec.issue_id === focusIssueId);
|
|
70154
|
+
if (focusedIndex <= 0) {
|
|
70155
|
+
return sortedRecommendations;
|
|
70156
|
+
}
|
|
70157
|
+
const focusedItem = sortedRecommendations[focusedIndex];
|
|
70158
|
+
return [
|
|
70159
|
+
focusedItem,
|
|
70160
|
+
...sortedRecommendations.slice(0, focusedIndex),
|
|
70161
|
+
...sortedRecommendations.slice(focusedIndex + 1)
|
|
70162
|
+
];
|
|
70163
|
+
}, [
|
|
70164
|
+
focusIssueId,
|
|
70165
|
+
recommendations,
|
|
70166
|
+
selectedLineId,
|
|
70167
|
+
selectedMemberId,
|
|
70168
|
+
selectedShift,
|
|
70169
|
+
selectedStatus,
|
|
70170
|
+
selectedWeeksRange,
|
|
70171
|
+
selectedSortBy
|
|
70172
|
+
]);
|
|
69894
70173
|
const stats = React141.useMemo(() => {
|
|
69895
70174
|
const baseFiltered = recommendations.filter((rec) => {
|
|
69896
70175
|
if (selectedLineId !== "all" && rec.line_id !== selectedLineId) return false;
|
|
@@ -69919,7 +70198,8 @@ var ImprovementCenterView = () => {
|
|
|
69919
70198
|
status: selectedStatus,
|
|
69920
70199
|
shift: selectedShift,
|
|
69921
70200
|
weeks_range: selectedWeeksRange,
|
|
69922
|
-
member_id: selectedMemberId
|
|
70201
|
+
member_id: selectedMemberId,
|
|
70202
|
+
sort_by: selectedSortBy
|
|
69923
70203
|
}
|
|
69924
70204
|
});
|
|
69925
70205
|
setSelectedLineId("all");
|
|
@@ -69927,6 +70207,7 @@ var ImprovementCenterView = () => {
|
|
|
69927
70207
|
setSelectedShift("all");
|
|
69928
70208
|
setSelectedWeeksRange("all");
|
|
69929
70209
|
setSelectedMemberId("all");
|
|
70210
|
+
setSelectedSortBy("all");
|
|
69930
70211
|
};
|
|
69931
70212
|
const shiftOptions = React141.useMemo(() => {
|
|
69932
70213
|
const shifts = /* @__PURE__ */ new Set();
|
|
@@ -70006,6 +70287,14 @@ var ImprovementCenterView = () => {
|
|
|
70006
70287
|
});
|
|
70007
70288
|
setSelectedLineId(lineId);
|
|
70008
70289
|
};
|
|
70290
|
+
const handleSortByChange = (sortBy) => {
|
|
70291
|
+
trackCoreEvent("Improvement Center Filter Applied", {
|
|
70292
|
+
filter_type: "sort_by",
|
|
70293
|
+
filter_value: sortBy,
|
|
70294
|
+
previous_value: selectedSortBy
|
|
70295
|
+
});
|
|
70296
|
+
setSelectedSortBy(sortBy);
|
|
70297
|
+
};
|
|
70009
70298
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-screen bg-gray-50 flex flex-col", children: [
|
|
70010
70299
|
/* @__PURE__ */ jsxRuntime.jsx("header", { className: "sticky top-0 z-30 bg-white border-b border-gray-200 flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 sm:px-6 lg:px-8 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
70011
70300
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-4 min-w-[120px]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -70045,11 +70334,11 @@ var ImprovementCenterView = () => {
|
|
|
70045
70334
|
"button",
|
|
70046
70335
|
{
|
|
70047
70336
|
onClick: () => setIsFilterOpen(!isFilterOpen),
|
|
70048
|
-
className: `flex items-center gap-2 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all shadow-sm ${isFilterOpen || (selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedLineId !== "all") ? "bg-blue-50 border-blue-200 text-blue-700" : "bg-white border-gray-200 text-gray-700 hover:bg-gray-50"}`,
|
|
70337
|
+
className: `flex items-center gap-2 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all shadow-sm ${isFilterOpen || (selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedLineId !== "all" || selectedSortBy !== "all") ? "bg-blue-50 border-blue-200 text-blue-700" : "bg-white border-gray-200 text-gray-700 hover:bg-gray-50"}`,
|
|
70049
70338
|
children: [
|
|
70050
70339
|
/* @__PURE__ */ jsxRuntime.jsx(outline.FunnelIcon, { className: "w-4 h-4" }),
|
|
70051
70340
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Filters" }),
|
|
70052
|
-
(selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedLineId !== "all") && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center w-5 h-5 bg-blue-100 text-blue-700 text-xs rounded-full font-bold ml-1", children: [selectedShift, selectedWeeksRange, selectedMemberId, selectedLineId].filter((v) => v !== "all").length }),
|
|
70341
|
+
(selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedLineId !== "all" || selectedSortBy !== "all") && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center w-5 h-5 bg-blue-100 text-blue-700 text-xs rounded-full font-bold ml-1", children: [selectedShift, selectedWeeksRange, selectedMemberId, selectedLineId].filter((v) => v !== "all").length + (selectedSortBy !== "all" ? 1 : 0) }),
|
|
70053
70342
|
/* @__PURE__ */ jsxRuntime.jsx(outline.ChevronDownIcon, { className: `w-3 h-3 ml-1 transition-transform ${isFilterOpen ? "rotate-180" : ""}` })
|
|
70054
70343
|
]
|
|
70055
70344
|
}
|
|
@@ -70057,7 +70346,7 @@ var ImprovementCenterView = () => {
|
|
|
70057
70346
|
isFilterOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 top-full mt-2 w-72 bg-white rounded-xl shadow-xl border border-gray-100 p-4 z-50 animate-in fade-in zoom-in-95 duration-100", children: [
|
|
70058
70347
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-3", children: [
|
|
70059
70348
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Filter View" }),
|
|
70060
|
-
(selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedLineId !== "all") && /* @__PURE__ */ jsxRuntime.jsx(
|
|
70349
|
+
(selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedLineId !== "all" || selectedSortBy !== "all") && /* @__PURE__ */ jsxRuntime.jsx(
|
|
70061
70350
|
"button",
|
|
70062
70351
|
{
|
|
70063
70352
|
onClick: clearFilters,
|
|
@@ -70067,6 +70356,7 @@ var ImprovementCenterView = () => {
|
|
|
70067
70356
|
)
|
|
70068
70357
|
] }),
|
|
70069
70358
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: [
|
|
70359
|
+
{ value: selectedSortBy, onChange: handleSortByChange, options: [{ id: "all", label: "All" }, { id: "highest_to_lowest", label: "Highest to Lowest" }, { id: "lowest_to_highest", label: "Lowest to Highest" }], label: "Priority" },
|
|
70070
70360
|
{ value: selectedShift, onChange: handleShiftFilterChange, options: shiftOptions, label: "Shift" },
|
|
70071
70361
|
{ value: selectedWeeksRange, onChange: handleWeeksFilterChange, options: weekOptions.map((o) => o.id), labels: weekOptions, label: "Duration" },
|
|
70072
70362
|
{ value: selectedMemberId, onChange: handleMemberFilterChange, options: ["all", ...teamMembers.map((m) => m.id)], labels: teamMembers, label: "Member" },
|
|
@@ -70082,12 +70372,19 @@ var ImprovementCenterView = () => {
|
|
|
70082
70372
|
style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.75rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.2em 1.2em` },
|
|
70083
70373
|
children: filter2.options.map((opt) => {
|
|
70084
70374
|
const val = typeof opt === "string" ? opt : opt.id;
|
|
70085
|
-
let label
|
|
70086
|
-
if (
|
|
70087
|
-
|
|
70375
|
+
let label;
|
|
70376
|
+
if (val === "all") {
|
|
70377
|
+
label = filter2.label === "Priority" ? "All Priorities" : `All ${filter2.label}s`;
|
|
70378
|
+
} else if (typeof opt === "object" && opt !== null && typeof opt.label === "string" && opt.label.length > 0) {
|
|
70379
|
+
label = opt.label;
|
|
70380
|
+
} else if (filter2.labels) {
|
|
70381
|
+
const found = filter2.labels.find(
|
|
70382
|
+
(l) => (l.id || l.user_id || l) === val
|
|
70383
|
+
);
|
|
70088
70384
|
label = found ? found.label || found.name || found : val;
|
|
70385
|
+
} else {
|
|
70386
|
+
label = val;
|
|
70089
70387
|
}
|
|
70090
|
-
if (val === "all") label = `All ${filter2.label}s`;
|
|
70091
70388
|
return /* @__PURE__ */ jsxRuntime.jsx("option", { value: val, children: label }, val);
|
|
70092
70389
|
})
|
|
70093
70390
|
}
|
|
@@ -70100,23 +70397,25 @@ var ImprovementCenterView = () => {
|
|
|
70100
70397
|
filteredRecommendations.length > 0 ? filteredRecommendations.map((rec, index) => {
|
|
70101
70398
|
const weeksOpen = rec.weeks_open || 1;
|
|
70102
70399
|
const openLabel = weeksOpen <= 1 ? "Opened this week" : `Opened for ${weeksOpen} weeks`;
|
|
70103
|
-
formatOpenedDate(rec.first_seen_at);
|
|
70104
70400
|
const periodLabel = formatPeriodRange(rec.period_start, rec.period_end);
|
|
70105
70401
|
const description = stripPeriodFromDescription(rec.description, rec.period_start, rec.period_end);
|
|
70402
|
+
const ticketLabel = formatImprovementTicketNumber(rec.issue_number) || `#${index + 1}`;
|
|
70403
|
+
const displayMetadata = getRecommendationDisplayMetadata(rec);
|
|
70404
|
+
const hasSignalContent = Boolean(
|
|
70405
|
+
rec.resolution_instructions || rec.targets_need_reassignment || rec.estimated_gain_pieces !== void 0 || rec.metrics && Object.keys(rec.metrics).length > 0
|
|
70406
|
+
);
|
|
70106
70407
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
70107
70408
|
motion.div,
|
|
70108
70409
|
{
|
|
70109
70410
|
initial: { opacity: 0, y: 20 },
|
|
70110
70411
|
animate: { opacity: 1, y: 0 },
|
|
70111
70412
|
transition: { delay: index * 0.1 },
|
|
70413
|
+
"data-testid": `improvement-card-${rec.issue_id}`,
|
|
70112
70414
|
className: `bg-white rounded-xl shadow-sm border overflow-hidden ${rec.ticket_status === "solved" ? "border-green-200" : "border-gray-200"}`,
|
|
70113
70415
|
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-5 relative", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col lg:flex-row gap-5", children: [
|
|
70114
70416
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
70115
70417
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2 mb-3", children: [
|
|
70116
|
-
/* @__PURE__ */ jsxRuntime.
|
|
70117
|
-
"#",
|
|
70118
|
-
rec.issue_number ?? index + 1
|
|
70119
|
-
] }),
|
|
70418
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-sm font-semibold text-gray-600 bg-gray-100 border border-gray-200", children: ticketLabel }),
|
|
70120
70419
|
rec.ticket_status === "solved" ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-sm font-medium bg-emerald-50 text-emerald-700 border border-emerald-100", children: [
|
|
70121
70420
|
/* @__PURE__ */ jsxRuntime.jsx(outline.CheckCircleIcon, { className: "w-4 h-4" }),
|
|
70122
70421
|
"Resolved"
|
|
@@ -70145,32 +70444,44 @@ var ImprovementCenterView = () => {
|
|
|
70145
70444
|
] })
|
|
70146
70445
|
] }),
|
|
70147
70446
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-900 mb-2", children: rec.title }),
|
|
70148
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
70149
|
-
|
|
70150
|
-
|
|
70151
|
-
|
|
70152
|
-
|
|
70153
|
-
|
|
70154
|
-
|
|
70155
|
-
|
|
70156
|
-
|
|
70157
|
-
|
|
70158
|
-
|
|
70159
|
-
|
|
70160
|
-
|
|
70447
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
70448
|
+
"p",
|
|
70449
|
+
{
|
|
70450
|
+
className: "text-base text-gray-500 mb-3",
|
|
70451
|
+
title: displayMetadata.metadataLabel,
|
|
70452
|
+
children: [
|
|
70453
|
+
displayMetadata.workstationLabel,
|
|
70454
|
+
" \xB7 ",
|
|
70455
|
+
displayMetadata.lineLabel,
|
|
70456
|
+
" \xB7 ",
|
|
70457
|
+
displayMetadata.supervisorLabel,
|
|
70458
|
+
(rec.shift_label || rec.shift_id !== void 0) && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "uppercase tracking-wide text-sm ml-1", children: [
|
|
70459
|
+
"\xB7 ",
|
|
70460
|
+
rec.shift_label || `Shift ${rec.shift_id}`
|
|
70461
|
+
] }),
|
|
70462
|
+
periodLabel && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
70463
|
+
" \xB7 ",
|
|
70464
|
+
periodLabel
|
|
70465
|
+
] })
|
|
70466
|
+
]
|
|
70467
|
+
}
|
|
70468
|
+
),
|
|
70161
70469
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base text-gray-600 leading-relaxed", children: description }),
|
|
70162
|
-
|
|
70163
|
-
/* @__PURE__ */ jsxRuntime.jsxs("
|
|
70164
|
-
/* @__PURE__ */ jsxRuntime.
|
|
70165
|
-
|
|
70166
|
-
|
|
70167
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-0 bottom-full mb-2 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-150 z-50 pointer-events-none", children: [
|
|
70168
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-xl border border-gray-100 p-4 w-80", children: [
|
|
70169
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-500 uppercase tracking-wide mb-1.5", children: "How this ticket gets resolved" }),
|
|
70170
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base text-gray-700 leading-relaxed", children: rec.resolution_instructions })
|
|
70470
|
+
hasSignalContent && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 flex flex-wrap items-center gap-x-4 gap-y-3", children: [
|
|
70471
|
+
rec.resolution_instructions && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative group inline-flex", children: [
|
|
70472
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-sm font-medium bg-blue-50 text-blue-600 border border-blue-200 cursor-help transition-colors group-hover:bg-blue-100 shadow-sm", children: [
|
|
70473
|
+
/* @__PURE__ */ jsxRuntime.jsx(outline.EyeIcon, { className: "w-4 h-4" }),
|
|
70474
|
+
"Resolve"
|
|
70171
70475
|
] }),
|
|
70172
|
-
/* @__PURE__ */ jsxRuntime.
|
|
70173
|
-
|
|
70476
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-0 bottom-full mb-2 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-150 z-50 pointer-events-none", children: [
|
|
70477
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-xl border border-gray-100 p-4 w-80", children: [
|
|
70478
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-500 uppercase tracking-wide mb-1.5", children: "How this ticket gets resolved" }),
|
|
70479
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base text-gray-700 leading-relaxed", children: rec.resolution_instructions })
|
|
70480
|
+
] }),
|
|
70481
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-6 top-full w-0 h-0 border-l-[6px] border-r-[6px] border-t-[6px] border-transparent border-t-white", style: { filter: "drop-shadow(0 1px 1px rgba(0,0,0,0.05))" } })
|
|
70482
|
+
] })
|
|
70483
|
+
] }),
|
|
70484
|
+
/* @__PURE__ */ jsxRuntime.jsx(ImprovementRecommendationSignals_default, { recommendation: rec })
|
|
70174
70485
|
] })
|
|
70175
70486
|
] }),
|
|
70176
70487
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full lg:w-5/12 bg-gray-50 rounded-lg p-4 border border-gray-100 flex-shrink-0", children: Array.isArray(rec.evidence) && rec.evidence.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -70190,8 +70501,8 @@ var ImprovementCenterView = () => {
|
|
|
70190
70501
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center py-16 bg-white rounded-xl border border-gray-200 shadow-sm", children: [
|
|
70191
70502
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto flex items-center justify-center w-16 h-16 rounded-full bg-green-50 mb-4", children: /* @__PURE__ */ jsxRuntime.jsx(outline.CheckCircleIcon, { className: "w-8 h-8 text-green-500" }) }),
|
|
70192
70503
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-900", children: "No tickets found" }),
|
|
70193
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-gray-500 max-w-md mx-auto", children: selectedLineId !== "all" || selectedStatus !== "all" || selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" ? "Try adjusting your filters to see more results." : "All monitored long-term patterns were evaluated and remained within limits. This is a success state!" }),
|
|
70194
|
-
(selectedLineId !== "all" || selectedStatus !== "all" || selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all") && /* @__PURE__ */ jsxRuntime.jsx(
|
|
70504
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-gray-500 max-w-md mx-auto", children: selectedLineId !== "all" || selectedStatus !== "all" || selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedSortBy !== "all" ? "Try adjusting your filters to see more results." : "All monitored long-term patterns were evaluated and remained within limits. This is a success state!" }),
|
|
70505
|
+
(selectedLineId !== "all" || selectedStatus !== "all" || selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedSortBy !== "all") && /* @__PURE__ */ jsxRuntime.jsx(
|
|
70195
70506
|
"button",
|
|
70196
70507
|
{
|
|
70197
70508
|
onClick: clearFilters,
|
|
@@ -72265,7 +72576,7 @@ var EMPTY_OVERVIEW = {
|
|
|
72265
72576
|
},
|
|
72266
72577
|
summary: {
|
|
72267
72578
|
plant_efficiency: { current: null, previous: null, delta_pp: null },
|
|
72268
|
-
avg_idle_per_workstation: { current_seconds: null, previous_seconds: null, delta_seconds: null }
|
|
72579
|
+
avg_idle_per_workstation: { current_seconds: null, previous_seconds: null, delta_seconds: null, top_contributors: [] }
|
|
72269
72580
|
},
|
|
72270
72581
|
poorest_lines: { output: [], uptime: [] },
|
|
72271
72582
|
trend: { shift_mode: "all", points: [] },
|
|
@@ -72291,15 +72602,6 @@ var toNumber3 = (value) => {
|
|
|
72291
72602
|
return null;
|
|
72292
72603
|
};
|
|
72293
72604
|
var roundOne = (value) => Math.round(value * 10) / 10;
|
|
72294
|
-
var getLastSevenDayRange = (timezone) => {
|
|
72295
|
-
const todayKey = dateFnsTz.formatInTimeZone(/* @__PURE__ */ new Date(), timezone || "UTC", "yyyy-MM-dd");
|
|
72296
|
-
const endDate = dateFns.parseISO(`${todayKey}T00:00:00`);
|
|
72297
|
-
const startDate = dateFns.subDays(endDate, 6);
|
|
72298
|
-
return {
|
|
72299
|
-
startKey: dateFns.format(startDate, "yyyy-MM-dd"),
|
|
72300
|
-
endKey: dateFns.format(endDate, "yyyy-MM-dd")
|
|
72301
|
-
};
|
|
72302
|
-
};
|
|
72303
72605
|
var formatIdleDuration = (seconds) => {
|
|
72304
72606
|
if (seconds === null || seconds === void 0 || !Number.isFinite(seconds)) {
|
|
72305
72607
|
return "--";
|
|
@@ -72314,23 +72616,11 @@ var formatComparisonWindow = (dayCount) => {
|
|
|
72314
72616
|
if (!dayCount || !Number.isFinite(dayCount)) return "previous range";
|
|
72315
72617
|
return `previous ${dayCount} ${dayCount === 1 ? "day" : "days"}`;
|
|
72316
72618
|
};
|
|
72317
|
-
var shuffle = (items) => {
|
|
72318
|
-
const next = [...items];
|
|
72319
|
-
for (let i = next.length - 1; i > 0; i -= 1) {
|
|
72320
|
-
const swapIndex = Math.floor(Math.random() * (i + 1));
|
|
72321
|
-
[next[i], next[swapIndex]] = [next[swapIndex], next[i]];
|
|
72322
|
-
}
|
|
72323
|
-
return next;
|
|
72324
|
-
};
|
|
72325
72619
|
var buildImprovementMetric = (recommendation) => {
|
|
72620
|
+
const { pcsGain } = getPositiveImprovementGain(recommendation);
|
|
72326
72621
|
const metrics2 = recommendation.metrics || {};
|
|
72327
|
-
|
|
72328
|
-
|
|
72329
|
-
return `+${roundOne(efficiencyGain)}% Efficiency`;
|
|
72330
|
-
}
|
|
72331
|
-
const outputGain = toNumber3(metrics2.output_gain);
|
|
72332
|
-
if (outputGain !== null) {
|
|
72333
|
-
return `+${Math.round(outputGain)} Units`;
|
|
72622
|
+
if (pcsGain !== null) {
|
|
72623
|
+
return formatImprovementPieceGain(pcsGain);
|
|
72334
72624
|
}
|
|
72335
72625
|
const idleMinutes = toNumber3(metrics2.idle_minutes);
|
|
72336
72626
|
if (idleMinutes !== null) {
|
|
@@ -72342,14 +72632,6 @@ var buildImprovementMetric = (recommendation) => {
|
|
|
72342
72632
|
}
|
|
72343
72633
|
return "Review Issue";
|
|
72344
72634
|
};
|
|
72345
|
-
var buildImprovementImpact = (recommendation) => {
|
|
72346
|
-
if (recommendation.issue_severity !== void 0 && recommendation.issue_severity !== null) {
|
|
72347
|
-
if (recommendation.issue_severity >= 3) return "High";
|
|
72348
|
-
if (recommendation.issue_severity >= 2) return "Medium";
|
|
72349
|
-
return "Low";
|
|
72350
|
-
}
|
|
72351
|
-
return "Medium";
|
|
72352
|
-
};
|
|
72353
72635
|
var buildDeltaBadge = (delta, options) => {
|
|
72354
72636
|
if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
|
|
72355
72637
|
return {
|
|
@@ -72407,12 +72689,15 @@ var OverviewIdleBreakdownSkeleton = () => /* @__PURE__ */ jsxRuntime.jsxs("div",
|
|
|
72407
72689
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-slate-200 rounded w-20" })
|
|
72408
72690
|
] }, i)) })
|
|
72409
72691
|
] });
|
|
72410
|
-
var OverviewImprovementsSkeleton = () => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4 py-3", children: Array.from({ length: 3 }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-
|
|
72411
|
-
/* @__PURE__ */ jsxRuntime.
|
|
72412
|
-
|
|
72413
|
-
/* @__PURE__ */ jsxRuntime.
|
|
72414
|
-
|
|
72415
|
-
|
|
72692
|
+
var OverviewImprovementsSkeleton = () => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4 py-3", children: Array.from({ length: 3 }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-4", children: [
|
|
72693
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 flex-1 min-w-0 pr-4", children: [
|
|
72694
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionPulse, { className: "h-5 w-10 rounded-full flex-shrink-0" }),
|
|
72695
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-2 min-w-0", children: [
|
|
72696
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionPulse, { className: "h-3 w-40" }),
|
|
72697
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionPulse, { className: "h-2.5 w-24" })
|
|
72698
|
+
] })
|
|
72699
|
+
] }),
|
|
72700
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end flex-shrink-0 ml-4", children: /* @__PURE__ */ jsxRuntime.jsx(SectionPulse, { className: "h-6 w-20 rounded-full" }) })
|
|
72416
72701
|
] }, index)) });
|
|
72417
72702
|
var PlantHeadView = () => {
|
|
72418
72703
|
const supabase = useSupabase();
|
|
@@ -72422,7 +72707,7 @@ var PlantHeadView = () => {
|
|
|
72422
72707
|
const { accessibleLineIds } = useUserLineAccess();
|
|
72423
72708
|
const mobileMenuContext = useMobileMenu();
|
|
72424
72709
|
useHideMobileHeader(!!mobileMenuContext);
|
|
72425
|
-
const [dateRange, setDateRange] = React141__namespace.default.useState(() =>
|
|
72710
|
+
const [dateRange, setDateRange] = React141__namespace.default.useState(() => getCurrentWeekToDateRange(appTimezone));
|
|
72426
72711
|
const [trendMode, setTrendMode] = React141__namespace.default.useState("all");
|
|
72427
72712
|
const [poorestLineMode, setPoorestLineMode] = React141__namespace.default.useState("output");
|
|
72428
72713
|
const [overview, setOverview] = React141__namespace.default.useState(EMPTY_OVERVIEW);
|
|
@@ -72436,9 +72721,12 @@ var PlantHeadView = () => {
|
|
|
72436
72721
|
const [improvements, setImprovements] = React141__namespace.default.useState([]);
|
|
72437
72722
|
const [isImprovementsLoading, setIsImprovementsLoading] = React141__namespace.default.useState(false);
|
|
72438
72723
|
const [isFilterOpen, setIsFilterOpen] = React141__namespace.default.useState(false);
|
|
72724
|
+
const [isIdleContributorsOpen, setIsIdleContributorsOpen] = React141__namespace.default.useState(false);
|
|
72725
|
+
const [isIdleContributorsPinned, setIsIdleContributorsPinned] = React141__namespace.default.useState(false);
|
|
72439
72726
|
const filterRef = React141__namespace.default.useRef(null);
|
|
72440
72727
|
const filterButtonRef = React141__namespace.default.useRef(null);
|
|
72441
72728
|
const mobileFilterButtonRef = React141__namespace.default.useRef(null);
|
|
72729
|
+
const idleContributorsRef = React141__namespace.default.useRef(null);
|
|
72442
72730
|
React141__namespace.default.useEffect(() => {
|
|
72443
72731
|
trackCorePageView("Operations Overview");
|
|
72444
72732
|
}, []);
|
|
@@ -72479,11 +72767,11 @@ var PlantHeadView = () => {
|
|
|
72479
72767
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
72480
72768
|
};
|
|
72481
72769
|
}, []);
|
|
72482
|
-
const
|
|
72770
|
+
const initializedTimezoneRef = React141__namespace.default.useRef(appTimezone);
|
|
72483
72771
|
React141__namespace.default.useEffect(() => {
|
|
72484
|
-
if (
|
|
72485
|
-
setDateRange(
|
|
72486
|
-
|
|
72772
|
+
if (initializedTimezoneRef.current === appTimezone) return;
|
|
72773
|
+
setDateRange(getCurrentWeekToDateRange(appTimezone));
|
|
72774
|
+
initializedTimezoneRef.current = appTimezone;
|
|
72487
72775
|
}, [appTimezone]);
|
|
72488
72776
|
const companyId = entityConfig.companyId;
|
|
72489
72777
|
const scopedLineIds = React141__namespace.default.useMemo(
|
|
@@ -72494,6 +72782,10 @@ var PlantHeadView = () => {
|
|
|
72494
72782
|
() => scopedLineIds.slice().sort().join(","),
|
|
72495
72783
|
[scopedLineIds]
|
|
72496
72784
|
);
|
|
72785
|
+
React141__namespace.default.useEffect(() => {
|
|
72786
|
+
setIsIdleContributorsOpen(false);
|
|
72787
|
+
setIsIdleContributorsPinned(false);
|
|
72788
|
+
}, [companyId, dateRange.endKey, dateRange.startKey, lineIdsKey, trendMode]);
|
|
72497
72789
|
const { supervisorsByLineId } = useSupervisorsByLineIds(scopedLineIds, {
|
|
72498
72790
|
enabled: !!companyId && scopedLineIds.length > 0,
|
|
72499
72791
|
companyId,
|
|
@@ -72691,11 +72983,16 @@ var PlantHeadView = () => {
|
|
|
72691
72983
|
const scopedRecommendations = (response.recommendations || []).filter((recommendation) => {
|
|
72692
72984
|
return !recommendation.line_id || allowedLineIds.has(recommendation.line_id);
|
|
72693
72985
|
});
|
|
72694
|
-
const nextImprovements =
|
|
72695
|
-
id: recommendation.id,
|
|
72986
|
+
const nextImprovements = [...scopedRecommendations].sort(compareImprovementRecommendationPriority).slice(0, 3).map((recommendation) => ({
|
|
72987
|
+
id: recommendation.issue_id || recommendation.id,
|
|
72988
|
+
issueId: recommendation.issue_id || recommendation.id,
|
|
72989
|
+
issueNumber: recommendation.issue_number,
|
|
72696
72990
|
title: recommendation.title?.trim() || "Untitled issue",
|
|
72697
|
-
|
|
72698
|
-
|
|
72991
|
+
metric: buildImprovementMetric(recommendation),
|
|
72992
|
+
location: recommendation.location,
|
|
72993
|
+
line: recommendation.line,
|
|
72994
|
+
lineId: recommendation.line_id,
|
|
72995
|
+
workspaceId: recommendation.workspace_id
|
|
72699
72996
|
}));
|
|
72700
72997
|
setImprovements(nextImprovements);
|
|
72701
72998
|
};
|
|
@@ -72741,7 +73038,99 @@ var PlantHeadView = () => {
|
|
|
72741
73038
|
comparisonLabel
|
|
72742
73039
|
});
|
|
72743
73040
|
}, [comparisonLabel, overview.summary?.avg_idle_per_workstation?.delta_seconds]);
|
|
73041
|
+
const canInspectIdleContributors = React141__namespace.default.useMemo(() => {
|
|
73042
|
+
return !isSnapshotLoading && overview.summary?.avg_idle_per_workstation?.current_seconds !== null && overview.summary?.avg_idle_per_workstation?.current_seconds !== void 0;
|
|
73043
|
+
}, [isSnapshotLoading, overview.summary?.avg_idle_per_workstation?.current_seconds]);
|
|
73044
|
+
const idleTopContributors = React141__namespace.default.useMemo(() => {
|
|
73045
|
+
return (overview.summary?.avg_idle_per_workstation?.top_contributors || []).map((item) => ({
|
|
73046
|
+
workspaceId: item.workspace_id || "",
|
|
73047
|
+
workspaceName: item.workspace_name?.trim() || item.workspace_id || "Unknown",
|
|
73048
|
+
lineId: item.line_id || "",
|
|
73049
|
+
lineName: item.line_name?.trim() || "Unknown Line",
|
|
73050
|
+
avgIdleSeconds: toNumber3(item.avg_idle_seconds)
|
|
73051
|
+
})).slice(0, 5);
|
|
73052
|
+
}, [overview.summary?.avg_idle_per_workstation?.top_contributors]);
|
|
73053
|
+
const showIdleContributorLineNames = React141__namespace.default.useMemo(() => {
|
|
73054
|
+
return (overview.scope?.line_count ?? 0) > 1;
|
|
73055
|
+
}, [overview.scope?.line_count]);
|
|
73056
|
+
const closeIdleContributors = React141__namespace.default.useCallback(() => {
|
|
73057
|
+
setIsIdleContributorsOpen(false);
|
|
73058
|
+
setIsIdleContributorsPinned(false);
|
|
73059
|
+
}, []);
|
|
73060
|
+
const handleIdleContributorsToggle = React141__namespace.default.useCallback(() => {
|
|
73061
|
+
if (!canInspectIdleContributors) return;
|
|
73062
|
+
setIsIdleContributorsPinned((prev) => {
|
|
73063
|
+
const next = !prev;
|
|
73064
|
+
setIsIdleContributorsOpen(next);
|
|
73065
|
+
return next;
|
|
73066
|
+
});
|
|
73067
|
+
}, [canInspectIdleContributors]);
|
|
73068
|
+
const handleIdleContributorsKeyDown = React141__namespace.default.useCallback((event) => {
|
|
73069
|
+
if (!canInspectIdleContributors) return;
|
|
73070
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
73071
|
+
event.preventDefault();
|
|
73072
|
+
handleIdleContributorsToggle();
|
|
73073
|
+
return;
|
|
73074
|
+
}
|
|
73075
|
+
if (event.key === "Escape") {
|
|
73076
|
+
event.preventDefault();
|
|
73077
|
+
closeIdleContributors();
|
|
73078
|
+
}
|
|
73079
|
+
}, [canInspectIdleContributors, closeIdleContributors, handleIdleContributorsToggle]);
|
|
73080
|
+
React141__namespace.default.useEffect(() => {
|
|
73081
|
+
if (!isIdleContributorsOpen) return void 0;
|
|
73082
|
+
const handleClickOutside = (event) => {
|
|
73083
|
+
if (!isIdleContributorsPinned) return;
|
|
73084
|
+
if (idleContributorsRef.current && !idleContributorsRef.current.contains(event.target)) {
|
|
73085
|
+
closeIdleContributors();
|
|
73086
|
+
}
|
|
73087
|
+
};
|
|
73088
|
+
const handleEscape = (event) => {
|
|
73089
|
+
if (event.key === "Escape") {
|
|
73090
|
+
closeIdleContributors();
|
|
73091
|
+
}
|
|
73092
|
+
};
|
|
73093
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
73094
|
+
document.addEventListener("touchstart", handleClickOutside);
|
|
73095
|
+
document.addEventListener("keydown", handleEscape);
|
|
73096
|
+
return () => {
|
|
73097
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
73098
|
+
document.removeEventListener("touchstart", handleClickOutside);
|
|
73099
|
+
document.removeEventListener("keydown", handleEscape);
|
|
73100
|
+
};
|
|
73101
|
+
}, [closeIdleContributors, isIdleContributorsOpen, isIdleContributorsPinned]);
|
|
73102
|
+
const currentWeekRange = React141__namespace.default.useMemo(
|
|
73103
|
+
() => getCurrentWeekToDateRange(appTimezone),
|
|
73104
|
+
[appTimezone]
|
|
73105
|
+
);
|
|
73106
|
+
const isCurrentWeekToDateRange = dateRange.startKey === currentWeekRange.startKey && dateRange.endKey === currentWeekRange.endKey;
|
|
72744
73107
|
const trendData = React141__namespace.default.useMemo(() => {
|
|
73108
|
+
const pointsByDate = new Map(
|
|
73109
|
+
(overview.trend?.points || []).flatMap((point) => {
|
|
73110
|
+
if (!point.date) return [];
|
|
73111
|
+
const pointDate = parseDateKeyToDate(point.date);
|
|
73112
|
+
return [[point.date, {
|
|
73113
|
+
name: dateFns.format(pointDate, "MMM d"),
|
|
73114
|
+
dayOfWeek: dateFns.format(pointDate, "EEEE"),
|
|
73115
|
+
efficiency: (() => {
|
|
73116
|
+
const value = toNumber3(point.avg_efficiency);
|
|
73117
|
+
return value === null ? void 0 : value;
|
|
73118
|
+
})()
|
|
73119
|
+
}]];
|
|
73120
|
+
})
|
|
73121
|
+
);
|
|
73122
|
+
if (isCurrentWeekToDateRange) {
|
|
73123
|
+
const weekStart = parseDateKeyToDate(currentWeekRange.startKey);
|
|
73124
|
+
return Array.from({ length: 7 }, (_, index) => {
|
|
73125
|
+
const date = dateFns.addDays(weekStart, index);
|
|
73126
|
+
const dateKey = dateFns.format(date, "yyyy-MM-dd");
|
|
73127
|
+
return pointsByDate.get(dateKey) || {
|
|
73128
|
+
name: dateFns.format(date, "MMM d"),
|
|
73129
|
+
dayOfWeek: dateFns.format(date, "EEEE"),
|
|
73130
|
+
efficiency: void 0
|
|
73131
|
+
};
|
|
73132
|
+
});
|
|
73133
|
+
}
|
|
72745
73134
|
return (overview.trend?.points || []).map((point) => {
|
|
72746
73135
|
const pointDate = point.date ? parseDateKeyToDate(point.date) : null;
|
|
72747
73136
|
return {
|
|
@@ -72753,7 +73142,7 @@ var PlantHeadView = () => {
|
|
|
72753
73142
|
})()
|
|
72754
73143
|
};
|
|
72755
73144
|
});
|
|
72756
|
-
}, [overview.trend?.points]);
|
|
73145
|
+
}, [currentWeekRange.startKey, isCurrentWeekToDateRange, overview.trend?.points]);
|
|
72757
73146
|
const trendPlayKey = React141__namespace.default.useMemo(() => {
|
|
72758
73147
|
return `${trendViewOpenNonce}:${trendFetchNonce}`;
|
|
72759
73148
|
}, [trendFetchNonce, trendViewOpenNonce]);
|
|
@@ -72800,6 +73189,33 @@ var PlantHeadView = () => {
|
|
|
72800
73189
|
if (!dayOfWeek || typeof label !== "string") return label;
|
|
72801
73190
|
return `${label} (${dayOfWeek})`;
|
|
72802
73191
|
}, []);
|
|
73192
|
+
const displayImprovements = React141__namespace.default.useMemo(() => {
|
|
73193
|
+
return improvements.map((item) => {
|
|
73194
|
+
const supervisors = item.lineId ? supervisorsByLineId.get(item.lineId) || [] : [];
|
|
73195
|
+
return {
|
|
73196
|
+
...item,
|
|
73197
|
+
ticketLabel: formatImprovementTicketNumber(item.issueNumber),
|
|
73198
|
+
...getImprovementDisplayMetadata({
|
|
73199
|
+
location: item.location,
|
|
73200
|
+
line: item.line,
|
|
73201
|
+
workspaceId: item.workspaceId,
|
|
73202
|
+
supervisors
|
|
73203
|
+
})
|
|
73204
|
+
};
|
|
73205
|
+
});
|
|
73206
|
+
}, [improvements, supervisorsByLineId]);
|
|
73207
|
+
const mobileSubtitle = React141__namespace.default.useMemo(() => {
|
|
73208
|
+
if (isCurrentWeekToDateRange) {
|
|
73209
|
+
return `Week of ${dateFns.format(parseDateKeyToDate(dateRange.startKey), "do MMM")}`;
|
|
73210
|
+
}
|
|
73211
|
+
return `${dateFns.format(parseDateKeyToDate(dateRange.startKey), "do MMM")} - ${dateFns.format(parseDateKeyToDate(dateRange.endKey), "do MMM, yyyy")}`;
|
|
73212
|
+
}, [dateRange.endKey, dateRange.startKey, isCurrentWeekToDateRange]);
|
|
73213
|
+
const desktopSubtitle = React141__namespace.default.useMemo(() => {
|
|
73214
|
+
if (isCurrentWeekToDateRange) {
|
|
73215
|
+
return `Week of ${dateFns.format(parseDateKeyToDate(dateRange.startKey), "do MMMM, yyyy")}`;
|
|
73216
|
+
}
|
|
73217
|
+
return `${dateFns.format(parseDateKeyToDate(dateRange.startKey), "do MMMM, yyyy")} - ${dateFns.format(parseDateKeyToDate(dateRange.endKey), "do MMMM, yyyy")}`;
|
|
73218
|
+
}, [dateRange.endKey, dateRange.startKey, isCurrentWeekToDateRange]);
|
|
72803
73219
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-h-screen bg-slate-50 w-full font-sans", children: [
|
|
72804
73220
|
/* @__PURE__ */ jsxRuntime.jsx("header", { className: "sticky top-0 z-10 bg-white border-b flex-shrink-0 shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 sm:px-4 md:px-6 py-2 sm:py-3 relative", children: [
|
|
72805
73221
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sm:hidden", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
|
|
@@ -72812,11 +73228,7 @@ var PlantHeadView = () => {
|
|
|
72812
73228
|
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 flex-shrink-0" }),
|
|
72813
73229
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center", children: [
|
|
72814
73230
|
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold text-gray-900 text-center px-1 truncate max-w-[200px]", children: "Operations Overview" }),
|
|
72815
|
-
/* @__PURE__ */ jsxRuntime.
|
|
72816
|
-
dateFns.format(parseDateKeyToDate(dateRange.startKey), "do MMM"),
|
|
72817
|
-
" - ",
|
|
72818
|
-
dateFns.format(parseDateKeyToDate(dateRange.endKey), "do MMM, yyyy")
|
|
72819
|
-
] })
|
|
73231
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium text-slate-500 text-center mt-0.5", children: mobileSubtitle })
|
|
72820
73232
|
] }),
|
|
72821
73233
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-shrink-0 flex items-center gap-1.5", children: [
|
|
72822
73234
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -72848,11 +73260,7 @@ var PlantHeadView = () => {
|
|
|
72848
73260
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center relative min-h-[56px]", children: [
|
|
72849
73261
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-1/2 -translate-x-1/2 flex flex-col items-center pointer-events-none", children: [
|
|
72850
73262
|
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl md:text-3xl lg:text-4xl font-semibold text-gray-900 tracking-tight text-center pointer-events-auto leading-tight mb-0.5", children: "Operations Overview" }),
|
|
72851
|
-
/* @__PURE__ */ jsxRuntime.
|
|
72852
|
-
dateFns.format(parseDateKeyToDate(dateRange.startKey), "do MMMM, yyyy"),
|
|
72853
|
-
" - ",
|
|
72854
|
-
dateFns.format(parseDateKeyToDate(dateRange.endKey), "do MMMM, yyyy")
|
|
72855
|
-
] })
|
|
73263
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-sm font-medium text-slate-500 text-center pointer-events-auto", children: desktopSubtitle })
|
|
72856
73264
|
] }),
|
|
72857
73265
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 flex items-center gap-3", children: [
|
|
72858
73266
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -72940,16 +73348,92 @@ var PlantHeadView = () => {
|
|
|
72940
73348
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
72941
73349
|
"div",
|
|
72942
73350
|
{
|
|
72943
|
-
|
|
73351
|
+
ref: idleContributorsRef,
|
|
73352
|
+
"data-testid": "idle-kpi-card-region",
|
|
73353
|
+
className: "relative",
|
|
73354
|
+
onMouseEnter: () => {
|
|
73355
|
+
if (canInspectIdleContributors) {
|
|
73356
|
+
setIsIdleContributorsOpen(true);
|
|
73357
|
+
}
|
|
73358
|
+
},
|
|
73359
|
+
onMouseLeave: () => {
|
|
73360
|
+
if (!isIdleContributorsPinned) {
|
|
73361
|
+
setIsIdleContributorsOpen(false);
|
|
73362
|
+
}
|
|
73363
|
+
},
|
|
73364
|
+
onFocus: () => {
|
|
73365
|
+
if (canInspectIdleContributors) {
|
|
73366
|
+
setIsIdleContributorsOpen(true);
|
|
73367
|
+
}
|
|
73368
|
+
},
|
|
73369
|
+
onBlur: (event) => {
|
|
73370
|
+
if (isIdleContributorsPinned) return;
|
|
73371
|
+
const nextTarget = event.relatedTarget;
|
|
73372
|
+
if (nextTarget && idleContributorsRef.current?.contains(nextTarget)) return;
|
|
73373
|
+
setIsIdleContributorsOpen(false);
|
|
73374
|
+
},
|
|
72944
73375
|
children: [
|
|
72945
|
-
/* @__PURE__ */ jsxRuntime.
|
|
72946
|
-
|
|
72947
|
-
|
|
72948
|
-
|
|
72949
|
-
|
|
72950
|
-
|
|
72951
|
-
|
|
72952
|
-
|
|
73376
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
73377
|
+
"div",
|
|
73378
|
+
{
|
|
73379
|
+
"data-testid": "idle-kpi-card",
|
|
73380
|
+
role: canInspectIdleContributors ? "button" : void 0,
|
|
73381
|
+
tabIndex: canInspectIdleContributors ? 0 : -1,
|
|
73382
|
+
"aria-controls": canInspectIdleContributors ? "idle-kpi-popover" : void 0,
|
|
73383
|
+
"aria-expanded": canInspectIdleContributors ? isIdleContributorsOpen : void 0,
|
|
73384
|
+
className: `bg-white rounded-xl border p-4 md:p-5 flex flex-col justify-center min-h-[100px] text-left transition-all ${canInspectIdleContributors ? "cursor-pointer hover:shadow-md focus:outline-none focus:ring-2 focus:ring-indigo-200" : ""} ${isIdleContributorsOpen ? "shadow-md border-indigo-100" : "shadow-sm border-slate-100"}`,
|
|
73385
|
+
onClick: handleIdleContributorsToggle,
|
|
73386
|
+
onKeyDown: handleIdleContributorsKeyDown,
|
|
73387
|
+
children: [
|
|
73388
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-1", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Idle Time per Workstation" }) }),
|
|
73389
|
+
isSnapshotLoading ? /* @__PURE__ */ jsxRuntime.jsx(OverviewMetricCardSkeleton, {}) : overview.summary?.avg_idle_per_workstation?.current_seconds !== null && overview.summary?.avg_idle_per_workstation?.current_seconds !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2 sm:gap-3 mt-1", children: [
|
|
73390
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-2xl sm:text-3xl font-bold text-slate-800 tracking-tight", children: formatIdleDuration(overview.summary.avg_idle_per_workstation.current_seconds) }),
|
|
73391
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${idleBadge.className}`, children: [
|
|
73392
|
+
idleBadge.icon === "up" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : idleBadge.icon === "down" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
|
|
73393
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-sm font-medium", children: idleBadge.text })
|
|
73394
|
+
] })
|
|
73395
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No idle time data available" })
|
|
73396
|
+
]
|
|
73397
|
+
}
|
|
73398
|
+
),
|
|
73399
|
+
canInspectIdleContributors && isIdleContributorsOpen ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
73400
|
+
"div",
|
|
73401
|
+
{
|
|
73402
|
+
id: "idle-kpi-popover",
|
|
73403
|
+
"data-testid": "idle-kpi-popover",
|
|
73404
|
+
className: "absolute left-0 right-0 top-full z-20 mt-2 bg-white p-4 border border-gray-100 shadow-xl rounded-xl sm:left-auto sm:right-0 sm:w-[320px] min-w-[280px]",
|
|
73405
|
+
children: [
|
|
73406
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 pb-3 mb-3 border-b border-slate-100", children: [
|
|
73407
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2.5 h-2.5 rounded-full flex-shrink-0 bg-red-500" }),
|
|
73408
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-slate-800 text-[15px]", children: "Idle Time per Workstation" })
|
|
73409
|
+
] }),
|
|
73410
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
73411
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] font-bold uppercase tracking-wider text-slate-400 mb-3", children: "TOP CONTRIBUTORS" }),
|
|
73412
|
+
idleTopContributors.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2.5", children: idleTopContributors.map((contributor, index) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
73413
|
+
"div",
|
|
73414
|
+
{
|
|
73415
|
+
className: "flex items-start justify-between gap-3",
|
|
73416
|
+
children: [
|
|
73417
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
73418
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
73419
|
+
"div",
|
|
73420
|
+
{
|
|
73421
|
+
className: "text-slate-600 text-[13px] truncate",
|
|
73422
|
+
title: contributor.workspaceName,
|
|
73423
|
+
children: contributor.workspaceName
|
|
73424
|
+
}
|
|
73425
|
+
),
|
|
73426
|
+
showIdleContributorLineNames && contributor.lineName ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[11px] font-medium text-slate-400 truncate", title: contributor.lineName, children: contributor.lineName }) : null
|
|
73427
|
+
] }),
|
|
73428
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-slate-500 text-[13px] text-right whitespace-nowrap", children: formatIdleDuration(contributor.avgIdleSeconds) })
|
|
73429
|
+
]
|
|
73430
|
+
},
|
|
73431
|
+
`${contributor.workspaceId || contributor.workspaceName}-${index}`
|
|
73432
|
+
)) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-dashed border-slate-200 bg-slate-50 px-3 py-2 text-xs text-slate-500", children: "No workstation idle averages available for this range." })
|
|
73433
|
+
] })
|
|
73434
|
+
]
|
|
73435
|
+
}
|
|
73436
|
+
) : null
|
|
72953
73437
|
]
|
|
72954
73438
|
}
|
|
72955
73439
|
)
|
|
@@ -73049,7 +73533,7 @@ var PlantHeadView = () => {
|
|
|
73049
73533
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-5 py-4 flex-none flex justify-between items-center border-b border-slate-50/50 relative", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Idle Time Breakdown" }) }),
|
|
73050
73534
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 p-4 pt-2 relative", children: isIdleReasonBreakdownLoading ? /* @__PURE__ */ jsxRuntime.jsx(OverviewIdleBreakdownSkeleton, {}) : showIdleModuleNotEnabledState ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full flex items-center justify-center rounded-xl border border-dashed border-slate-200 bg-slate-50/80 px-6 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
73051
73535
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-slate-700", children: "Module not enabled" }),
|
|
73052
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-slate-500", children: "Enable idle-time
|
|
73536
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-slate-500", children: "Enable idle-time classification on at least one line to view this breakdown." })
|
|
73053
73537
|
] }) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
73054
73538
|
IdleTimeReasonChart,
|
|
73055
73539
|
{
|
|
@@ -73103,24 +73587,48 @@ var PlantHeadView = () => {
|
|
|
73103
73587
|
}
|
|
73104
73588
|
)
|
|
73105
73589
|
] }),
|
|
73106
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 p-0 flex flex-col px-5 py-2 justify-start overflow-auto", children: isImprovementsLoading ? /* @__PURE__ */ jsxRuntime.jsx(OverviewImprovementsSkeleton, {}) :
|
|
73590
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 p-0 flex flex-col px-5 py-2 justify-start overflow-auto", children: isImprovementsLoading ? /* @__PURE__ */ jsxRuntime.jsx(OverviewImprovementsSkeleton, {}) : displayImprovements.length > 0 ? displayImprovements.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
73107
73591
|
"div",
|
|
73108
73592
|
{
|
|
73593
|
+
"data-testid": `plant-head-improvement-${item.issueId}`,
|
|
73109
73594
|
onClick: () => {
|
|
73110
|
-
trackCoreEvent("Operations Overview Improvement Clicked", {
|
|
73111
|
-
|
|
73595
|
+
trackCoreEvent("Operations Overview Improvement Clicked", {
|
|
73596
|
+
issue_id: item.issueId,
|
|
73597
|
+
issue_number: item.issueNumber,
|
|
73598
|
+
title: item.title
|
|
73599
|
+
});
|
|
73600
|
+
const params = new URLSearchParams({
|
|
73601
|
+
focusIssueId: item.issueId
|
|
73602
|
+
});
|
|
73603
|
+
navigate(`/improvement-center?${params.toString()}`);
|
|
73112
73604
|
},
|
|
73113
73605
|
className: "flex items-center justify-between py-3 border-b border-slate-50 last:border-0 group cursor-pointer",
|
|
73114
|
-
children:
|
|
73115
|
-
/* @__PURE__ */ jsxRuntime.
|
|
73116
|
-
|
|
73117
|
-
/* @__PURE__ */ jsxRuntime.
|
|
73118
|
-
|
|
73119
|
-
|
|
73120
|
-
|
|
73606
|
+
children: [
|
|
73607
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 flex-1 min-w-0 pr-4", children: [
|
|
73608
|
+
item.ticketLabel && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center rounded-full border border-indigo-100 bg-indigo-50 px-2 py-0.5 text-[10px] font-semibold text-indigo-600", children: item.ticketLabel }) }),
|
|
73609
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
73610
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 min-w-0 mb-0.5", children: /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-[13px] font-semibold text-slate-800 truncate transition-colors group-hover:text-indigo-600", children: item.title }) }),
|
|
73611
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
73612
|
+
"p",
|
|
73613
|
+
{
|
|
73614
|
+
className: "text-[10px] font-medium text-slate-400 truncate",
|
|
73615
|
+
title: item.metadataLabel,
|
|
73616
|
+
children: item.metadataLabel
|
|
73617
|
+
}
|
|
73618
|
+
)
|
|
73121
73619
|
] })
|
|
73122
|
-
] })
|
|
73123
|
-
|
|
73620
|
+
] }),
|
|
73621
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end flex-shrink-0 ml-4", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
73622
|
+
"span",
|
|
73623
|
+
{
|
|
73624
|
+
className: `inline-flex items-center gap-1 rounded-full border px-2.5 py-0.5 text-[11px] ${item.metric.includes("pcs / day") || item.metric.includes("gain") ? "border-emerald-100 bg-emerald-50 text-emerald-700" : item.metric.includes("Idle") ? "border-amber-100 bg-amber-50 text-amber-700" : "border-slate-100 bg-slate-50 text-slate-600"}`,
|
|
73625
|
+
children: [
|
|
73626
|
+
(item.metric.includes("pcs / day") || item.metric.includes("gain")) && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingUp, { className: "h-3 w-3" }),
|
|
73627
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", children: item.metric })
|
|
73628
|
+
]
|
|
73629
|
+
}
|
|
73630
|
+
) })
|
|
73631
|
+
]
|
|
73124
73632
|
},
|
|
73125
73633
|
item.id
|
|
73126
73634
|
)) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-8 text-center text-sm text-slate-400", children: "No open improvement issues" }) })
|
|
@@ -73908,6 +74416,7 @@ exports.getCoreSessionReplayUrl = getCoreSessionReplayUrl;
|
|
|
73908
74416
|
exports.getCurrentShift = getCurrentShift;
|
|
73909
74417
|
exports.getCurrentShiftForLine = getCurrentShiftForLine;
|
|
73910
74418
|
exports.getCurrentTimeInZone = getCurrentTimeInZone;
|
|
74419
|
+
exports.getCurrentWeekToDateRange = getCurrentWeekToDateRange;
|
|
73911
74420
|
exports.getDashboardHeaderTimeInZone = getDashboardHeaderTimeInZone;
|
|
73912
74421
|
exports.getDateKeyFromDate = getDateKeyFromDate;
|
|
73913
74422
|
exports.getDaysDifferenceInZone = getDaysDifferenceInZone;
|