@optifye/dashboard-core 6.11.28 → 6.11.30
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 +42 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +695 -111
- package/dist/index.mjs +695 -111
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -39191,6 +39191,456 @@ var MetricCard2 = ({ title, value, unit = "", trend = null }) => {
|
|
|
39191
39191
|
] });
|
|
39192
39192
|
};
|
|
39193
39193
|
var MetricCard_default = MetricCard2;
|
|
39194
|
+
var normalizeValue = (v) => {
|
|
39195
|
+
if (!v) return "";
|
|
39196
|
+
return v.substring(0, 5);
|
|
39197
|
+
};
|
|
39198
|
+
var to12h = (value24) => {
|
|
39199
|
+
const norm = normalizeValue(value24);
|
|
39200
|
+
if (!norm || norm.length < 5) return { hour: 12, minute: 0, period: "AM" };
|
|
39201
|
+
const [h, m] = norm.split(":").map(Number);
|
|
39202
|
+
const period = h >= 12 ? "PM" : "AM";
|
|
39203
|
+
let hour12 = h % 12;
|
|
39204
|
+
if (hour12 === 0) hour12 = 12;
|
|
39205
|
+
return { hour: hour12, minute: isNaN(m) ? 0 : m, period };
|
|
39206
|
+
};
|
|
39207
|
+
var to24h = (hour12, minute, period) => {
|
|
39208
|
+
let h = hour12;
|
|
39209
|
+
if (period === "AM" && h === 12) h = 0;
|
|
39210
|
+
if (period === "PM" && h !== 12) h += 12;
|
|
39211
|
+
return `${h.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}`;
|
|
39212
|
+
};
|
|
39213
|
+
var pad22 = (n) => n.toString().padStart(2, "0");
|
|
39214
|
+
var SegmentedTimeInput = ({
|
|
39215
|
+
hour,
|
|
39216
|
+
minute,
|
|
39217
|
+
period,
|
|
39218
|
+
hasValue,
|
|
39219
|
+
placeholder,
|
|
39220
|
+
disabled,
|
|
39221
|
+
activeSegment,
|
|
39222
|
+
onSegmentFocus,
|
|
39223
|
+
onSegmentBlur,
|
|
39224
|
+
onHourChange,
|
|
39225
|
+
onMinuteChange,
|
|
39226
|
+
onPeriodChange,
|
|
39227
|
+
onTogglePopover,
|
|
39228
|
+
isPopoverOpen
|
|
39229
|
+
}) => {
|
|
39230
|
+
const containerRef = useRef(null);
|
|
39231
|
+
const digitBufferRef = useRef("");
|
|
39232
|
+
const digitTimerRef = useRef(null);
|
|
39233
|
+
useEffect(() => {
|
|
39234
|
+
digitBufferRef.current = "";
|
|
39235
|
+
if (digitTimerRef.current) clearTimeout(digitTimerRef.current);
|
|
39236
|
+
}, [activeSegment]);
|
|
39237
|
+
const commitHourDigits = useCallback((digits) => {
|
|
39238
|
+
const val = parseInt(digits, 10);
|
|
39239
|
+
if (val >= 1 && val <= 12) onHourChange(val);
|
|
39240
|
+
else if (val === 0) onHourChange(12);
|
|
39241
|
+
digitBufferRef.current = "";
|
|
39242
|
+
}, [onHourChange]);
|
|
39243
|
+
const commitMinuteDigits = useCallback((digits) => {
|
|
39244
|
+
const val = parseInt(digits, 10);
|
|
39245
|
+
onMinuteChange(Math.min(59, Math.max(0, val)));
|
|
39246
|
+
digitBufferRef.current = "";
|
|
39247
|
+
}, [onMinuteChange]);
|
|
39248
|
+
const handleKeyDown = useCallback((e) => {
|
|
39249
|
+
if (disabled || !activeSegment) return;
|
|
39250
|
+
const key = e.key;
|
|
39251
|
+
if (key === "Tab") {
|
|
39252
|
+
if (e.shiftKey) {
|
|
39253
|
+
if (activeSegment === "minute") {
|
|
39254
|
+
e.preventDefault();
|
|
39255
|
+
onSegmentFocus("hour");
|
|
39256
|
+
} else if (activeSegment === "period") {
|
|
39257
|
+
e.preventDefault();
|
|
39258
|
+
onSegmentFocus("minute");
|
|
39259
|
+
}
|
|
39260
|
+
} else {
|
|
39261
|
+
if (activeSegment === "hour") {
|
|
39262
|
+
e.preventDefault();
|
|
39263
|
+
onSegmentFocus("minute");
|
|
39264
|
+
} else if (activeSegment === "minute") {
|
|
39265
|
+
e.preventDefault();
|
|
39266
|
+
onSegmentFocus("period");
|
|
39267
|
+
}
|
|
39268
|
+
}
|
|
39269
|
+
return;
|
|
39270
|
+
}
|
|
39271
|
+
e.preventDefault();
|
|
39272
|
+
if (key === "ArrowUp" || key === "ArrowDown") {
|
|
39273
|
+
const delta = key === "ArrowUp" ? 1 : -1;
|
|
39274
|
+
if (activeSegment === "hour") {
|
|
39275
|
+
let newH = hour + delta;
|
|
39276
|
+
if (newH > 12) newH = 1;
|
|
39277
|
+
if (newH < 1) newH = 12;
|
|
39278
|
+
onHourChange(newH);
|
|
39279
|
+
} else if (activeSegment === "minute") {
|
|
39280
|
+
let newM = minute + delta;
|
|
39281
|
+
if (newM > 59) newM = 0;
|
|
39282
|
+
if (newM < 0) newM = 59;
|
|
39283
|
+
onMinuteChange(newM);
|
|
39284
|
+
} else if (activeSegment === "period") {
|
|
39285
|
+
onPeriodChange(period === "AM" ? "PM" : "AM");
|
|
39286
|
+
}
|
|
39287
|
+
return;
|
|
39288
|
+
}
|
|
39289
|
+
if (key === "Enter" || key === " ") {
|
|
39290
|
+
onTogglePopover();
|
|
39291
|
+
return;
|
|
39292
|
+
}
|
|
39293
|
+
if (key === "Escape") {
|
|
39294
|
+
onSegmentBlur();
|
|
39295
|
+
return;
|
|
39296
|
+
}
|
|
39297
|
+
if (activeSegment === "period") {
|
|
39298
|
+
if (key.toLowerCase() === "a") onPeriodChange("AM");
|
|
39299
|
+
else if (key.toLowerCase() === "p") onPeriodChange("PM");
|
|
39300
|
+
return;
|
|
39301
|
+
}
|
|
39302
|
+
if (key >= "0" && key <= "9") {
|
|
39303
|
+
if (digitTimerRef.current) clearTimeout(digitTimerRef.current);
|
|
39304
|
+
if (activeSegment === "hour") {
|
|
39305
|
+
digitBufferRef.current += key;
|
|
39306
|
+
if (digitBufferRef.current.length >= 2) {
|
|
39307
|
+
commitHourDigits(digitBufferRef.current);
|
|
39308
|
+
onSegmentFocus("minute");
|
|
39309
|
+
} else {
|
|
39310
|
+
const firstDigit = parseInt(key, 10);
|
|
39311
|
+
if (firstDigit >= 2) {
|
|
39312
|
+
commitHourDigits(digitBufferRef.current);
|
|
39313
|
+
onSegmentFocus("minute");
|
|
39314
|
+
} else {
|
|
39315
|
+
digitTimerRef.current = setTimeout(() => {
|
|
39316
|
+
commitHourDigits(digitBufferRef.current);
|
|
39317
|
+
onSegmentFocus("minute");
|
|
39318
|
+
}, 800);
|
|
39319
|
+
}
|
|
39320
|
+
}
|
|
39321
|
+
} else if (activeSegment === "minute") {
|
|
39322
|
+
digitBufferRef.current += key;
|
|
39323
|
+
if (digitBufferRef.current.length >= 2) {
|
|
39324
|
+
commitMinuteDigits(digitBufferRef.current);
|
|
39325
|
+
onSegmentFocus("period");
|
|
39326
|
+
} else {
|
|
39327
|
+
const firstDigit = parseInt(key, 10);
|
|
39328
|
+
if (firstDigit >= 6) {
|
|
39329
|
+
commitMinuteDigits("0" + key);
|
|
39330
|
+
onSegmentFocus("period");
|
|
39331
|
+
} else {
|
|
39332
|
+
digitTimerRef.current = setTimeout(() => {
|
|
39333
|
+
commitMinuteDigits(digitBufferRef.current.padStart(2, "0"));
|
|
39334
|
+
onSegmentFocus("period");
|
|
39335
|
+
}, 800);
|
|
39336
|
+
}
|
|
39337
|
+
}
|
|
39338
|
+
}
|
|
39339
|
+
}
|
|
39340
|
+
}, [disabled, activeSegment, hour, minute, period, onHourChange, onMinuteChange, onPeriodChange, onSegmentFocus, onSegmentBlur, onTogglePopover, commitHourDigits, commitMinuteDigits]);
|
|
39341
|
+
const segmentClass = (seg) => `px-0.5 py-0.5 rounded cursor-pointer select-none transition-colors duration-150 ${activeSegment === seg ? "bg-blue-100 text-blue-700" : "text-gray-900 hover:bg-gray-100"}`;
|
|
39342
|
+
return /* @__PURE__ */ jsx(
|
|
39343
|
+
"div",
|
|
39344
|
+
{
|
|
39345
|
+
ref: containerRef,
|
|
39346
|
+
tabIndex: disabled ? -1 : 0,
|
|
39347
|
+
onFocus: () => {
|
|
39348
|
+
if (!activeSegment && !disabled) onSegmentFocus("hour");
|
|
39349
|
+
},
|
|
39350
|
+
onKeyDown: handleKeyDown,
|
|
39351
|
+
className: "flex items-center gap-0 outline-none flex-1 min-w-0",
|
|
39352
|
+
children: hasValue ? /* @__PURE__ */ jsxs("div", { className: "flex items-center text-sm tabular-nums text-gray-900", children: [
|
|
39353
|
+
/* @__PURE__ */ jsx(
|
|
39354
|
+
"span",
|
|
39355
|
+
{
|
|
39356
|
+
onClick: (e) => {
|
|
39357
|
+
e.stopPropagation();
|
|
39358
|
+
if (!disabled) onSegmentFocus("hour");
|
|
39359
|
+
},
|
|
39360
|
+
className: segmentClass("hour"),
|
|
39361
|
+
role: "spinbutton",
|
|
39362
|
+
"aria-label": "Hour",
|
|
39363
|
+
"aria-valuenow": hour,
|
|
39364
|
+
"aria-valuemin": 1,
|
|
39365
|
+
"aria-valuemax": 12,
|
|
39366
|
+
children: pad22(hour)
|
|
39367
|
+
}
|
|
39368
|
+
),
|
|
39369
|
+
/* @__PURE__ */ jsx("span", { className: "text-gray-400 mx-px", children: ":" }),
|
|
39370
|
+
/* @__PURE__ */ jsx(
|
|
39371
|
+
"span",
|
|
39372
|
+
{
|
|
39373
|
+
onClick: (e) => {
|
|
39374
|
+
e.stopPropagation();
|
|
39375
|
+
if (!disabled) onSegmentFocus("minute");
|
|
39376
|
+
},
|
|
39377
|
+
className: segmentClass("minute"),
|
|
39378
|
+
role: "spinbutton",
|
|
39379
|
+
"aria-label": "Minute",
|
|
39380
|
+
"aria-valuenow": minute,
|
|
39381
|
+
"aria-valuemin": 0,
|
|
39382
|
+
"aria-valuemax": 59,
|
|
39383
|
+
children: pad22(minute)
|
|
39384
|
+
}
|
|
39385
|
+
),
|
|
39386
|
+
/* @__PURE__ */ jsx(
|
|
39387
|
+
"span",
|
|
39388
|
+
{
|
|
39389
|
+
onClick: (e) => {
|
|
39390
|
+
e.stopPropagation();
|
|
39391
|
+
if (!disabled) onSegmentFocus("period");
|
|
39392
|
+
},
|
|
39393
|
+
className: `${segmentClass("period")} ml-1 text-gray-500`,
|
|
39394
|
+
role: "spinbutton",
|
|
39395
|
+
"aria-label": "AM or PM",
|
|
39396
|
+
"aria-valuenow": period === "AM" ? 0 : 1,
|
|
39397
|
+
"aria-valuemin": 0,
|
|
39398
|
+
"aria-valuemax": 1,
|
|
39399
|
+
children: period
|
|
39400
|
+
}
|
|
39401
|
+
)
|
|
39402
|
+
] }) : /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-400 select-none", children: placeholder })
|
|
39403
|
+
}
|
|
39404
|
+
);
|
|
39405
|
+
};
|
|
39406
|
+
var SCROLLBAR_HIDE_ID = "tp-scrollbar-hide";
|
|
39407
|
+
var injectScrollbarHideCSS = () => {
|
|
39408
|
+
if (typeof document === "undefined") return;
|
|
39409
|
+
if (document.getElementById(SCROLLBAR_HIDE_ID)) return;
|
|
39410
|
+
const style = document.createElement("style");
|
|
39411
|
+
style.id = SCROLLBAR_HIDE_ID;
|
|
39412
|
+
style.textContent = ".tp-scroll-hide::-webkit-scrollbar{display:none}";
|
|
39413
|
+
document.head.appendChild(style);
|
|
39414
|
+
};
|
|
39415
|
+
var ITEM_H = 40;
|
|
39416
|
+
var VISIBLE = 5;
|
|
39417
|
+
var WHEEL_H = ITEM_H * VISIBLE;
|
|
39418
|
+
var PAD = Math.floor(VISIBLE / 2);
|
|
39419
|
+
var ScrollColumn = ({ items, selected, onSelect, width = 56 }) => {
|
|
39420
|
+
const elRef = useRef(null);
|
|
39421
|
+
const suppressRef = useRef(false);
|
|
39422
|
+
const snapTimerRef = useRef(null);
|
|
39423
|
+
const mountedRef = useRef(false);
|
|
39424
|
+
const dragging = useRef(false);
|
|
39425
|
+
const dragStartY = useRef(0);
|
|
39426
|
+
const dragStartScroll = useRef(0);
|
|
39427
|
+
useEffect(() => {
|
|
39428
|
+
injectScrollbarHideCSS();
|
|
39429
|
+
}, []);
|
|
39430
|
+
useEffect(() => {
|
|
39431
|
+
const idx = items.findIndex((i) => i.value === selected);
|
|
39432
|
+
if (idx < 0 || !elRef.current || suppressRef.current) return;
|
|
39433
|
+
const target = idx * ITEM_H;
|
|
39434
|
+
if (!mountedRef.current) {
|
|
39435
|
+
suppressRef.current = true;
|
|
39436
|
+
elRef.current.scrollTop = target;
|
|
39437
|
+
setTimeout(() => {
|
|
39438
|
+
if (elRef.current) elRef.current.scrollTop = target;
|
|
39439
|
+
setTimeout(() => {
|
|
39440
|
+
suppressRef.current = false;
|
|
39441
|
+
mountedRef.current = true;
|
|
39442
|
+
}, 200);
|
|
39443
|
+
}, 30);
|
|
39444
|
+
} else {
|
|
39445
|
+
elRef.current.scrollTo({ top: target, behavior: "smooth" });
|
|
39446
|
+
}
|
|
39447
|
+
}, [selected, items]);
|
|
39448
|
+
const scheduleSnap = useCallback(() => {
|
|
39449
|
+
if (snapTimerRef.current) clearTimeout(snapTimerRef.current);
|
|
39450
|
+
snapTimerRef.current = setTimeout(() => {
|
|
39451
|
+
if (!elRef.current || suppressRef.current) return;
|
|
39452
|
+
const idx = Math.round(elRef.current.scrollTop / ITEM_H);
|
|
39453
|
+
const clamped = Math.max(0, Math.min(items.length - 1, idx));
|
|
39454
|
+
suppressRef.current = true;
|
|
39455
|
+
elRef.current.scrollTo({ top: clamped * ITEM_H, behavior: "smooth" });
|
|
39456
|
+
const item = items[clamped];
|
|
39457
|
+
if (item && item.value !== selected) onSelect(item.value);
|
|
39458
|
+
setTimeout(() => {
|
|
39459
|
+
suppressRef.current = false;
|
|
39460
|
+
}, 150);
|
|
39461
|
+
}, 100);
|
|
39462
|
+
}, [items, selected, onSelect]);
|
|
39463
|
+
const onScroll = useCallback(() => {
|
|
39464
|
+
if (suppressRef.current) return;
|
|
39465
|
+
scheduleSnap();
|
|
39466
|
+
}, [scheduleSnap]);
|
|
39467
|
+
const onMouseDown = useCallback((e) => {
|
|
39468
|
+
dragging.current = true;
|
|
39469
|
+
dragStartY.current = e.clientY;
|
|
39470
|
+
dragStartScroll.current = elRef.current?.scrollTop ?? 0;
|
|
39471
|
+
e.preventDefault();
|
|
39472
|
+
const onMove = (ev) => {
|
|
39473
|
+
if (!dragging.current || !elRef.current) return;
|
|
39474
|
+
const dy = dragStartY.current - ev.clientY;
|
|
39475
|
+
elRef.current.scrollTop = dragStartScroll.current + dy;
|
|
39476
|
+
};
|
|
39477
|
+
const onUp = () => {
|
|
39478
|
+
dragging.current = false;
|
|
39479
|
+
scheduleSnap();
|
|
39480
|
+
document.removeEventListener("mousemove", onMove);
|
|
39481
|
+
document.removeEventListener("mouseup", onUp);
|
|
39482
|
+
};
|
|
39483
|
+
document.addEventListener("mousemove", onMove);
|
|
39484
|
+
document.addEventListener("mouseup", onUp);
|
|
39485
|
+
}, [scheduleSnap]);
|
|
39486
|
+
const onTouchStart = useCallback((e) => {
|
|
39487
|
+
dragging.current = true;
|
|
39488
|
+
dragStartY.current = e.touches[0].clientY;
|
|
39489
|
+
dragStartScroll.current = elRef.current?.scrollTop ?? 0;
|
|
39490
|
+
}, []);
|
|
39491
|
+
const onTouchMove = useCallback((e) => {
|
|
39492
|
+
if (!dragging.current || !elRef.current) return;
|
|
39493
|
+
const dy = dragStartY.current - e.touches[0].clientY;
|
|
39494
|
+
elRef.current.scrollTop = dragStartScroll.current + dy;
|
|
39495
|
+
e.preventDefault();
|
|
39496
|
+
}, []);
|
|
39497
|
+
const onTouchEnd = useCallback(() => {
|
|
39498
|
+
dragging.current = false;
|
|
39499
|
+
scheduleSnap();
|
|
39500
|
+
}, [scheduleSnap]);
|
|
39501
|
+
const handleClick = useCallback((value, idx) => {
|
|
39502
|
+
onSelect(value);
|
|
39503
|
+
if (elRef.current) {
|
|
39504
|
+
suppressRef.current = true;
|
|
39505
|
+
elRef.current.scrollTo({ top: idx * ITEM_H, behavior: "smooth" });
|
|
39506
|
+
setTimeout(() => {
|
|
39507
|
+
suppressRef.current = false;
|
|
39508
|
+
}, 250);
|
|
39509
|
+
}
|
|
39510
|
+
}, [onSelect]);
|
|
39511
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative select-none", style: { width, height: WHEEL_H }, children: [
|
|
39512
|
+
/* @__PURE__ */ jsx(
|
|
39513
|
+
"div",
|
|
39514
|
+
{
|
|
39515
|
+
className: "absolute left-1 right-1 rounded-lg bg-blue-50/80 border border-blue-200/60 pointer-events-none z-0",
|
|
39516
|
+
style: { top: PAD * ITEM_H, height: ITEM_H }
|
|
39517
|
+
}
|
|
39518
|
+
),
|
|
39519
|
+
/* @__PURE__ */ jsx(
|
|
39520
|
+
"div",
|
|
39521
|
+
{
|
|
39522
|
+
className: "absolute inset-x-0 top-0 pointer-events-none z-10",
|
|
39523
|
+
style: { height: ITEM_H * 1.8, background: "linear-gradient(to bottom, white 0%, rgba(255,255,255,0.85) 50%, transparent 100%)" }
|
|
39524
|
+
}
|
|
39525
|
+
),
|
|
39526
|
+
/* @__PURE__ */ jsx(
|
|
39527
|
+
"div",
|
|
39528
|
+
{
|
|
39529
|
+
className: "absolute inset-x-0 bottom-0 pointer-events-none z-10",
|
|
39530
|
+
style: { height: ITEM_H * 1.8, background: "linear-gradient(to top, white 0%, rgba(255,255,255,0.85) 50%, transparent 100%)" }
|
|
39531
|
+
}
|
|
39532
|
+
),
|
|
39533
|
+
/* @__PURE__ */ jsxs(
|
|
39534
|
+
"div",
|
|
39535
|
+
{
|
|
39536
|
+
ref: elRef,
|
|
39537
|
+
onScroll,
|
|
39538
|
+
onMouseDown,
|
|
39539
|
+
onTouchStart,
|
|
39540
|
+
onTouchMove,
|
|
39541
|
+
onTouchEnd,
|
|
39542
|
+
className: "h-full overflow-y-auto tp-scroll-hide relative z-[1] cursor-grab active:cursor-grabbing",
|
|
39543
|
+
style: { scrollbarWidth: "none", msOverflowStyle: "none" },
|
|
39544
|
+
role: "listbox",
|
|
39545
|
+
children: [
|
|
39546
|
+
Array.from({ length: PAD }).map((_, i) => /* @__PURE__ */ jsx("div", { style: { height: ITEM_H }, "aria-hidden": true }, `pt-${i}`)),
|
|
39547
|
+
items.map((item, idx) => {
|
|
39548
|
+
const isSel = item.value === selected;
|
|
39549
|
+
return /* @__PURE__ */ jsx(
|
|
39550
|
+
"div",
|
|
39551
|
+
{
|
|
39552
|
+
onClick: () => handleClick(item.value, idx),
|
|
39553
|
+
className: `flex items-center justify-center transition-all duration-100 ${isSel ? "text-gray-900 font-semibold text-[15px]" : "text-gray-300 text-sm"}`,
|
|
39554
|
+
style: { height: ITEM_H },
|
|
39555
|
+
role: "option",
|
|
39556
|
+
"aria-selected": isSel,
|
|
39557
|
+
children: item.label
|
|
39558
|
+
},
|
|
39559
|
+
item.value
|
|
39560
|
+
);
|
|
39561
|
+
}),
|
|
39562
|
+
Array.from({ length: PAD }).map((_, i) => /* @__PURE__ */ jsx("div", { style: { height: ITEM_H }, "aria-hidden": true }, `pb-${i}`))
|
|
39563
|
+
]
|
|
39564
|
+
}
|
|
39565
|
+
)
|
|
39566
|
+
] });
|
|
39567
|
+
};
|
|
39568
|
+
var HOURS = Array.from({ length: 12 }, (_, i) => ({ value: i + 1, label: (i + 1).toString() }));
|
|
39569
|
+
var MINUTES = Array.from({ length: 60 }, (_, i) => ({ value: i, label: pad22(i) }));
|
|
39570
|
+
var TimePopover = ({
|
|
39571
|
+
hour,
|
|
39572
|
+
minute,
|
|
39573
|
+
period,
|
|
39574
|
+
onHourChange,
|
|
39575
|
+
onMinuteChange,
|
|
39576
|
+
onPeriodChange,
|
|
39577
|
+
onClose,
|
|
39578
|
+
onNow
|
|
39579
|
+
}) => {
|
|
39580
|
+
const bandCenter = PAD * ITEM_H + ITEM_H / 2;
|
|
39581
|
+
return /* @__PURE__ */ jsxs(
|
|
39582
|
+
"div",
|
|
39583
|
+
{
|
|
39584
|
+
className: "absolute z-50 left-0 right-0 sm:left-auto sm:right-auto sm:w-[264px] mt-1.5 bg-white border border-gray-200 rounded-2xl shadow-[0_8px_30px_rgba(0,0,0,0.08),0_2px_8px_rgba(0,0,0,0.04)] overflow-hidden",
|
|
39585
|
+
role: "dialog",
|
|
39586
|
+
"aria-label": "Choose time",
|
|
39587
|
+
onClick: (e) => e.stopPropagation(),
|
|
39588
|
+
children: [
|
|
39589
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-center px-4 pt-4 pb-2", children: [
|
|
39590
|
+
/* @__PURE__ */ jsx(ScrollColumn, { items: HOURS, selected: hour, onSelect: (v) => onHourChange(v), width: 52 }),
|
|
39591
|
+
/* @__PURE__ */ jsx(
|
|
39592
|
+
"div",
|
|
39593
|
+
{
|
|
39594
|
+
className: "text-gray-300 text-lg font-light flex-shrink-0 w-4 text-center select-none",
|
|
39595
|
+
style: { marginTop: bandCenter - 12 },
|
|
39596
|
+
children: ":"
|
|
39597
|
+
}
|
|
39598
|
+
),
|
|
39599
|
+
/* @__PURE__ */ jsx(ScrollColumn, { items: MINUTES, selected: minute, onSelect: (v) => onMinuteChange(v), width: 52 }),
|
|
39600
|
+
/* @__PURE__ */ jsx(
|
|
39601
|
+
"div",
|
|
39602
|
+
{
|
|
39603
|
+
className: "flex flex-col gap-1.5 ml-3 flex-shrink-0",
|
|
39604
|
+
style: { marginTop: bandCenter - 38 },
|
|
39605
|
+
children: ["AM", "PM"].map((p) => /* @__PURE__ */ jsx(
|
|
39606
|
+
"button",
|
|
39607
|
+
{
|
|
39608
|
+
type: "button",
|
|
39609
|
+
onClick: () => onPeriodChange(p),
|
|
39610
|
+
className: `w-12 h-8 rounded-lg text-[11px] font-bold tracking-widest transition-all duration-150 ${period === p ? "bg-blue-600 text-white shadow-sm" : "bg-gray-100 text-gray-400 hover:bg-gray-200 hover:text-gray-600"}`,
|
|
39611
|
+
"aria-pressed": period === p,
|
|
39612
|
+
children: p
|
|
39613
|
+
},
|
|
39614
|
+
p
|
|
39615
|
+
))
|
|
39616
|
+
}
|
|
39617
|
+
)
|
|
39618
|
+
] }),
|
|
39619
|
+
/* @__PURE__ */ jsx("div", { className: "mx-4 border-t border-gray-100" }),
|
|
39620
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-2.5", children: [
|
|
39621
|
+
/* @__PURE__ */ jsx(
|
|
39622
|
+
"button",
|
|
39623
|
+
{
|
|
39624
|
+
type: "button",
|
|
39625
|
+
onClick: onNow,
|
|
39626
|
+
className: "text-[13px] font-medium text-blue-600 hover:text-blue-700 transition-colors px-2.5 py-1 rounded-md hover:bg-blue-50",
|
|
39627
|
+
children: "Now"
|
|
39628
|
+
}
|
|
39629
|
+
),
|
|
39630
|
+
/* @__PURE__ */ jsx(
|
|
39631
|
+
"button",
|
|
39632
|
+
{
|
|
39633
|
+
type: "button",
|
|
39634
|
+
onClick: onClose,
|
|
39635
|
+
className: "text-[13px] font-medium text-white bg-blue-600 hover:bg-blue-700 px-4 py-1.5 rounded-lg transition-colors shadow-sm",
|
|
39636
|
+
children: "Done"
|
|
39637
|
+
}
|
|
39638
|
+
)
|
|
39639
|
+
] })
|
|
39640
|
+
]
|
|
39641
|
+
}
|
|
39642
|
+
);
|
|
39643
|
+
};
|
|
39194
39644
|
var TimePickerDropdown = ({
|
|
39195
39645
|
value,
|
|
39196
39646
|
onChange,
|
|
@@ -39198,124 +39648,155 @@ var TimePickerDropdown = ({
|
|
|
39198
39648
|
className = "",
|
|
39199
39649
|
disabled = false
|
|
39200
39650
|
}) => {
|
|
39201
|
-
const [
|
|
39202
|
-
const [
|
|
39203
|
-
const
|
|
39204
|
-
const
|
|
39205
|
-
const
|
|
39206
|
-
|
|
39207
|
-
for (let hour = 0; hour < 24; hour++) {
|
|
39208
|
-
for (let minute = 0; minute < 60; minute += 10) {
|
|
39209
|
-
const time24 = `${hour.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}`;
|
|
39210
|
-
const hour12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
|
|
39211
|
-
const ampm = hour < 12 ? "AM" : "PM";
|
|
39212
|
-
const time12 = `${hour12}:${minute.toString().padStart(2, "0")} ${ampm}`;
|
|
39213
|
-
slots.push({ value: time24, label: time12 });
|
|
39214
|
-
}
|
|
39215
|
-
}
|
|
39216
|
-
return slots;
|
|
39217
|
-
};
|
|
39218
|
-
const timeSlots = generateTimeSlots();
|
|
39219
|
-
const filteredSlots = timeSlots.filter(
|
|
39220
|
-
(slot) => slot.label.toLowerCase().includes(searchTerm.toLowerCase())
|
|
39221
|
-
);
|
|
39222
|
-
const getDisplayValue = (value2) => {
|
|
39223
|
-
if (!value2) return "";
|
|
39224
|
-
const normalizedValue = value2.substring(0, 5);
|
|
39225
|
-
const slot = timeSlots.find((s) => s.value === normalizedValue);
|
|
39226
|
-
return slot ? slot.label : value2;
|
|
39227
|
-
};
|
|
39651
|
+
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
|
|
39652
|
+
const [activeSegment, setActiveSegment] = useState(null);
|
|
39653
|
+
const containerRef = useRef(null);
|
|
39654
|
+
const normalizedValue = useMemo(() => normalizeValue(value), [value]);
|
|
39655
|
+
const hasValue = normalizedValue.length === 5 && normalizedValue.includes(":");
|
|
39656
|
+
const { hour, minute, period } = useMemo(() => to12h(normalizedValue), [normalizedValue]);
|
|
39228
39657
|
useEffect(() => {
|
|
39229
39658
|
const handleClickOutside = (event) => {
|
|
39230
|
-
if (
|
|
39231
|
-
|
|
39232
|
-
|
|
39659
|
+
if (containerRef.current && !containerRef.current.contains(event.target)) {
|
|
39660
|
+
setIsPopoverOpen(false);
|
|
39661
|
+
setActiveSegment(null);
|
|
39233
39662
|
}
|
|
39234
39663
|
};
|
|
39235
39664
|
document.addEventListener("mousedown", handleClickOutside);
|
|
39236
39665
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
39237
39666
|
}, []);
|
|
39238
|
-
const
|
|
39239
|
-
|
|
39240
|
-
|
|
39241
|
-
|
|
39242
|
-
|
|
39243
|
-
|
|
39244
|
-
|
|
39245
|
-
|
|
39246
|
-
|
|
39247
|
-
|
|
39248
|
-
|
|
39667
|
+
const emitChange = useCallback((h, m, p) => {
|
|
39668
|
+
onChange(to24h(h, m, p));
|
|
39669
|
+
}, [onChange]);
|
|
39670
|
+
const handleHourChange = useCallback((h) => {
|
|
39671
|
+
emitChange(h, minute, period);
|
|
39672
|
+
}, [emitChange, minute, period]);
|
|
39673
|
+
const handleMinuteChange = useCallback((m) => {
|
|
39674
|
+
emitChange(hour, m, period);
|
|
39675
|
+
}, [emitChange, hour, period]);
|
|
39676
|
+
const handlePeriodChange = useCallback((p) => {
|
|
39677
|
+
emitChange(hour, minute, p);
|
|
39678
|
+
}, [emitChange, hour, minute]);
|
|
39679
|
+
const handleNow = useCallback(() => {
|
|
39680
|
+
const now4 = /* @__PURE__ */ new Date();
|
|
39681
|
+
const h24 = now4.getHours();
|
|
39682
|
+
const m = now4.getMinutes();
|
|
39683
|
+
const p = h24 >= 12 ? "PM" : "AM";
|
|
39684
|
+
let h12 = h24 % 12;
|
|
39685
|
+
if (h12 === 0) h12 = 12;
|
|
39686
|
+
emitChange(h12, m, p);
|
|
39687
|
+
}, [emitChange]);
|
|
39688
|
+
const handleSegmentFocus = useCallback((seg) => {
|
|
39689
|
+
setActiveSegment(seg);
|
|
39690
|
+
if (!hasValue) {
|
|
39691
|
+
onChange(to24h(12, 0, "AM"));
|
|
39692
|
+
}
|
|
39693
|
+
}, [hasValue, onChange]);
|
|
39694
|
+
const handleSegmentBlur = useCallback(() => {
|
|
39695
|
+
setActiveSegment(null);
|
|
39696
|
+
}, []);
|
|
39697
|
+
const togglePopover = useCallback(() => {
|
|
39698
|
+
if (disabled) return;
|
|
39699
|
+
setIsPopoverOpen((prev) => !prev);
|
|
39700
|
+
if (!hasValue) {
|
|
39701
|
+
onChange(to24h(12, 0, "AM"));
|
|
39249
39702
|
}
|
|
39250
|
-
};
|
|
39251
|
-
const
|
|
39252
|
-
onChange(timeValue);
|
|
39253
|
-
setIsOpen(false);
|
|
39254
|
-
setSearchTerm("");
|
|
39255
|
-
};
|
|
39256
|
-
const handleToggle = () => {
|
|
39703
|
+
}, [disabled, hasValue, onChange]);
|
|
39704
|
+
const handleContainerClick = useCallback(() => {
|
|
39257
39705
|
if (disabled) return;
|
|
39258
|
-
|
|
39259
|
-
|
|
39260
|
-
|
|
39706
|
+
if (!activeSegment) {
|
|
39707
|
+
setActiveSegment("hour");
|
|
39708
|
+
if (!hasValue) {
|
|
39709
|
+
onChange(to24h(12, 0, "AM"));
|
|
39710
|
+
}
|
|
39261
39711
|
}
|
|
39262
|
-
};
|
|
39263
|
-
return /* @__PURE__ */ jsxs("div", { className: `relative ${className}`, ref:
|
|
39264
|
-
/* @__PURE__ */
|
|
39265
|
-
"
|
|
39712
|
+
}, [disabled, activeSegment, hasValue, onChange]);
|
|
39713
|
+
return /* @__PURE__ */ jsxs("div", { className: `relative ${className}`, ref: containerRef, children: [
|
|
39714
|
+
/* @__PURE__ */ jsxs(
|
|
39715
|
+
"div",
|
|
39266
39716
|
{
|
|
39267
|
-
|
|
39268
|
-
onClick: handleToggle,
|
|
39269
|
-
disabled,
|
|
39717
|
+
onClick: handleContainerClick,
|
|
39270
39718
|
className: `
|
|
39271
|
-
w-full px-3 py-2
|
|
39272
|
-
|
|
39273
|
-
|
|
39274
|
-
${disabled ? "bg-gray-50 cursor-not-allowed" : "cursor-pointer"}
|
|
39275
|
-
${
|
|
39719
|
+
w-full px-3 py-2 bg-white border rounded-md shadow-sm
|
|
39720
|
+
flex items-center gap-2
|
|
39721
|
+
transition-all duration-200
|
|
39722
|
+
${disabled ? "bg-gray-50 cursor-not-allowed border-gray-200" : "cursor-pointer border-gray-300 hover:border-gray-400"}
|
|
39723
|
+
${activeSegment || isPopoverOpen ? "ring-2 ring-blue-500 border-blue-500" : ""}
|
|
39276
39724
|
`,
|
|
39277
|
-
|
|
39278
|
-
|
|
39279
|
-
|
|
39280
|
-
|
|
39281
|
-
|
|
39725
|
+
role: "group",
|
|
39726
|
+
"aria-label": "Time picker",
|
|
39727
|
+
children: [
|
|
39728
|
+
/* @__PURE__ */ jsx(
|
|
39729
|
+
"button",
|
|
39730
|
+
{
|
|
39731
|
+
type: "button",
|
|
39732
|
+
onClick: (e) => {
|
|
39733
|
+
e.stopPropagation();
|
|
39734
|
+
togglePopover();
|
|
39735
|
+
},
|
|
39736
|
+
disabled,
|
|
39737
|
+
className: "text-gray-400 hover:text-blue-500 transition-colors flex-shrink-0 focus:outline-none",
|
|
39738
|
+
"aria-expanded": isPopoverOpen,
|
|
39739
|
+
"aria-haspopup": "dialog",
|
|
39740
|
+
"aria-label": "Open time picker",
|
|
39741
|
+
tabIndex: -1,
|
|
39742
|
+
children: /* @__PURE__ */ jsx(Clock, { className: "h-4 w-4" })
|
|
39743
|
+
}
|
|
39744
|
+
),
|
|
39282
39745
|
/* @__PURE__ */ jsx(
|
|
39283
|
-
|
|
39746
|
+
SegmentedTimeInput,
|
|
39284
39747
|
{
|
|
39285
|
-
|
|
39748
|
+
hour,
|
|
39749
|
+
minute,
|
|
39750
|
+
period,
|
|
39751
|
+
hasValue,
|
|
39752
|
+
placeholder,
|
|
39753
|
+
disabled,
|
|
39754
|
+
activeSegment,
|
|
39755
|
+
onSegmentFocus: handleSegmentFocus,
|
|
39756
|
+
onSegmentBlur: handleSegmentBlur,
|
|
39757
|
+
onHourChange: handleHourChange,
|
|
39758
|
+
onMinuteChange: handleMinuteChange,
|
|
39759
|
+
onPeriodChange: handlePeriodChange,
|
|
39760
|
+
onTogglePopover: togglePopover,
|
|
39761
|
+
isPopoverOpen
|
|
39762
|
+
}
|
|
39763
|
+
),
|
|
39764
|
+
/* @__PURE__ */ jsx(
|
|
39765
|
+
"button",
|
|
39766
|
+
{
|
|
39767
|
+
type: "button",
|
|
39768
|
+
onClick: (e) => {
|
|
39769
|
+
e.stopPropagation();
|
|
39770
|
+
togglePopover();
|
|
39771
|
+
},
|
|
39772
|
+
disabled,
|
|
39773
|
+
className: "text-gray-400 hover:text-gray-600 transition-transform duration-200 flex-shrink-0 focus:outline-none",
|
|
39774
|
+
tabIndex: -1,
|
|
39775
|
+
"aria-hidden": "true",
|
|
39776
|
+
children: /* @__PURE__ */ jsx(
|
|
39777
|
+
ChevronDown,
|
|
39778
|
+
{
|
|
39779
|
+
className: `h-4 w-4 transition-transform duration-200 ${isPopoverOpen ? "rotate-180" : ""}`
|
|
39780
|
+
}
|
|
39781
|
+
)
|
|
39286
39782
|
}
|
|
39287
39783
|
)
|
|
39288
|
-
]
|
|
39784
|
+
]
|
|
39289
39785
|
}
|
|
39290
39786
|
),
|
|
39291
|
-
|
|
39292
|
-
|
|
39293
|
-
|
|
39294
|
-
|
|
39295
|
-
|
|
39296
|
-
|
|
39297
|
-
|
|
39298
|
-
|
|
39299
|
-
|
|
39300
|
-
|
|
39301
|
-
|
|
39302
|
-
|
|
39303
|
-
|
|
39304
|
-
/* @__PURE__ */ jsx("div", { className: "overflow-y-auto max-h-48", children: filteredSlots.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-sm text-gray-500 text-center", children: "No times found" }) : filteredSlots.map((slot) => /* @__PURE__ */ jsx(
|
|
39305
|
-
"button",
|
|
39306
|
-
{
|
|
39307
|
-
type: "button",
|
|
39308
|
-
onClick: () => handleSelect(slot.value),
|
|
39309
|
-
className: `
|
|
39310
|
-
w-full px-3 py-2 text-left text-sm hover:bg-blue-50 hover:text-blue-600
|
|
39311
|
-
transition-colors duration-150 border-b border-gray-100 last:border-b-0
|
|
39312
|
-
${slot.value === value ? "bg-blue-50 text-blue-600 font-medium" : "text-gray-700"}
|
|
39313
|
-
`,
|
|
39314
|
-
children: slot.label
|
|
39315
|
-
},
|
|
39316
|
-
slot.value
|
|
39317
|
-
)) })
|
|
39318
|
-
] })
|
|
39787
|
+
isPopoverOpen && /* @__PURE__ */ jsx(
|
|
39788
|
+
TimePopover,
|
|
39789
|
+
{
|
|
39790
|
+
hour,
|
|
39791
|
+
minute,
|
|
39792
|
+
period,
|
|
39793
|
+
onHourChange: handleHourChange,
|
|
39794
|
+
onMinuteChange: handleMinuteChange,
|
|
39795
|
+
onPeriodChange: handlePeriodChange,
|
|
39796
|
+
onClose: () => setIsPopoverOpen(false),
|
|
39797
|
+
onNow: handleNow
|
|
39798
|
+
}
|
|
39799
|
+
)
|
|
39319
39800
|
] });
|
|
39320
39801
|
};
|
|
39321
39802
|
var SilentErrorBoundary = class extends React142__default.Component {
|
|
@@ -40053,6 +40534,7 @@ var AvatarUpload = ({
|
|
|
40053
40534
|
)
|
|
40054
40535
|
] });
|
|
40055
40536
|
};
|
|
40537
|
+
var CLIP_METADATA_PAGE_SIZE = 50;
|
|
40056
40538
|
var parseCycleTime = (value) => {
|
|
40057
40539
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
40058
40540
|
return value;
|
|
@@ -40139,7 +40621,9 @@ var FileManagerFilters = ({
|
|
|
40139
40621
|
className = "",
|
|
40140
40622
|
targetCycleTime = null,
|
|
40141
40623
|
idleTimeVlmEnabled = false,
|
|
40142
|
-
showPercentileCycleFilters = true
|
|
40624
|
+
showPercentileCycleFilters = true,
|
|
40625
|
+
prefetchedClipMetadata,
|
|
40626
|
+
activeCategoryLoading
|
|
40143
40627
|
}) => {
|
|
40144
40628
|
const [expandedNodes, setExpandedNodes] = useState(/* @__PURE__ */ new Set());
|
|
40145
40629
|
const [startTime, setStartTime] = useState("");
|
|
@@ -40160,10 +40644,83 @@ var FileManagerFilters = ({
|
|
|
40160
40644
|
const [categoryPages, setCategoryPages] = useState({});
|
|
40161
40645
|
const [categoryHasMore, setCategoryHasMore] = useState({});
|
|
40162
40646
|
const [localClipClassifications, setLocalClipClassifications] = useState({});
|
|
40647
|
+
const clipMetadataRef = useRef({});
|
|
40648
|
+
const inFlightMetadataRequestsRef = useRef(/* @__PURE__ */ new Set());
|
|
40163
40649
|
const mergedClipClassifications = useMemo(() => ({
|
|
40164
40650
|
...clipClassifications || {},
|
|
40165
40651
|
...localClipClassifications
|
|
40166
40652
|
}), [clipClassifications, localClipClassifications]);
|
|
40653
|
+
useEffect(() => {
|
|
40654
|
+
clipMetadataRef.current = clipMetadata;
|
|
40655
|
+
}, [clipMetadata]);
|
|
40656
|
+
const isCategoryExternallyManaged = useCallback((categoryId) => {
|
|
40657
|
+
if (!categoryId) {
|
|
40658
|
+
return false;
|
|
40659
|
+
}
|
|
40660
|
+
if (prefetchedClipMetadata && Array.isArray(prefetchedClipMetadata[categoryId]) && prefetchedClipMetadata[categoryId].length > 0) {
|
|
40661
|
+
return true;
|
|
40662
|
+
}
|
|
40663
|
+
if (activeCategoryLoading !== void 0 && categoryId === activeFilter) {
|
|
40664
|
+
return true;
|
|
40665
|
+
}
|
|
40666
|
+
return false;
|
|
40667
|
+
}, [prefetchedClipMetadata, activeCategoryLoading, activeFilter]);
|
|
40668
|
+
useEffect(() => {
|
|
40669
|
+
if (!prefetchedClipMetadata) {
|
|
40670
|
+
return;
|
|
40671
|
+
}
|
|
40672
|
+
setClipMetadata((prev) => {
|
|
40673
|
+
let changed = false;
|
|
40674
|
+
const next = { ...prev };
|
|
40675
|
+
Object.entries(prefetchedClipMetadata).forEach(([categoryId, clips]) => {
|
|
40676
|
+
if (!Array.isArray(clips) || clips.length === 0) {
|
|
40677
|
+
return;
|
|
40678
|
+
}
|
|
40679
|
+
const previousClips = prev[categoryId] || [];
|
|
40680
|
+
const previousSignature = previousClips.map((clip) => clip.clipId || clip.id).join("|");
|
|
40681
|
+
const nextSignature = clips.map((clip) => clip.clipId || clip.id).join("|");
|
|
40682
|
+
if (previousSignature === nextSignature) {
|
|
40683
|
+
return;
|
|
40684
|
+
}
|
|
40685
|
+
next[categoryId] = clips;
|
|
40686
|
+
changed = true;
|
|
40687
|
+
});
|
|
40688
|
+
return changed ? next : prev;
|
|
40689
|
+
});
|
|
40690
|
+
setCategoryPages((prev) => {
|
|
40691
|
+
let changed = false;
|
|
40692
|
+
const next = { ...prev };
|
|
40693
|
+
Object.entries(prefetchedClipMetadata).forEach(([categoryId, clips]) => {
|
|
40694
|
+
if (!Array.isArray(clips) || clips.length === 0) {
|
|
40695
|
+
return;
|
|
40696
|
+
}
|
|
40697
|
+
const inferredPage = Math.max(1, Math.ceil(clips.length / CLIP_METADATA_PAGE_SIZE));
|
|
40698
|
+
if (next[categoryId] === inferredPage) {
|
|
40699
|
+
return;
|
|
40700
|
+
}
|
|
40701
|
+
next[categoryId] = inferredPage;
|
|
40702
|
+
changed = true;
|
|
40703
|
+
});
|
|
40704
|
+
return changed ? next : prev;
|
|
40705
|
+
});
|
|
40706
|
+
setCategoryHasMore((prev) => {
|
|
40707
|
+
let changed = false;
|
|
40708
|
+
const next = { ...prev };
|
|
40709
|
+
Object.entries(prefetchedClipMetadata).forEach(([categoryId, clips]) => {
|
|
40710
|
+
if (!Array.isArray(clips) || clips.length === 0) {
|
|
40711
|
+
return;
|
|
40712
|
+
}
|
|
40713
|
+
const knownTotal = typeof counts?.[categoryId] === "number" ? counts[categoryId] : null;
|
|
40714
|
+
const inferredHasMore = knownTotal !== null ? clips.length < knownTotal : prev[categoryId];
|
|
40715
|
+
if (typeof inferredHasMore !== "boolean" || next[categoryId] === inferredHasMore) {
|
|
40716
|
+
return;
|
|
40717
|
+
}
|
|
40718
|
+
next[categoryId] = inferredHasMore;
|
|
40719
|
+
changed = true;
|
|
40720
|
+
});
|
|
40721
|
+
return changed ? next : prev;
|
|
40722
|
+
});
|
|
40723
|
+
}, [prefetchedClipMetadata, counts]);
|
|
40167
40724
|
const { state: filterState } = useClipFilter();
|
|
40168
40725
|
const [percentileCounts, setPercentileCounts] = useState({
|
|
40169
40726
|
"fast-cycles": null,
|
|
@@ -40270,7 +40827,8 @@ var FileManagerFilters = ({
|
|
|
40270
40827
|
shift: shift.toString(),
|
|
40271
40828
|
category: categoryId,
|
|
40272
40829
|
page,
|
|
40273
|
-
limit:
|
|
40830
|
+
limit: CLIP_METADATA_PAGE_SIZE,
|
|
40831
|
+
knownTotal: typeof counts?.[categoryId] === "number" ? counts[categoryId] : null,
|
|
40274
40832
|
snapshotDateTime,
|
|
40275
40833
|
snapshotClipId
|
|
40276
40834
|
}),
|
|
@@ -40280,7 +40838,7 @@ var FileManagerFilters = ({
|
|
|
40280
40838
|
throw new Error(`API error: ${response.status}`);
|
|
40281
40839
|
}
|
|
40282
40840
|
return response.json();
|
|
40283
|
-
}, [workspaceId, date, shift, snapshotDateTime, snapshotClipId, supabase]);
|
|
40841
|
+
}, [workspaceId, date, shift, counts, snapshotDateTime, snapshotClipId, supabase]);
|
|
40284
40842
|
const seedIdleClassifications = useCallback(async (clips) => {
|
|
40285
40843
|
if (!idleTimeVlmEnabled || clips.length === 0) {
|
|
40286
40844
|
return;
|
|
@@ -40337,6 +40895,10 @@ var FileManagerFilters = ({
|
|
|
40337
40895
|
return;
|
|
40338
40896
|
}
|
|
40339
40897
|
const loadingKey = `${categoryId}-${page}`;
|
|
40898
|
+
if (inFlightMetadataRequestsRef.current.has(loadingKey)) {
|
|
40899
|
+
return;
|
|
40900
|
+
}
|
|
40901
|
+
inFlightMetadataRequestsRef.current.add(loadingKey);
|
|
40340
40902
|
setLoadingCategories((prev) => /* @__PURE__ */ new Set([...prev, loadingKey]));
|
|
40341
40903
|
try {
|
|
40342
40904
|
const data = await fetchClipMetadataPage(categoryId, page);
|
|
@@ -40353,6 +40915,7 @@ var FileManagerFilters = ({
|
|
|
40353
40915
|
} catch (error) {
|
|
40354
40916
|
console.error("[FileManager] Error fetching clip metadata:", error);
|
|
40355
40917
|
} finally {
|
|
40918
|
+
inFlightMetadataRequestsRef.current.delete(loadingKey);
|
|
40356
40919
|
setLoadingCategories((prev) => {
|
|
40357
40920
|
const newSet = new Set(prev);
|
|
40358
40921
|
newSet.delete(loadingKey);
|
|
@@ -40626,16 +41189,19 @@ var FileManagerFilters = ({
|
|
|
40626
41189
|
useEffect(() => {
|
|
40627
41190
|
if (activeFilter) {
|
|
40628
41191
|
setExpandedNodes((prev) => {
|
|
41192
|
+
if (prev.has(activeFilter)) {
|
|
41193
|
+
return prev;
|
|
41194
|
+
}
|
|
40629
41195
|
const newExpanded = new Set(prev);
|
|
40630
41196
|
newExpanded.add(activeFilter);
|
|
40631
41197
|
return newExpanded;
|
|
40632
41198
|
});
|
|
40633
41199
|
const category = categories.find((cat) => cat.id === activeFilter);
|
|
40634
|
-
if (category) {
|
|
41200
|
+
if (category && !isCategoryExternallyManaged(activeFilter) && !clipMetadataRef.current[activeFilter]) {
|
|
40635
41201
|
fetchClipMetadata(activeFilter, 1);
|
|
40636
41202
|
}
|
|
40637
41203
|
}
|
|
40638
|
-
}, [activeFilter]);
|
|
41204
|
+
}, [activeFilter, isCategoryExternallyManaged]);
|
|
40639
41205
|
useEffect(() => {
|
|
40640
41206
|
const handleEscape = (e) => {
|
|
40641
41207
|
if (e.key === "Escape") {
|
|
@@ -40906,14 +41472,14 @@ var FileManagerFilters = ({
|
|
|
40906
41472
|
} else {
|
|
40907
41473
|
newExpanded.add(nodeId);
|
|
40908
41474
|
const category = categories.find((cat) => cat.id === nodeId);
|
|
40909
|
-
if (category && !clipMetadata[nodeId]) {
|
|
41475
|
+
if (category && !clipMetadata[nodeId] && !isCategoryExternallyManaged(nodeId)) {
|
|
40910
41476
|
console.log(`[FileManager] Fetching clips for expanded category: ${nodeId}`);
|
|
40911
41477
|
fetchClipMetadata(nodeId, 1);
|
|
40912
41478
|
}
|
|
40913
|
-
if (showPercentileCycleFilters && nodeId === "fast-cycles" && (percentileClips["fast-cycles"] || []).length === 0) {
|
|
41479
|
+
if (!isCategoryExternallyManaged(nodeId) && showPercentileCycleFilters && nodeId === "fast-cycles" && (percentileClips["fast-cycles"] || []).length === 0) {
|
|
40914
41480
|
fetchPercentileClips("fast-cycles");
|
|
40915
41481
|
}
|
|
40916
|
-
if (showPercentileCycleFilters && nodeId === "slow-cycles" && (percentileClips["slow-cycles"] || []).length === 0) {
|
|
41482
|
+
if (!isCategoryExternallyManaged(nodeId) && showPercentileCycleFilters && nodeId === "slow-cycles" && (percentileClips["slow-cycles"] || []).length === 0) {
|
|
40917
41483
|
fetchPercentileClips("slow-cycles");
|
|
40918
41484
|
}
|
|
40919
41485
|
}
|
|
@@ -40927,14 +41493,14 @@ var FileManagerFilters = ({
|
|
|
40927
41493
|
} else {
|
|
40928
41494
|
newExpanded.add(node.id);
|
|
40929
41495
|
const category = categories.find((cat) => cat.id === node.id);
|
|
40930
|
-
if (category && !clipMetadata[node.id]) {
|
|
41496
|
+
if (category && !clipMetadata[node.id] && !isCategoryExternallyManaged(node.id)) {
|
|
40931
41497
|
console.log(`[FileManager] Fetching clips for expanded category: ${node.id}`);
|
|
40932
41498
|
fetchClipMetadata(node.id, 1);
|
|
40933
41499
|
}
|
|
40934
|
-
if (showPercentileCycleFilters && node.id === "fast-cycles" && (percentileClips["fast-cycles"] || []).length === 0) {
|
|
41500
|
+
if (!isCategoryExternallyManaged(node.id) && showPercentileCycleFilters && node.id === "fast-cycles" && (percentileClips["fast-cycles"] || []).length === 0) {
|
|
40935
41501
|
fetchPercentileClips("fast-cycles");
|
|
40936
41502
|
}
|
|
40937
|
-
if (showPercentileCycleFilters && node.id === "slow-cycles" && (percentileClips["slow-cycles"] || []).length === 0) {
|
|
41503
|
+
if (!isCategoryExternallyManaged(node.id) && showPercentileCycleFilters && node.id === "slow-cycles" && (percentileClips["slow-cycles"] || []).length === 0) {
|
|
40938
41504
|
fetchPercentileClips("slow-cycles");
|
|
40939
41505
|
}
|
|
40940
41506
|
}
|
|
@@ -40987,6 +41553,9 @@ var FileManagerFilters = ({
|
|
|
40987
41553
|
const isCurrentVideo = currentVideoId === node.id;
|
|
40988
41554
|
const isCountUnknown = node.type === "percentile-category" && node.count === null;
|
|
40989
41555
|
const hasChildren = isCountUnknown || (node.count || 0) > 0;
|
|
41556
|
+
const showExternalLoadingState = Boolean(
|
|
41557
|
+
activeCategoryLoading && isExpanded && node.id === activeFilter && (node.type === "category" || node.type === "percentile-category")
|
|
41558
|
+
);
|
|
40990
41559
|
const colorClasses = node.color ? getColorClasses(node.color) : null;
|
|
40991
41560
|
return /* @__PURE__ */ jsxs("div", { className: "select-none animate-in", children: [
|
|
40992
41561
|
/* @__PURE__ */ jsxs(
|
|
@@ -41068,6 +41637,10 @@ var FileManagerFilters = ({
|
|
|
41068
41637
|
),
|
|
41069
41638
|
hasChildren && isExpanded && (node.type === "category" || node.type === "percentile-category") && /* @__PURE__ */ jsx("div", { className: "mt-2 ml-3 animate-in border-l-2 border-slate-100 pl-3", children: /* @__PURE__ */ jsxs("div", { className: "max-h-64 overflow-y-auto space-y-1 scrollbar-thin scrollbar-track-slate-100 scrollbar-thumb-slate-300", children: [
|
|
41070
41639
|
node.children.map((child) => renderNode(child, depth + 1)),
|
|
41640
|
+
showExternalLoadingState && /* @__PURE__ */ jsx("div", { className: "py-2 px-3 text-center", children: /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center text-sm text-slate-500", children: [
|
|
41641
|
+
/* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
41642
|
+
"Loading clips..."
|
|
41643
|
+
] }) }),
|
|
41071
41644
|
loadingCategories.has(`${node.id}-${(categoryPages[node.id] || 0) + 1}`) && /* @__PURE__ */ jsx("div", { className: "py-2 px-3 text-center", children: /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center text-sm text-slate-500", children: [
|
|
41072
41645
|
/* @__PURE__ */ jsx("div", { className: "animate-spin mr-2 h-4 w-4 border-2 border-slate-300 border-t-blue-500 rounded-full" }),
|
|
41073
41646
|
"Loading more clips..."
|
|
@@ -42540,6 +43113,7 @@ var BottlenecksContent = ({
|
|
|
42540
43113
|
category: categoryId,
|
|
42541
43114
|
page: 1,
|
|
42542
43115
|
limit: 100,
|
|
43116
|
+
knownTotal: mergedCounts[categoryId] ?? null,
|
|
42543
43117
|
snapshotDateTime,
|
|
42544
43118
|
snapshotClipId
|
|
42545
43119
|
}),
|
|
@@ -42556,7 +43130,7 @@ var BottlenecksContent = ({
|
|
|
42556
43130
|
metadataClips = categoryData.clips.map((clip, index) => ({
|
|
42557
43131
|
id: clip.id,
|
|
42558
43132
|
clipId: clip.id,
|
|
42559
|
-
clip_timestamp: clip.
|
|
43133
|
+
clip_timestamp: clip.creation_timestamp || clip.timestamp,
|
|
42560
43134
|
description: clip.description,
|
|
42561
43135
|
severity: clip.severity,
|
|
42562
43136
|
category: categoryId,
|
|
@@ -43194,6 +43768,14 @@ var BottlenecksContent = ({
|
|
|
43194
43768
|
}
|
|
43195
43769
|
return currentPosition;
|
|
43196
43770
|
}, [activeFilter, categoryMetadata.length, currentMetadataIndex, currentPosition, isPercentileCategory]);
|
|
43771
|
+
const prefetchedExplorerMetadata = useMemo(() => {
|
|
43772
|
+
if (!activeFilter || categoryMetadata.length === 0) {
|
|
43773
|
+
return void 0;
|
|
43774
|
+
}
|
|
43775
|
+
return {
|
|
43776
|
+
[activeFilter]: categoryMetadata
|
|
43777
|
+
};
|
|
43778
|
+
}, [activeFilter, categoryMetadata]);
|
|
43197
43779
|
const classificationClipIds = useMemo(() => {
|
|
43198
43780
|
if (!idleTimeVlmEnabled) {
|
|
43199
43781
|
return [];
|
|
@@ -43915,6 +44497,8 @@ var BottlenecksContent = ({
|
|
|
43915
44497
|
clipClassifications,
|
|
43916
44498
|
idleTimeVlmEnabled,
|
|
43917
44499
|
showPercentileCycleFilters: isFastSlowClipFiltersEnabled,
|
|
44500
|
+
prefetchedClipMetadata: prefetchedExplorerMetadata,
|
|
44501
|
+
activeCategoryLoading: isCategoryLoading,
|
|
43918
44502
|
onFilterChange: (filterId) => {
|
|
43919
44503
|
updateActiveFilter(filterId);
|
|
43920
44504
|
const category = categoriesToShow.find((cat) => cat.type === filterId);
|