@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.js
CHANGED
|
@@ -39220,6 +39220,456 @@ var MetricCard2 = ({ title, value, unit = "", trend = null }) => {
|
|
|
39220
39220
|
] });
|
|
39221
39221
|
};
|
|
39222
39222
|
var MetricCard_default = MetricCard2;
|
|
39223
|
+
var normalizeValue = (v) => {
|
|
39224
|
+
if (!v) return "";
|
|
39225
|
+
return v.substring(0, 5);
|
|
39226
|
+
};
|
|
39227
|
+
var to12h = (value24) => {
|
|
39228
|
+
const norm = normalizeValue(value24);
|
|
39229
|
+
if (!norm || norm.length < 5) return { hour: 12, minute: 0, period: "AM" };
|
|
39230
|
+
const [h, m] = norm.split(":").map(Number);
|
|
39231
|
+
const period = h >= 12 ? "PM" : "AM";
|
|
39232
|
+
let hour12 = h % 12;
|
|
39233
|
+
if (hour12 === 0) hour12 = 12;
|
|
39234
|
+
return { hour: hour12, minute: isNaN(m) ? 0 : m, period };
|
|
39235
|
+
};
|
|
39236
|
+
var to24h = (hour12, minute, period) => {
|
|
39237
|
+
let h = hour12;
|
|
39238
|
+
if (period === "AM" && h === 12) h = 0;
|
|
39239
|
+
if (period === "PM" && h !== 12) h += 12;
|
|
39240
|
+
return `${h.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}`;
|
|
39241
|
+
};
|
|
39242
|
+
var pad22 = (n) => n.toString().padStart(2, "0");
|
|
39243
|
+
var SegmentedTimeInput = ({
|
|
39244
|
+
hour,
|
|
39245
|
+
minute,
|
|
39246
|
+
period,
|
|
39247
|
+
hasValue,
|
|
39248
|
+
placeholder,
|
|
39249
|
+
disabled,
|
|
39250
|
+
activeSegment,
|
|
39251
|
+
onSegmentFocus,
|
|
39252
|
+
onSegmentBlur,
|
|
39253
|
+
onHourChange,
|
|
39254
|
+
onMinuteChange,
|
|
39255
|
+
onPeriodChange,
|
|
39256
|
+
onTogglePopover,
|
|
39257
|
+
isPopoverOpen
|
|
39258
|
+
}) => {
|
|
39259
|
+
const containerRef = React142.useRef(null);
|
|
39260
|
+
const digitBufferRef = React142.useRef("");
|
|
39261
|
+
const digitTimerRef = React142.useRef(null);
|
|
39262
|
+
React142.useEffect(() => {
|
|
39263
|
+
digitBufferRef.current = "";
|
|
39264
|
+
if (digitTimerRef.current) clearTimeout(digitTimerRef.current);
|
|
39265
|
+
}, [activeSegment]);
|
|
39266
|
+
const commitHourDigits = React142.useCallback((digits) => {
|
|
39267
|
+
const val = parseInt(digits, 10);
|
|
39268
|
+
if (val >= 1 && val <= 12) onHourChange(val);
|
|
39269
|
+
else if (val === 0) onHourChange(12);
|
|
39270
|
+
digitBufferRef.current = "";
|
|
39271
|
+
}, [onHourChange]);
|
|
39272
|
+
const commitMinuteDigits = React142.useCallback((digits) => {
|
|
39273
|
+
const val = parseInt(digits, 10);
|
|
39274
|
+
onMinuteChange(Math.min(59, Math.max(0, val)));
|
|
39275
|
+
digitBufferRef.current = "";
|
|
39276
|
+
}, [onMinuteChange]);
|
|
39277
|
+
const handleKeyDown = React142.useCallback((e) => {
|
|
39278
|
+
if (disabled || !activeSegment) return;
|
|
39279
|
+
const key = e.key;
|
|
39280
|
+
if (key === "Tab") {
|
|
39281
|
+
if (e.shiftKey) {
|
|
39282
|
+
if (activeSegment === "minute") {
|
|
39283
|
+
e.preventDefault();
|
|
39284
|
+
onSegmentFocus("hour");
|
|
39285
|
+
} else if (activeSegment === "period") {
|
|
39286
|
+
e.preventDefault();
|
|
39287
|
+
onSegmentFocus("minute");
|
|
39288
|
+
}
|
|
39289
|
+
} else {
|
|
39290
|
+
if (activeSegment === "hour") {
|
|
39291
|
+
e.preventDefault();
|
|
39292
|
+
onSegmentFocus("minute");
|
|
39293
|
+
} else if (activeSegment === "minute") {
|
|
39294
|
+
e.preventDefault();
|
|
39295
|
+
onSegmentFocus("period");
|
|
39296
|
+
}
|
|
39297
|
+
}
|
|
39298
|
+
return;
|
|
39299
|
+
}
|
|
39300
|
+
e.preventDefault();
|
|
39301
|
+
if (key === "ArrowUp" || key === "ArrowDown") {
|
|
39302
|
+
const delta = key === "ArrowUp" ? 1 : -1;
|
|
39303
|
+
if (activeSegment === "hour") {
|
|
39304
|
+
let newH = hour + delta;
|
|
39305
|
+
if (newH > 12) newH = 1;
|
|
39306
|
+
if (newH < 1) newH = 12;
|
|
39307
|
+
onHourChange(newH);
|
|
39308
|
+
} else if (activeSegment === "minute") {
|
|
39309
|
+
let newM = minute + delta;
|
|
39310
|
+
if (newM > 59) newM = 0;
|
|
39311
|
+
if (newM < 0) newM = 59;
|
|
39312
|
+
onMinuteChange(newM);
|
|
39313
|
+
} else if (activeSegment === "period") {
|
|
39314
|
+
onPeriodChange(period === "AM" ? "PM" : "AM");
|
|
39315
|
+
}
|
|
39316
|
+
return;
|
|
39317
|
+
}
|
|
39318
|
+
if (key === "Enter" || key === " ") {
|
|
39319
|
+
onTogglePopover();
|
|
39320
|
+
return;
|
|
39321
|
+
}
|
|
39322
|
+
if (key === "Escape") {
|
|
39323
|
+
onSegmentBlur();
|
|
39324
|
+
return;
|
|
39325
|
+
}
|
|
39326
|
+
if (activeSegment === "period") {
|
|
39327
|
+
if (key.toLowerCase() === "a") onPeriodChange("AM");
|
|
39328
|
+
else if (key.toLowerCase() === "p") onPeriodChange("PM");
|
|
39329
|
+
return;
|
|
39330
|
+
}
|
|
39331
|
+
if (key >= "0" && key <= "9") {
|
|
39332
|
+
if (digitTimerRef.current) clearTimeout(digitTimerRef.current);
|
|
39333
|
+
if (activeSegment === "hour") {
|
|
39334
|
+
digitBufferRef.current += key;
|
|
39335
|
+
if (digitBufferRef.current.length >= 2) {
|
|
39336
|
+
commitHourDigits(digitBufferRef.current);
|
|
39337
|
+
onSegmentFocus("minute");
|
|
39338
|
+
} else {
|
|
39339
|
+
const firstDigit = parseInt(key, 10);
|
|
39340
|
+
if (firstDigit >= 2) {
|
|
39341
|
+
commitHourDigits(digitBufferRef.current);
|
|
39342
|
+
onSegmentFocus("minute");
|
|
39343
|
+
} else {
|
|
39344
|
+
digitTimerRef.current = setTimeout(() => {
|
|
39345
|
+
commitHourDigits(digitBufferRef.current);
|
|
39346
|
+
onSegmentFocus("minute");
|
|
39347
|
+
}, 800);
|
|
39348
|
+
}
|
|
39349
|
+
}
|
|
39350
|
+
} else if (activeSegment === "minute") {
|
|
39351
|
+
digitBufferRef.current += key;
|
|
39352
|
+
if (digitBufferRef.current.length >= 2) {
|
|
39353
|
+
commitMinuteDigits(digitBufferRef.current);
|
|
39354
|
+
onSegmentFocus("period");
|
|
39355
|
+
} else {
|
|
39356
|
+
const firstDigit = parseInt(key, 10);
|
|
39357
|
+
if (firstDigit >= 6) {
|
|
39358
|
+
commitMinuteDigits("0" + key);
|
|
39359
|
+
onSegmentFocus("period");
|
|
39360
|
+
} else {
|
|
39361
|
+
digitTimerRef.current = setTimeout(() => {
|
|
39362
|
+
commitMinuteDigits(digitBufferRef.current.padStart(2, "0"));
|
|
39363
|
+
onSegmentFocus("period");
|
|
39364
|
+
}, 800);
|
|
39365
|
+
}
|
|
39366
|
+
}
|
|
39367
|
+
}
|
|
39368
|
+
}
|
|
39369
|
+
}, [disabled, activeSegment, hour, minute, period, onHourChange, onMinuteChange, onPeriodChange, onSegmentFocus, onSegmentBlur, onTogglePopover, commitHourDigits, commitMinuteDigits]);
|
|
39370
|
+
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"}`;
|
|
39371
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
39372
|
+
"div",
|
|
39373
|
+
{
|
|
39374
|
+
ref: containerRef,
|
|
39375
|
+
tabIndex: disabled ? -1 : 0,
|
|
39376
|
+
onFocus: () => {
|
|
39377
|
+
if (!activeSegment && !disabled) onSegmentFocus("hour");
|
|
39378
|
+
},
|
|
39379
|
+
onKeyDown: handleKeyDown,
|
|
39380
|
+
className: "flex items-center gap-0 outline-none flex-1 min-w-0",
|
|
39381
|
+
children: hasValue ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center text-sm tabular-nums text-gray-900", children: [
|
|
39382
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
39383
|
+
"span",
|
|
39384
|
+
{
|
|
39385
|
+
onClick: (e) => {
|
|
39386
|
+
e.stopPropagation();
|
|
39387
|
+
if (!disabled) onSegmentFocus("hour");
|
|
39388
|
+
},
|
|
39389
|
+
className: segmentClass("hour"),
|
|
39390
|
+
role: "spinbutton",
|
|
39391
|
+
"aria-label": "Hour",
|
|
39392
|
+
"aria-valuenow": hour,
|
|
39393
|
+
"aria-valuemin": 1,
|
|
39394
|
+
"aria-valuemax": 12,
|
|
39395
|
+
children: pad22(hour)
|
|
39396
|
+
}
|
|
39397
|
+
),
|
|
39398
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-400 mx-px", children: ":" }),
|
|
39399
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
39400
|
+
"span",
|
|
39401
|
+
{
|
|
39402
|
+
onClick: (e) => {
|
|
39403
|
+
e.stopPropagation();
|
|
39404
|
+
if (!disabled) onSegmentFocus("minute");
|
|
39405
|
+
},
|
|
39406
|
+
className: segmentClass("minute"),
|
|
39407
|
+
role: "spinbutton",
|
|
39408
|
+
"aria-label": "Minute",
|
|
39409
|
+
"aria-valuenow": minute,
|
|
39410
|
+
"aria-valuemin": 0,
|
|
39411
|
+
"aria-valuemax": 59,
|
|
39412
|
+
children: pad22(minute)
|
|
39413
|
+
}
|
|
39414
|
+
),
|
|
39415
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
39416
|
+
"span",
|
|
39417
|
+
{
|
|
39418
|
+
onClick: (e) => {
|
|
39419
|
+
e.stopPropagation();
|
|
39420
|
+
if (!disabled) onSegmentFocus("period");
|
|
39421
|
+
},
|
|
39422
|
+
className: `${segmentClass("period")} ml-1 text-gray-500`,
|
|
39423
|
+
role: "spinbutton",
|
|
39424
|
+
"aria-label": "AM or PM",
|
|
39425
|
+
"aria-valuenow": period === "AM" ? 0 : 1,
|
|
39426
|
+
"aria-valuemin": 0,
|
|
39427
|
+
"aria-valuemax": 1,
|
|
39428
|
+
children: period
|
|
39429
|
+
}
|
|
39430
|
+
)
|
|
39431
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-400 select-none", children: placeholder })
|
|
39432
|
+
}
|
|
39433
|
+
);
|
|
39434
|
+
};
|
|
39435
|
+
var SCROLLBAR_HIDE_ID = "tp-scrollbar-hide";
|
|
39436
|
+
var injectScrollbarHideCSS = () => {
|
|
39437
|
+
if (typeof document === "undefined") return;
|
|
39438
|
+
if (document.getElementById(SCROLLBAR_HIDE_ID)) return;
|
|
39439
|
+
const style = document.createElement("style");
|
|
39440
|
+
style.id = SCROLLBAR_HIDE_ID;
|
|
39441
|
+
style.textContent = ".tp-scroll-hide::-webkit-scrollbar{display:none}";
|
|
39442
|
+
document.head.appendChild(style);
|
|
39443
|
+
};
|
|
39444
|
+
var ITEM_H = 40;
|
|
39445
|
+
var VISIBLE = 5;
|
|
39446
|
+
var WHEEL_H = ITEM_H * VISIBLE;
|
|
39447
|
+
var PAD = Math.floor(VISIBLE / 2);
|
|
39448
|
+
var ScrollColumn = ({ items, selected, onSelect, width = 56 }) => {
|
|
39449
|
+
const elRef = React142.useRef(null);
|
|
39450
|
+
const suppressRef = React142.useRef(false);
|
|
39451
|
+
const snapTimerRef = React142.useRef(null);
|
|
39452
|
+
const mountedRef = React142.useRef(false);
|
|
39453
|
+
const dragging = React142.useRef(false);
|
|
39454
|
+
const dragStartY = React142.useRef(0);
|
|
39455
|
+
const dragStartScroll = React142.useRef(0);
|
|
39456
|
+
React142.useEffect(() => {
|
|
39457
|
+
injectScrollbarHideCSS();
|
|
39458
|
+
}, []);
|
|
39459
|
+
React142.useEffect(() => {
|
|
39460
|
+
const idx = items.findIndex((i) => i.value === selected);
|
|
39461
|
+
if (idx < 0 || !elRef.current || suppressRef.current) return;
|
|
39462
|
+
const target = idx * ITEM_H;
|
|
39463
|
+
if (!mountedRef.current) {
|
|
39464
|
+
suppressRef.current = true;
|
|
39465
|
+
elRef.current.scrollTop = target;
|
|
39466
|
+
setTimeout(() => {
|
|
39467
|
+
if (elRef.current) elRef.current.scrollTop = target;
|
|
39468
|
+
setTimeout(() => {
|
|
39469
|
+
suppressRef.current = false;
|
|
39470
|
+
mountedRef.current = true;
|
|
39471
|
+
}, 200);
|
|
39472
|
+
}, 30);
|
|
39473
|
+
} else {
|
|
39474
|
+
elRef.current.scrollTo({ top: target, behavior: "smooth" });
|
|
39475
|
+
}
|
|
39476
|
+
}, [selected, items]);
|
|
39477
|
+
const scheduleSnap = React142.useCallback(() => {
|
|
39478
|
+
if (snapTimerRef.current) clearTimeout(snapTimerRef.current);
|
|
39479
|
+
snapTimerRef.current = setTimeout(() => {
|
|
39480
|
+
if (!elRef.current || suppressRef.current) return;
|
|
39481
|
+
const idx = Math.round(elRef.current.scrollTop / ITEM_H);
|
|
39482
|
+
const clamped = Math.max(0, Math.min(items.length - 1, idx));
|
|
39483
|
+
suppressRef.current = true;
|
|
39484
|
+
elRef.current.scrollTo({ top: clamped * ITEM_H, behavior: "smooth" });
|
|
39485
|
+
const item = items[clamped];
|
|
39486
|
+
if (item && item.value !== selected) onSelect(item.value);
|
|
39487
|
+
setTimeout(() => {
|
|
39488
|
+
suppressRef.current = false;
|
|
39489
|
+
}, 150);
|
|
39490
|
+
}, 100);
|
|
39491
|
+
}, [items, selected, onSelect]);
|
|
39492
|
+
const onScroll = React142.useCallback(() => {
|
|
39493
|
+
if (suppressRef.current) return;
|
|
39494
|
+
scheduleSnap();
|
|
39495
|
+
}, [scheduleSnap]);
|
|
39496
|
+
const onMouseDown = React142.useCallback((e) => {
|
|
39497
|
+
dragging.current = true;
|
|
39498
|
+
dragStartY.current = e.clientY;
|
|
39499
|
+
dragStartScroll.current = elRef.current?.scrollTop ?? 0;
|
|
39500
|
+
e.preventDefault();
|
|
39501
|
+
const onMove = (ev) => {
|
|
39502
|
+
if (!dragging.current || !elRef.current) return;
|
|
39503
|
+
const dy = dragStartY.current - ev.clientY;
|
|
39504
|
+
elRef.current.scrollTop = dragStartScroll.current + dy;
|
|
39505
|
+
};
|
|
39506
|
+
const onUp = () => {
|
|
39507
|
+
dragging.current = false;
|
|
39508
|
+
scheduleSnap();
|
|
39509
|
+
document.removeEventListener("mousemove", onMove);
|
|
39510
|
+
document.removeEventListener("mouseup", onUp);
|
|
39511
|
+
};
|
|
39512
|
+
document.addEventListener("mousemove", onMove);
|
|
39513
|
+
document.addEventListener("mouseup", onUp);
|
|
39514
|
+
}, [scheduleSnap]);
|
|
39515
|
+
const onTouchStart = React142.useCallback((e) => {
|
|
39516
|
+
dragging.current = true;
|
|
39517
|
+
dragStartY.current = e.touches[0].clientY;
|
|
39518
|
+
dragStartScroll.current = elRef.current?.scrollTop ?? 0;
|
|
39519
|
+
}, []);
|
|
39520
|
+
const onTouchMove = React142.useCallback((e) => {
|
|
39521
|
+
if (!dragging.current || !elRef.current) return;
|
|
39522
|
+
const dy = dragStartY.current - e.touches[0].clientY;
|
|
39523
|
+
elRef.current.scrollTop = dragStartScroll.current + dy;
|
|
39524
|
+
e.preventDefault();
|
|
39525
|
+
}, []);
|
|
39526
|
+
const onTouchEnd = React142.useCallback(() => {
|
|
39527
|
+
dragging.current = false;
|
|
39528
|
+
scheduleSnap();
|
|
39529
|
+
}, [scheduleSnap]);
|
|
39530
|
+
const handleClick = React142.useCallback((value, idx) => {
|
|
39531
|
+
onSelect(value);
|
|
39532
|
+
if (elRef.current) {
|
|
39533
|
+
suppressRef.current = true;
|
|
39534
|
+
elRef.current.scrollTo({ top: idx * ITEM_H, behavior: "smooth" });
|
|
39535
|
+
setTimeout(() => {
|
|
39536
|
+
suppressRef.current = false;
|
|
39537
|
+
}, 250);
|
|
39538
|
+
}
|
|
39539
|
+
}, [onSelect]);
|
|
39540
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative select-none", style: { width, height: WHEEL_H }, children: [
|
|
39541
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
39542
|
+
"div",
|
|
39543
|
+
{
|
|
39544
|
+
className: "absolute left-1 right-1 rounded-lg bg-blue-50/80 border border-blue-200/60 pointer-events-none z-0",
|
|
39545
|
+
style: { top: PAD * ITEM_H, height: ITEM_H }
|
|
39546
|
+
}
|
|
39547
|
+
),
|
|
39548
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
39549
|
+
"div",
|
|
39550
|
+
{
|
|
39551
|
+
className: "absolute inset-x-0 top-0 pointer-events-none z-10",
|
|
39552
|
+
style: { height: ITEM_H * 1.8, background: "linear-gradient(to bottom, white 0%, rgba(255,255,255,0.85) 50%, transparent 100%)" }
|
|
39553
|
+
}
|
|
39554
|
+
),
|
|
39555
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
39556
|
+
"div",
|
|
39557
|
+
{
|
|
39558
|
+
className: "absolute inset-x-0 bottom-0 pointer-events-none z-10",
|
|
39559
|
+
style: { height: ITEM_H * 1.8, background: "linear-gradient(to top, white 0%, rgba(255,255,255,0.85) 50%, transparent 100%)" }
|
|
39560
|
+
}
|
|
39561
|
+
),
|
|
39562
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
39563
|
+
"div",
|
|
39564
|
+
{
|
|
39565
|
+
ref: elRef,
|
|
39566
|
+
onScroll,
|
|
39567
|
+
onMouseDown,
|
|
39568
|
+
onTouchStart,
|
|
39569
|
+
onTouchMove,
|
|
39570
|
+
onTouchEnd,
|
|
39571
|
+
className: "h-full overflow-y-auto tp-scroll-hide relative z-[1] cursor-grab active:cursor-grabbing",
|
|
39572
|
+
style: { scrollbarWidth: "none", msOverflowStyle: "none" },
|
|
39573
|
+
role: "listbox",
|
|
39574
|
+
children: [
|
|
39575
|
+
Array.from({ length: PAD }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: ITEM_H }, "aria-hidden": true }, `pt-${i}`)),
|
|
39576
|
+
items.map((item, idx) => {
|
|
39577
|
+
const isSel = item.value === selected;
|
|
39578
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
39579
|
+
"div",
|
|
39580
|
+
{
|
|
39581
|
+
onClick: () => handleClick(item.value, idx),
|
|
39582
|
+
className: `flex items-center justify-center transition-all duration-100 ${isSel ? "text-gray-900 font-semibold text-[15px]" : "text-gray-300 text-sm"}`,
|
|
39583
|
+
style: { height: ITEM_H },
|
|
39584
|
+
role: "option",
|
|
39585
|
+
"aria-selected": isSel,
|
|
39586
|
+
children: item.label
|
|
39587
|
+
},
|
|
39588
|
+
item.value
|
|
39589
|
+
);
|
|
39590
|
+
}),
|
|
39591
|
+
Array.from({ length: PAD }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: ITEM_H }, "aria-hidden": true }, `pb-${i}`))
|
|
39592
|
+
]
|
|
39593
|
+
}
|
|
39594
|
+
)
|
|
39595
|
+
] });
|
|
39596
|
+
};
|
|
39597
|
+
var HOURS = Array.from({ length: 12 }, (_, i) => ({ value: i + 1, label: (i + 1).toString() }));
|
|
39598
|
+
var MINUTES = Array.from({ length: 60 }, (_, i) => ({ value: i, label: pad22(i) }));
|
|
39599
|
+
var TimePopover = ({
|
|
39600
|
+
hour,
|
|
39601
|
+
minute,
|
|
39602
|
+
period,
|
|
39603
|
+
onHourChange,
|
|
39604
|
+
onMinuteChange,
|
|
39605
|
+
onPeriodChange,
|
|
39606
|
+
onClose,
|
|
39607
|
+
onNow
|
|
39608
|
+
}) => {
|
|
39609
|
+
const bandCenter = PAD * ITEM_H + ITEM_H / 2;
|
|
39610
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
39611
|
+
"div",
|
|
39612
|
+
{
|
|
39613
|
+
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",
|
|
39614
|
+
role: "dialog",
|
|
39615
|
+
"aria-label": "Choose time",
|
|
39616
|
+
onClick: (e) => e.stopPropagation(),
|
|
39617
|
+
children: [
|
|
39618
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-center px-4 pt-4 pb-2", children: [
|
|
39619
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScrollColumn, { items: HOURS, selected: hour, onSelect: (v) => onHourChange(v), width: 52 }),
|
|
39620
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
39621
|
+
"div",
|
|
39622
|
+
{
|
|
39623
|
+
className: "text-gray-300 text-lg font-light flex-shrink-0 w-4 text-center select-none",
|
|
39624
|
+
style: { marginTop: bandCenter - 12 },
|
|
39625
|
+
children: ":"
|
|
39626
|
+
}
|
|
39627
|
+
),
|
|
39628
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScrollColumn, { items: MINUTES, selected: minute, onSelect: (v) => onMinuteChange(v), width: 52 }),
|
|
39629
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
39630
|
+
"div",
|
|
39631
|
+
{
|
|
39632
|
+
className: "flex flex-col gap-1.5 ml-3 flex-shrink-0",
|
|
39633
|
+
style: { marginTop: bandCenter - 38 },
|
|
39634
|
+
children: ["AM", "PM"].map((p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
39635
|
+
"button",
|
|
39636
|
+
{
|
|
39637
|
+
type: "button",
|
|
39638
|
+
onClick: () => onPeriodChange(p),
|
|
39639
|
+
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"}`,
|
|
39640
|
+
"aria-pressed": period === p,
|
|
39641
|
+
children: p
|
|
39642
|
+
},
|
|
39643
|
+
p
|
|
39644
|
+
))
|
|
39645
|
+
}
|
|
39646
|
+
)
|
|
39647
|
+
] }),
|
|
39648
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-4 border-t border-gray-100" }),
|
|
39649
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-2.5", children: [
|
|
39650
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
39651
|
+
"button",
|
|
39652
|
+
{
|
|
39653
|
+
type: "button",
|
|
39654
|
+
onClick: onNow,
|
|
39655
|
+
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",
|
|
39656
|
+
children: "Now"
|
|
39657
|
+
}
|
|
39658
|
+
),
|
|
39659
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
39660
|
+
"button",
|
|
39661
|
+
{
|
|
39662
|
+
type: "button",
|
|
39663
|
+
onClick: onClose,
|
|
39664
|
+
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",
|
|
39665
|
+
children: "Done"
|
|
39666
|
+
}
|
|
39667
|
+
)
|
|
39668
|
+
] })
|
|
39669
|
+
]
|
|
39670
|
+
}
|
|
39671
|
+
);
|
|
39672
|
+
};
|
|
39223
39673
|
var TimePickerDropdown = ({
|
|
39224
39674
|
value,
|
|
39225
39675
|
onChange,
|
|
@@ -39227,124 +39677,155 @@ var TimePickerDropdown = ({
|
|
|
39227
39677
|
className = "",
|
|
39228
39678
|
disabled = false
|
|
39229
39679
|
}) => {
|
|
39230
|
-
const [
|
|
39231
|
-
const [
|
|
39232
|
-
const
|
|
39233
|
-
const
|
|
39234
|
-
const
|
|
39235
|
-
|
|
39236
|
-
for (let hour = 0; hour < 24; hour++) {
|
|
39237
|
-
for (let minute = 0; minute < 60; minute += 10) {
|
|
39238
|
-
const time24 = `${hour.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}`;
|
|
39239
|
-
const hour12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
|
|
39240
|
-
const ampm = hour < 12 ? "AM" : "PM";
|
|
39241
|
-
const time12 = `${hour12}:${minute.toString().padStart(2, "0")} ${ampm}`;
|
|
39242
|
-
slots.push({ value: time24, label: time12 });
|
|
39243
|
-
}
|
|
39244
|
-
}
|
|
39245
|
-
return slots;
|
|
39246
|
-
};
|
|
39247
|
-
const timeSlots = generateTimeSlots();
|
|
39248
|
-
const filteredSlots = timeSlots.filter(
|
|
39249
|
-
(slot) => slot.label.toLowerCase().includes(searchTerm.toLowerCase())
|
|
39250
|
-
);
|
|
39251
|
-
const getDisplayValue = (value2) => {
|
|
39252
|
-
if (!value2) return "";
|
|
39253
|
-
const normalizedValue = value2.substring(0, 5);
|
|
39254
|
-
const slot = timeSlots.find((s) => s.value === normalizedValue);
|
|
39255
|
-
return slot ? slot.label : value2;
|
|
39256
|
-
};
|
|
39680
|
+
const [isPopoverOpen, setIsPopoverOpen] = React142.useState(false);
|
|
39681
|
+
const [activeSegment, setActiveSegment] = React142.useState(null);
|
|
39682
|
+
const containerRef = React142.useRef(null);
|
|
39683
|
+
const normalizedValue = React142.useMemo(() => normalizeValue(value), [value]);
|
|
39684
|
+
const hasValue = normalizedValue.length === 5 && normalizedValue.includes(":");
|
|
39685
|
+
const { hour, minute, period } = React142.useMemo(() => to12h(normalizedValue), [normalizedValue]);
|
|
39257
39686
|
React142.useEffect(() => {
|
|
39258
39687
|
const handleClickOutside = (event) => {
|
|
39259
|
-
if (
|
|
39260
|
-
|
|
39261
|
-
|
|
39688
|
+
if (containerRef.current && !containerRef.current.contains(event.target)) {
|
|
39689
|
+
setIsPopoverOpen(false);
|
|
39690
|
+
setActiveSegment(null);
|
|
39262
39691
|
}
|
|
39263
39692
|
};
|
|
39264
39693
|
document.addEventListener("mousedown", handleClickOutside);
|
|
39265
39694
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
39266
39695
|
}, []);
|
|
39267
|
-
const
|
|
39268
|
-
|
|
39269
|
-
|
|
39270
|
-
|
|
39271
|
-
|
|
39272
|
-
|
|
39273
|
-
|
|
39274
|
-
|
|
39275
|
-
|
|
39276
|
-
|
|
39277
|
-
|
|
39696
|
+
const emitChange = React142.useCallback((h, m, p) => {
|
|
39697
|
+
onChange(to24h(h, m, p));
|
|
39698
|
+
}, [onChange]);
|
|
39699
|
+
const handleHourChange = React142.useCallback((h) => {
|
|
39700
|
+
emitChange(h, minute, period);
|
|
39701
|
+
}, [emitChange, minute, period]);
|
|
39702
|
+
const handleMinuteChange = React142.useCallback((m) => {
|
|
39703
|
+
emitChange(hour, m, period);
|
|
39704
|
+
}, [emitChange, hour, period]);
|
|
39705
|
+
const handlePeriodChange = React142.useCallback((p) => {
|
|
39706
|
+
emitChange(hour, minute, p);
|
|
39707
|
+
}, [emitChange, hour, minute]);
|
|
39708
|
+
const handleNow = React142.useCallback(() => {
|
|
39709
|
+
const now4 = /* @__PURE__ */ new Date();
|
|
39710
|
+
const h24 = now4.getHours();
|
|
39711
|
+
const m = now4.getMinutes();
|
|
39712
|
+
const p = h24 >= 12 ? "PM" : "AM";
|
|
39713
|
+
let h12 = h24 % 12;
|
|
39714
|
+
if (h12 === 0) h12 = 12;
|
|
39715
|
+
emitChange(h12, m, p);
|
|
39716
|
+
}, [emitChange]);
|
|
39717
|
+
const handleSegmentFocus = React142.useCallback((seg) => {
|
|
39718
|
+
setActiveSegment(seg);
|
|
39719
|
+
if (!hasValue) {
|
|
39720
|
+
onChange(to24h(12, 0, "AM"));
|
|
39721
|
+
}
|
|
39722
|
+
}, [hasValue, onChange]);
|
|
39723
|
+
const handleSegmentBlur = React142.useCallback(() => {
|
|
39724
|
+
setActiveSegment(null);
|
|
39725
|
+
}, []);
|
|
39726
|
+
const togglePopover = React142.useCallback(() => {
|
|
39727
|
+
if (disabled) return;
|
|
39728
|
+
setIsPopoverOpen((prev) => !prev);
|
|
39729
|
+
if (!hasValue) {
|
|
39730
|
+
onChange(to24h(12, 0, "AM"));
|
|
39278
39731
|
}
|
|
39279
|
-
};
|
|
39280
|
-
const
|
|
39281
|
-
onChange(timeValue);
|
|
39282
|
-
setIsOpen(false);
|
|
39283
|
-
setSearchTerm("");
|
|
39284
|
-
};
|
|
39285
|
-
const handleToggle = () => {
|
|
39732
|
+
}, [disabled, hasValue, onChange]);
|
|
39733
|
+
const handleContainerClick = React142.useCallback(() => {
|
|
39286
39734
|
if (disabled) return;
|
|
39287
|
-
|
|
39288
|
-
|
|
39289
|
-
|
|
39735
|
+
if (!activeSegment) {
|
|
39736
|
+
setActiveSegment("hour");
|
|
39737
|
+
if (!hasValue) {
|
|
39738
|
+
onChange(to24h(12, 0, "AM"));
|
|
39739
|
+
}
|
|
39290
39740
|
}
|
|
39291
|
-
};
|
|
39292
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `relative ${className}`, ref:
|
|
39293
|
-
/* @__PURE__ */ jsxRuntime.
|
|
39294
|
-
"
|
|
39741
|
+
}, [disabled, activeSegment, hasValue, onChange]);
|
|
39742
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `relative ${className}`, ref: containerRef, children: [
|
|
39743
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
39744
|
+
"div",
|
|
39295
39745
|
{
|
|
39296
|
-
|
|
39297
|
-
onClick: handleToggle,
|
|
39298
|
-
disabled,
|
|
39746
|
+
onClick: handleContainerClick,
|
|
39299
39747
|
className: `
|
|
39300
|
-
w-full px-3 py-2
|
|
39301
|
-
|
|
39302
|
-
|
|
39303
|
-
${disabled ? "bg-gray-50 cursor-not-allowed" : "cursor-pointer"}
|
|
39304
|
-
${
|
|
39748
|
+
w-full px-3 py-2 bg-white border rounded-md shadow-sm
|
|
39749
|
+
flex items-center gap-2
|
|
39750
|
+
transition-all duration-200
|
|
39751
|
+
${disabled ? "bg-gray-50 cursor-not-allowed border-gray-200" : "cursor-pointer border-gray-300 hover:border-gray-400"}
|
|
39752
|
+
${activeSegment || isPopoverOpen ? "ring-2 ring-blue-500 border-blue-500" : ""}
|
|
39305
39753
|
`,
|
|
39306
|
-
|
|
39307
|
-
|
|
39308
|
-
|
|
39309
|
-
|
|
39310
|
-
|
|
39754
|
+
role: "group",
|
|
39755
|
+
"aria-label": "Time picker",
|
|
39756
|
+
children: [
|
|
39757
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
39758
|
+
"button",
|
|
39759
|
+
{
|
|
39760
|
+
type: "button",
|
|
39761
|
+
onClick: (e) => {
|
|
39762
|
+
e.stopPropagation();
|
|
39763
|
+
togglePopover();
|
|
39764
|
+
},
|
|
39765
|
+
disabled,
|
|
39766
|
+
className: "text-gray-400 hover:text-blue-500 transition-colors flex-shrink-0 focus:outline-none",
|
|
39767
|
+
"aria-expanded": isPopoverOpen,
|
|
39768
|
+
"aria-haspopup": "dialog",
|
|
39769
|
+
"aria-label": "Open time picker",
|
|
39770
|
+
tabIndex: -1,
|
|
39771
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-4 w-4" })
|
|
39772
|
+
}
|
|
39773
|
+
),
|
|
39311
39774
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
39312
|
-
|
|
39775
|
+
SegmentedTimeInput,
|
|
39313
39776
|
{
|
|
39314
|
-
|
|
39777
|
+
hour,
|
|
39778
|
+
minute,
|
|
39779
|
+
period,
|
|
39780
|
+
hasValue,
|
|
39781
|
+
placeholder,
|
|
39782
|
+
disabled,
|
|
39783
|
+
activeSegment,
|
|
39784
|
+
onSegmentFocus: handleSegmentFocus,
|
|
39785
|
+
onSegmentBlur: handleSegmentBlur,
|
|
39786
|
+
onHourChange: handleHourChange,
|
|
39787
|
+
onMinuteChange: handleMinuteChange,
|
|
39788
|
+
onPeriodChange: handlePeriodChange,
|
|
39789
|
+
onTogglePopover: togglePopover,
|
|
39790
|
+
isPopoverOpen
|
|
39791
|
+
}
|
|
39792
|
+
),
|
|
39793
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
39794
|
+
"button",
|
|
39795
|
+
{
|
|
39796
|
+
type: "button",
|
|
39797
|
+
onClick: (e) => {
|
|
39798
|
+
e.stopPropagation();
|
|
39799
|
+
togglePopover();
|
|
39800
|
+
},
|
|
39801
|
+
disabled,
|
|
39802
|
+
className: "text-gray-400 hover:text-gray-600 transition-transform duration-200 flex-shrink-0 focus:outline-none",
|
|
39803
|
+
tabIndex: -1,
|
|
39804
|
+
"aria-hidden": "true",
|
|
39805
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
39806
|
+
lucideReact.ChevronDown,
|
|
39807
|
+
{
|
|
39808
|
+
className: `h-4 w-4 transition-transform duration-200 ${isPopoverOpen ? "rotate-180" : ""}`
|
|
39809
|
+
}
|
|
39810
|
+
)
|
|
39315
39811
|
}
|
|
39316
39812
|
)
|
|
39317
|
-
]
|
|
39813
|
+
]
|
|
39318
39814
|
}
|
|
39319
39815
|
),
|
|
39320
|
-
|
|
39321
|
-
|
|
39322
|
-
|
|
39323
|
-
|
|
39324
|
-
|
|
39325
|
-
|
|
39326
|
-
|
|
39327
|
-
|
|
39328
|
-
|
|
39329
|
-
|
|
39330
|
-
|
|
39331
|
-
|
|
39332
|
-
|
|
39333
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-y-auto max-h-48", children: filteredSlots.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 text-sm text-gray-500 text-center", children: "No times found" }) : filteredSlots.map((slot) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
39334
|
-
"button",
|
|
39335
|
-
{
|
|
39336
|
-
type: "button",
|
|
39337
|
-
onClick: () => handleSelect(slot.value),
|
|
39338
|
-
className: `
|
|
39339
|
-
w-full px-3 py-2 text-left text-sm hover:bg-blue-50 hover:text-blue-600
|
|
39340
|
-
transition-colors duration-150 border-b border-gray-100 last:border-b-0
|
|
39341
|
-
${slot.value === value ? "bg-blue-50 text-blue-600 font-medium" : "text-gray-700"}
|
|
39342
|
-
`,
|
|
39343
|
-
children: slot.label
|
|
39344
|
-
},
|
|
39345
|
-
slot.value
|
|
39346
|
-
)) })
|
|
39347
|
-
] })
|
|
39816
|
+
isPopoverOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
39817
|
+
TimePopover,
|
|
39818
|
+
{
|
|
39819
|
+
hour,
|
|
39820
|
+
minute,
|
|
39821
|
+
period,
|
|
39822
|
+
onHourChange: handleHourChange,
|
|
39823
|
+
onMinuteChange: handleMinuteChange,
|
|
39824
|
+
onPeriodChange: handlePeriodChange,
|
|
39825
|
+
onClose: () => setIsPopoverOpen(false),
|
|
39826
|
+
onNow: handleNow
|
|
39827
|
+
}
|
|
39828
|
+
)
|
|
39348
39829
|
] });
|
|
39349
39830
|
};
|
|
39350
39831
|
var SilentErrorBoundary = class extends React142__namespace.default.Component {
|
|
@@ -40082,6 +40563,7 @@ var AvatarUpload = ({
|
|
|
40082
40563
|
)
|
|
40083
40564
|
] });
|
|
40084
40565
|
};
|
|
40566
|
+
var CLIP_METADATA_PAGE_SIZE = 50;
|
|
40085
40567
|
var parseCycleTime = (value) => {
|
|
40086
40568
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
40087
40569
|
return value;
|
|
@@ -40168,7 +40650,9 @@ var FileManagerFilters = ({
|
|
|
40168
40650
|
className = "",
|
|
40169
40651
|
targetCycleTime = null,
|
|
40170
40652
|
idleTimeVlmEnabled = false,
|
|
40171
|
-
showPercentileCycleFilters = true
|
|
40653
|
+
showPercentileCycleFilters = true,
|
|
40654
|
+
prefetchedClipMetadata,
|
|
40655
|
+
activeCategoryLoading
|
|
40172
40656
|
}) => {
|
|
40173
40657
|
const [expandedNodes, setExpandedNodes] = React142.useState(/* @__PURE__ */ new Set());
|
|
40174
40658
|
const [startTime, setStartTime] = React142.useState("");
|
|
@@ -40189,10 +40673,83 @@ var FileManagerFilters = ({
|
|
|
40189
40673
|
const [categoryPages, setCategoryPages] = React142.useState({});
|
|
40190
40674
|
const [categoryHasMore, setCategoryHasMore] = React142.useState({});
|
|
40191
40675
|
const [localClipClassifications, setLocalClipClassifications] = React142.useState({});
|
|
40676
|
+
const clipMetadataRef = React142.useRef({});
|
|
40677
|
+
const inFlightMetadataRequestsRef = React142.useRef(/* @__PURE__ */ new Set());
|
|
40192
40678
|
const mergedClipClassifications = React142.useMemo(() => ({
|
|
40193
40679
|
...clipClassifications || {},
|
|
40194
40680
|
...localClipClassifications
|
|
40195
40681
|
}), [clipClassifications, localClipClassifications]);
|
|
40682
|
+
React142.useEffect(() => {
|
|
40683
|
+
clipMetadataRef.current = clipMetadata;
|
|
40684
|
+
}, [clipMetadata]);
|
|
40685
|
+
const isCategoryExternallyManaged = React142.useCallback((categoryId) => {
|
|
40686
|
+
if (!categoryId) {
|
|
40687
|
+
return false;
|
|
40688
|
+
}
|
|
40689
|
+
if (prefetchedClipMetadata && Array.isArray(prefetchedClipMetadata[categoryId]) && prefetchedClipMetadata[categoryId].length > 0) {
|
|
40690
|
+
return true;
|
|
40691
|
+
}
|
|
40692
|
+
if (activeCategoryLoading !== void 0 && categoryId === activeFilter) {
|
|
40693
|
+
return true;
|
|
40694
|
+
}
|
|
40695
|
+
return false;
|
|
40696
|
+
}, [prefetchedClipMetadata, activeCategoryLoading, activeFilter]);
|
|
40697
|
+
React142.useEffect(() => {
|
|
40698
|
+
if (!prefetchedClipMetadata) {
|
|
40699
|
+
return;
|
|
40700
|
+
}
|
|
40701
|
+
setClipMetadata((prev) => {
|
|
40702
|
+
let changed = false;
|
|
40703
|
+
const next = { ...prev };
|
|
40704
|
+
Object.entries(prefetchedClipMetadata).forEach(([categoryId, clips]) => {
|
|
40705
|
+
if (!Array.isArray(clips) || clips.length === 0) {
|
|
40706
|
+
return;
|
|
40707
|
+
}
|
|
40708
|
+
const previousClips = prev[categoryId] || [];
|
|
40709
|
+
const previousSignature = previousClips.map((clip) => clip.clipId || clip.id).join("|");
|
|
40710
|
+
const nextSignature = clips.map((clip) => clip.clipId || clip.id).join("|");
|
|
40711
|
+
if (previousSignature === nextSignature) {
|
|
40712
|
+
return;
|
|
40713
|
+
}
|
|
40714
|
+
next[categoryId] = clips;
|
|
40715
|
+
changed = true;
|
|
40716
|
+
});
|
|
40717
|
+
return changed ? next : prev;
|
|
40718
|
+
});
|
|
40719
|
+
setCategoryPages((prev) => {
|
|
40720
|
+
let changed = false;
|
|
40721
|
+
const next = { ...prev };
|
|
40722
|
+
Object.entries(prefetchedClipMetadata).forEach(([categoryId, clips]) => {
|
|
40723
|
+
if (!Array.isArray(clips) || clips.length === 0) {
|
|
40724
|
+
return;
|
|
40725
|
+
}
|
|
40726
|
+
const inferredPage = Math.max(1, Math.ceil(clips.length / CLIP_METADATA_PAGE_SIZE));
|
|
40727
|
+
if (next[categoryId] === inferredPage) {
|
|
40728
|
+
return;
|
|
40729
|
+
}
|
|
40730
|
+
next[categoryId] = inferredPage;
|
|
40731
|
+
changed = true;
|
|
40732
|
+
});
|
|
40733
|
+
return changed ? next : prev;
|
|
40734
|
+
});
|
|
40735
|
+
setCategoryHasMore((prev) => {
|
|
40736
|
+
let changed = false;
|
|
40737
|
+
const next = { ...prev };
|
|
40738
|
+
Object.entries(prefetchedClipMetadata).forEach(([categoryId, clips]) => {
|
|
40739
|
+
if (!Array.isArray(clips) || clips.length === 0) {
|
|
40740
|
+
return;
|
|
40741
|
+
}
|
|
40742
|
+
const knownTotal = typeof counts?.[categoryId] === "number" ? counts[categoryId] : null;
|
|
40743
|
+
const inferredHasMore = knownTotal !== null ? clips.length < knownTotal : prev[categoryId];
|
|
40744
|
+
if (typeof inferredHasMore !== "boolean" || next[categoryId] === inferredHasMore) {
|
|
40745
|
+
return;
|
|
40746
|
+
}
|
|
40747
|
+
next[categoryId] = inferredHasMore;
|
|
40748
|
+
changed = true;
|
|
40749
|
+
});
|
|
40750
|
+
return changed ? next : prev;
|
|
40751
|
+
});
|
|
40752
|
+
}, [prefetchedClipMetadata, counts]);
|
|
40196
40753
|
const { state: filterState } = useClipFilter();
|
|
40197
40754
|
const [percentileCounts, setPercentileCounts] = React142.useState({
|
|
40198
40755
|
"fast-cycles": null,
|
|
@@ -40299,7 +40856,8 @@ var FileManagerFilters = ({
|
|
|
40299
40856
|
shift: shift.toString(),
|
|
40300
40857
|
category: categoryId,
|
|
40301
40858
|
page,
|
|
40302
|
-
limit:
|
|
40859
|
+
limit: CLIP_METADATA_PAGE_SIZE,
|
|
40860
|
+
knownTotal: typeof counts?.[categoryId] === "number" ? counts[categoryId] : null,
|
|
40303
40861
|
snapshotDateTime,
|
|
40304
40862
|
snapshotClipId
|
|
40305
40863
|
}),
|
|
@@ -40309,7 +40867,7 @@ var FileManagerFilters = ({
|
|
|
40309
40867
|
throw new Error(`API error: ${response.status}`);
|
|
40310
40868
|
}
|
|
40311
40869
|
return response.json();
|
|
40312
|
-
}, [workspaceId, date, shift, snapshotDateTime, snapshotClipId, supabase]);
|
|
40870
|
+
}, [workspaceId, date, shift, counts, snapshotDateTime, snapshotClipId, supabase]);
|
|
40313
40871
|
const seedIdleClassifications = React142.useCallback(async (clips) => {
|
|
40314
40872
|
if (!idleTimeVlmEnabled || clips.length === 0) {
|
|
40315
40873
|
return;
|
|
@@ -40366,6 +40924,10 @@ var FileManagerFilters = ({
|
|
|
40366
40924
|
return;
|
|
40367
40925
|
}
|
|
40368
40926
|
const loadingKey = `${categoryId}-${page}`;
|
|
40927
|
+
if (inFlightMetadataRequestsRef.current.has(loadingKey)) {
|
|
40928
|
+
return;
|
|
40929
|
+
}
|
|
40930
|
+
inFlightMetadataRequestsRef.current.add(loadingKey);
|
|
40369
40931
|
setLoadingCategories((prev) => /* @__PURE__ */ new Set([...prev, loadingKey]));
|
|
40370
40932
|
try {
|
|
40371
40933
|
const data = await fetchClipMetadataPage(categoryId, page);
|
|
@@ -40382,6 +40944,7 @@ var FileManagerFilters = ({
|
|
|
40382
40944
|
} catch (error) {
|
|
40383
40945
|
console.error("[FileManager] Error fetching clip metadata:", error);
|
|
40384
40946
|
} finally {
|
|
40947
|
+
inFlightMetadataRequestsRef.current.delete(loadingKey);
|
|
40385
40948
|
setLoadingCategories((prev) => {
|
|
40386
40949
|
const newSet = new Set(prev);
|
|
40387
40950
|
newSet.delete(loadingKey);
|
|
@@ -40655,16 +41218,19 @@ var FileManagerFilters = ({
|
|
|
40655
41218
|
React142.useEffect(() => {
|
|
40656
41219
|
if (activeFilter) {
|
|
40657
41220
|
setExpandedNodes((prev) => {
|
|
41221
|
+
if (prev.has(activeFilter)) {
|
|
41222
|
+
return prev;
|
|
41223
|
+
}
|
|
40658
41224
|
const newExpanded = new Set(prev);
|
|
40659
41225
|
newExpanded.add(activeFilter);
|
|
40660
41226
|
return newExpanded;
|
|
40661
41227
|
});
|
|
40662
41228
|
const category = categories.find((cat) => cat.id === activeFilter);
|
|
40663
|
-
if (category) {
|
|
41229
|
+
if (category && !isCategoryExternallyManaged(activeFilter) && !clipMetadataRef.current[activeFilter]) {
|
|
40664
41230
|
fetchClipMetadata(activeFilter, 1);
|
|
40665
41231
|
}
|
|
40666
41232
|
}
|
|
40667
|
-
}, [activeFilter]);
|
|
41233
|
+
}, [activeFilter, isCategoryExternallyManaged]);
|
|
40668
41234
|
React142.useEffect(() => {
|
|
40669
41235
|
const handleEscape = (e) => {
|
|
40670
41236
|
if (e.key === "Escape") {
|
|
@@ -40935,14 +41501,14 @@ var FileManagerFilters = ({
|
|
|
40935
41501
|
} else {
|
|
40936
41502
|
newExpanded.add(nodeId);
|
|
40937
41503
|
const category = categories.find((cat) => cat.id === nodeId);
|
|
40938
|
-
if (category && !clipMetadata[nodeId]) {
|
|
41504
|
+
if (category && !clipMetadata[nodeId] && !isCategoryExternallyManaged(nodeId)) {
|
|
40939
41505
|
console.log(`[FileManager] Fetching clips for expanded category: ${nodeId}`);
|
|
40940
41506
|
fetchClipMetadata(nodeId, 1);
|
|
40941
41507
|
}
|
|
40942
|
-
if (showPercentileCycleFilters && nodeId === "fast-cycles" && (percentileClips["fast-cycles"] || []).length === 0) {
|
|
41508
|
+
if (!isCategoryExternallyManaged(nodeId) && showPercentileCycleFilters && nodeId === "fast-cycles" && (percentileClips["fast-cycles"] || []).length === 0) {
|
|
40943
41509
|
fetchPercentileClips("fast-cycles");
|
|
40944
41510
|
}
|
|
40945
|
-
if (showPercentileCycleFilters && nodeId === "slow-cycles" && (percentileClips["slow-cycles"] || []).length === 0) {
|
|
41511
|
+
if (!isCategoryExternallyManaged(nodeId) && showPercentileCycleFilters && nodeId === "slow-cycles" && (percentileClips["slow-cycles"] || []).length === 0) {
|
|
40946
41512
|
fetchPercentileClips("slow-cycles");
|
|
40947
41513
|
}
|
|
40948
41514
|
}
|
|
@@ -40956,14 +41522,14 @@ var FileManagerFilters = ({
|
|
|
40956
41522
|
} else {
|
|
40957
41523
|
newExpanded.add(node.id);
|
|
40958
41524
|
const category = categories.find((cat) => cat.id === node.id);
|
|
40959
|
-
if (category && !clipMetadata[node.id]) {
|
|
41525
|
+
if (category && !clipMetadata[node.id] && !isCategoryExternallyManaged(node.id)) {
|
|
40960
41526
|
console.log(`[FileManager] Fetching clips for expanded category: ${node.id}`);
|
|
40961
41527
|
fetchClipMetadata(node.id, 1);
|
|
40962
41528
|
}
|
|
40963
|
-
if (showPercentileCycleFilters && node.id === "fast-cycles" && (percentileClips["fast-cycles"] || []).length === 0) {
|
|
41529
|
+
if (!isCategoryExternallyManaged(node.id) && showPercentileCycleFilters && node.id === "fast-cycles" && (percentileClips["fast-cycles"] || []).length === 0) {
|
|
40964
41530
|
fetchPercentileClips("fast-cycles");
|
|
40965
41531
|
}
|
|
40966
|
-
if (showPercentileCycleFilters && node.id === "slow-cycles" && (percentileClips["slow-cycles"] || []).length === 0) {
|
|
41532
|
+
if (!isCategoryExternallyManaged(node.id) && showPercentileCycleFilters && node.id === "slow-cycles" && (percentileClips["slow-cycles"] || []).length === 0) {
|
|
40967
41533
|
fetchPercentileClips("slow-cycles");
|
|
40968
41534
|
}
|
|
40969
41535
|
}
|
|
@@ -41016,6 +41582,9 @@ var FileManagerFilters = ({
|
|
|
41016
41582
|
const isCurrentVideo = currentVideoId === node.id;
|
|
41017
41583
|
const isCountUnknown = node.type === "percentile-category" && node.count === null;
|
|
41018
41584
|
const hasChildren = isCountUnknown || (node.count || 0) > 0;
|
|
41585
|
+
const showExternalLoadingState = Boolean(
|
|
41586
|
+
activeCategoryLoading && isExpanded && node.id === activeFilter && (node.type === "category" || node.type === "percentile-category")
|
|
41587
|
+
);
|
|
41019
41588
|
const colorClasses = node.color ? getColorClasses(node.color) : null;
|
|
41020
41589
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "select-none animate-in", children: [
|
|
41021
41590
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -41097,6 +41666,10 @@ var FileManagerFilters = ({
|
|
|
41097
41666
|
),
|
|
41098
41667
|
hasChildren && isExpanded && (node.type === "category" || node.type === "percentile-category") && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 ml-3 animate-in border-l-2 border-slate-100 pl-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-h-64 overflow-y-auto space-y-1 scrollbar-thin scrollbar-track-slate-100 scrollbar-thumb-slate-300", children: [
|
|
41099
41668
|
node.children.map((child) => renderNode(child, depth + 1)),
|
|
41669
|
+
showExternalLoadingState && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-2 px-3 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center text-sm text-slate-500", children: [
|
|
41670
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
41671
|
+
"Loading clips..."
|
|
41672
|
+
] }) }),
|
|
41100
41673
|
loadingCategories.has(`${node.id}-${(categoryPages[node.id] || 0) + 1}`) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-2 px-3 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center text-sm text-slate-500", children: [
|
|
41101
41674
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin mr-2 h-4 w-4 border-2 border-slate-300 border-t-blue-500 rounded-full" }),
|
|
41102
41675
|
"Loading more clips..."
|
|
@@ -42569,6 +43142,7 @@ var BottlenecksContent = ({
|
|
|
42569
43142
|
category: categoryId,
|
|
42570
43143
|
page: 1,
|
|
42571
43144
|
limit: 100,
|
|
43145
|
+
knownTotal: mergedCounts[categoryId] ?? null,
|
|
42572
43146
|
snapshotDateTime,
|
|
42573
43147
|
snapshotClipId
|
|
42574
43148
|
}),
|
|
@@ -42585,7 +43159,7 @@ var BottlenecksContent = ({
|
|
|
42585
43159
|
metadataClips = categoryData.clips.map((clip, index) => ({
|
|
42586
43160
|
id: clip.id,
|
|
42587
43161
|
clipId: clip.id,
|
|
42588
|
-
clip_timestamp: clip.
|
|
43162
|
+
clip_timestamp: clip.creation_timestamp || clip.timestamp,
|
|
42589
43163
|
description: clip.description,
|
|
42590
43164
|
severity: clip.severity,
|
|
42591
43165
|
category: categoryId,
|
|
@@ -43223,6 +43797,14 @@ var BottlenecksContent = ({
|
|
|
43223
43797
|
}
|
|
43224
43798
|
return currentPosition;
|
|
43225
43799
|
}, [activeFilter, categoryMetadata.length, currentMetadataIndex, currentPosition, isPercentileCategory]);
|
|
43800
|
+
const prefetchedExplorerMetadata = React142.useMemo(() => {
|
|
43801
|
+
if (!activeFilter || categoryMetadata.length === 0) {
|
|
43802
|
+
return void 0;
|
|
43803
|
+
}
|
|
43804
|
+
return {
|
|
43805
|
+
[activeFilter]: categoryMetadata
|
|
43806
|
+
};
|
|
43807
|
+
}, [activeFilter, categoryMetadata]);
|
|
43226
43808
|
const classificationClipIds = React142.useMemo(() => {
|
|
43227
43809
|
if (!idleTimeVlmEnabled) {
|
|
43228
43810
|
return [];
|
|
@@ -43944,6 +44526,8 @@ var BottlenecksContent = ({
|
|
|
43944
44526
|
clipClassifications,
|
|
43945
44527
|
idleTimeVlmEnabled,
|
|
43946
44528
|
showPercentileCycleFilters: isFastSlowClipFiltersEnabled,
|
|
44529
|
+
prefetchedClipMetadata: prefetchedExplorerMetadata,
|
|
44530
|
+
activeCategoryLoading: isCategoryLoading,
|
|
43947
44531
|
onFilterChange: (filterId) => {
|
|
43948
44532
|
updateActiveFilter(filterId);
|
|
43949
44533
|
const category = categoriesToShow.find((cat) => cat.type === filterId);
|