@universe-platform/ui 0.1.0-beta.4 → 0.1.0-beta.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/globals.css +337 -2
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +983 -114
- package/dist/index.mjs +983 -114
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -77,7 +77,7 @@ function cn(...inputs) {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
// src/components/TableBlock/TableBlockClient.tsx
|
|
80
|
-
var
|
|
80
|
+
var import_react6 = require("react");
|
|
81
81
|
|
|
82
82
|
// src/hooks/useToast.ts
|
|
83
83
|
var import_react2 = require("react");
|
|
@@ -277,7 +277,7 @@ function useToast() {
|
|
|
277
277
|
}
|
|
278
278
|
|
|
279
279
|
// src/components/TableBlock/fields/fieldRegistry.tsx
|
|
280
|
-
var
|
|
280
|
+
var import_react5 = __toESM(require("react"));
|
|
281
281
|
|
|
282
282
|
// src/components/TableBlock/fields/DrivePickerCell.tsx
|
|
283
283
|
var import_react3 = require("react");
|
|
@@ -399,8 +399,311 @@ function DrivePickerCell({ value, onChange, tableName, onMarkForDeletion, contex
|
|
|
399
399
|
) });
|
|
400
400
|
}
|
|
401
401
|
|
|
402
|
-
// src/components/TableBlock/fields/
|
|
402
|
+
// src/components/TableBlock/fields/DatePickerCell.tsx
|
|
403
|
+
var import_react4 = require("react");
|
|
404
|
+
var import_lucide_react3 = require("lucide-react");
|
|
403
405
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
406
|
+
function parseDateParts(val) {
|
|
407
|
+
if (val === void 0 || val === null || val === "") return null;
|
|
408
|
+
if (typeof val === "string") {
|
|
409
|
+
const trimmed = val.trim();
|
|
410
|
+
if (!trimmed) return null;
|
|
411
|
+
const ymdMatch = trimmed.match(/^(\d{4})[-/.](\d{1,2})[-/.](\d{1,2})/);
|
|
412
|
+
if (ymdMatch) {
|
|
413
|
+
const year = parseInt(ymdMatch[1], 10);
|
|
414
|
+
const month = parseInt(ymdMatch[2], 10);
|
|
415
|
+
const day = parseInt(ymdMatch[3], 10);
|
|
416
|
+
if (month >= 1 && month <= 12 && day >= 1 && day <= 31) {
|
|
417
|
+
return { year, month, day };
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
const dmyMatch = trimmed.match(/^(\d{1,2})[-/.](\d{1,2})[-/.](\d{4})/);
|
|
421
|
+
if (dmyMatch) {
|
|
422
|
+
const day = parseInt(dmyMatch[1], 10);
|
|
423
|
+
const month = parseInt(dmyMatch[2], 10);
|
|
424
|
+
const year = parseInt(dmyMatch[3], 10);
|
|
425
|
+
if (month >= 1 && month <= 12 && day >= 1 && day <= 31) {
|
|
426
|
+
return { year, month, day };
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
const parsed = new Date(trimmed);
|
|
430
|
+
if (!isNaN(parsed.getTime())) {
|
|
431
|
+
return {
|
|
432
|
+
year: parsed.getFullYear(),
|
|
433
|
+
month: parsed.getMonth() + 1,
|
|
434
|
+
day: parsed.getDate()
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
} else if (val instanceof Date && !isNaN(val.getTime())) {
|
|
438
|
+
return {
|
|
439
|
+
year: val.getFullYear(),
|
|
440
|
+
month: val.getMonth() + 1,
|
|
441
|
+
day: val.getDate()
|
|
442
|
+
};
|
|
443
|
+
} else if (typeof val === "number" && !isNaN(val)) {
|
|
444
|
+
const parsed = new Date(val);
|
|
445
|
+
if (!isNaN(parsed.getTime())) {
|
|
446
|
+
return {
|
|
447
|
+
year: parsed.getFullYear(),
|
|
448
|
+
month: parsed.getMonth() + 1,
|
|
449
|
+
day: parsed.getDate()
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
function formatDateIso(year, month, day) {
|
|
456
|
+
const mm = String(month).padStart(2, "0");
|
|
457
|
+
const dd = String(day).padStart(2, "0");
|
|
458
|
+
return `${year}-${mm}-${dd}`;
|
|
459
|
+
}
|
|
460
|
+
function formatDateDisplay(parts) {
|
|
461
|
+
if (!parts) return "";
|
|
462
|
+
const mm = String(parts.month).padStart(2, "0");
|
|
463
|
+
const dd = String(parts.day).padStart(2, "0");
|
|
464
|
+
return `${dd}/${mm}/${parts.year}`;
|
|
465
|
+
}
|
|
466
|
+
var HEBREW_MONTHS = [
|
|
467
|
+
"\u05D9\u05E0\u05D5\u05D0\u05E8",
|
|
468
|
+
"\u05E4\u05D1\u05E8\u05D5\u05D0\u05E8",
|
|
469
|
+
"\u05DE\u05E8\u05E5",
|
|
470
|
+
"\u05D0\u05E4\u05E8\u05D9\u05DC",
|
|
471
|
+
"\u05DE\u05D0\u05D9",
|
|
472
|
+
"\u05D9\u05D5\u05E0\u05D9",
|
|
473
|
+
"\u05D9\u05D5\u05DC\u05D9",
|
|
474
|
+
"\u05D0\u05D5\u05D2\u05D5\u05E1\u05D8",
|
|
475
|
+
"\u05E1\u05E4\u05D8\u05DE\u05D1\u05E8",
|
|
476
|
+
"\u05D0\u05D5\u05E7\u05D8\u05D5\u05D1\u05E8",
|
|
477
|
+
"\u05E0\u05D5\u05D1\u05DE\u05D1\u05E8",
|
|
478
|
+
"\u05D3\u05E6\u05DE\u05D1\u05E8"
|
|
479
|
+
];
|
|
480
|
+
var WEEKDAY_LABELS = ["\u05D0'", "\u05D1'", "\u05D2'", "\u05D3'", "\u05D4'", "\u05D5'", "\u05E9'"];
|
|
481
|
+
function DatePickerCell({ value, onChange, readOnly = false }) {
|
|
482
|
+
const [isOpen, setIsOpen] = (0, import_react4.useState)(false);
|
|
483
|
+
const containerRef = (0, import_react4.useRef)(null);
|
|
484
|
+
const [popoverPos, setPopoverPos] = (0, import_react4.useState)({ top: 0, right: 0 });
|
|
485
|
+
const parsedParts = (0, import_react4.useMemo)(() => parseDateParts(value), [value]);
|
|
486
|
+
const displayString = (0, import_react4.useMemo)(() => formatDateDisplay(parsedParts), [parsedParts]);
|
|
487
|
+
const [rawInput, setRawInput] = (0, import_react4.useState)(displayString);
|
|
488
|
+
(0, import_react4.useEffect)(() => {
|
|
489
|
+
setRawInput(displayString);
|
|
490
|
+
}, [displayString]);
|
|
491
|
+
const now = /* @__PURE__ */ new Date();
|
|
492
|
+
const [viewYear, setViewYear] = (0, import_react4.useState)((parsedParts == null ? void 0 : parsedParts.year) || now.getFullYear());
|
|
493
|
+
const [viewMonth, setViewMonth] = (0, import_react4.useState)((parsedParts == null ? void 0 : parsedParts.month) || now.getMonth() + 1);
|
|
494
|
+
(0, import_react4.useEffect)(() => {
|
|
495
|
+
if (parsedParts) {
|
|
496
|
+
setViewYear(parsedParts.year);
|
|
497
|
+
setViewMonth(parsedParts.month);
|
|
498
|
+
}
|
|
499
|
+
}, [parsedParts, isOpen]);
|
|
500
|
+
const updatePopoverPosition = (0, import_react4.useCallback)(() => {
|
|
501
|
+
if (containerRef.current) {
|
|
502
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
503
|
+
const right = window.innerWidth - rect.right;
|
|
504
|
+
const popoverHeight = 320;
|
|
505
|
+
const spaceBelow = window.innerHeight - rect.bottom;
|
|
506
|
+
if (spaceBelow < popoverHeight && rect.top > popoverHeight) {
|
|
507
|
+
setPopoverPos({
|
|
508
|
+
top: Math.max(10, rect.top - popoverHeight - 4),
|
|
509
|
+
right: Math.max(10, right)
|
|
510
|
+
});
|
|
511
|
+
} else {
|
|
512
|
+
setPopoverPos({
|
|
513
|
+
top: Math.min(window.innerHeight - popoverHeight - 10, rect.bottom + 4),
|
|
514
|
+
right: Math.max(10, right)
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}, []);
|
|
519
|
+
(0, import_react4.useEffect)(() => {
|
|
520
|
+
if (!isOpen) return;
|
|
521
|
+
updatePopoverPosition();
|
|
522
|
+
function handleScrollOrResize() {
|
|
523
|
+
updatePopoverPosition();
|
|
524
|
+
}
|
|
525
|
+
function handleClickOutside(event) {
|
|
526
|
+
if (containerRef.current && !containerRef.current.contains(event.target)) {
|
|
527
|
+
const popoverEl = document.getElementById("date-picker-popover");
|
|
528
|
+
if (popoverEl && popoverEl.contains(event.target)) {
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
setIsOpen(false);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
window.addEventListener("scroll", handleScrollOrResize, true);
|
|
535
|
+
window.addEventListener("resize", handleScrollOrResize);
|
|
536
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
537
|
+
return () => {
|
|
538
|
+
window.removeEventListener("scroll", handleScrollOrResize, true);
|
|
539
|
+
window.removeEventListener("resize", handleScrollOrResize);
|
|
540
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
541
|
+
};
|
|
542
|
+
}, [isOpen, updatePopoverPosition]);
|
|
543
|
+
const handleInputChange = (e) => {
|
|
544
|
+
const text = e.target.value;
|
|
545
|
+
setRawInput(text);
|
|
546
|
+
if (!text.trim()) {
|
|
547
|
+
onChange(null);
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
const parts = parseDateParts(text);
|
|
551
|
+
if (parts) {
|
|
552
|
+
const iso = formatDateIso(parts.year, parts.month, parts.day);
|
|
553
|
+
onChange(iso);
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
const handleInputBlur = () => {
|
|
557
|
+
const parts = parseDateParts(rawInput);
|
|
558
|
+
if (parts) {
|
|
559
|
+
setRawInput(formatDateDisplay(parts));
|
|
560
|
+
} else if (!rawInput.trim()) {
|
|
561
|
+
setRawInput("");
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
const handleSelectDay = (day) => {
|
|
565
|
+
const iso = formatDateIso(viewYear, viewMonth, day);
|
|
566
|
+
onChange(iso);
|
|
567
|
+
setRawInput(formatDateDisplay({ year: viewYear, month: viewMonth, day }));
|
|
568
|
+
setIsOpen(false);
|
|
569
|
+
};
|
|
570
|
+
const handlePrevMonth = () => {
|
|
571
|
+
if (viewMonth === 1) {
|
|
572
|
+
setViewMonth(12);
|
|
573
|
+
setViewYear((prev) => prev - 1);
|
|
574
|
+
} else {
|
|
575
|
+
setViewMonth((prev) => prev - 1);
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
const handleNextMonth = () => {
|
|
579
|
+
if (viewMonth === 12) {
|
|
580
|
+
setViewMonth(1);
|
|
581
|
+
setViewYear((prev) => prev + 1);
|
|
582
|
+
} else {
|
|
583
|
+
setViewMonth((prev) => prev + 1);
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
const calendarDays = (0, import_react4.useMemo)(() => {
|
|
587
|
+
const firstDayIndex = new Date(viewYear, viewMonth - 1, 1).getDay();
|
|
588
|
+
const totalDays = new Date(viewYear, viewMonth, 0).getDate();
|
|
589
|
+
const days = [];
|
|
590
|
+
const prevMonthTotalDays = new Date(viewYear, viewMonth - 1, 0).getDate();
|
|
591
|
+
for (let i = firstDayIndex - 1; i >= 0; i--) {
|
|
592
|
+
days.push({ day: prevMonthTotalDays - i, isCurrentMonth: false });
|
|
593
|
+
}
|
|
594
|
+
for (let d = 1; d <= totalDays; d++) {
|
|
595
|
+
days.push({ day: d, isCurrentMonth: true });
|
|
596
|
+
}
|
|
597
|
+
const remaining = 7 - days.length % 7;
|
|
598
|
+
if (remaining < 7) {
|
|
599
|
+
for (let d = 1; d <= remaining; d++) {
|
|
600
|
+
days.push({ day: d, isCurrentMonth: false });
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
return days;
|
|
604
|
+
}, [viewYear, viewMonth]);
|
|
605
|
+
if (readOnly) {
|
|
606
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "px-2 py-1 flex items-center justify-end w-full h-full text-sm font-normal text-slate-800 text-right", dir: "ltr", children: displayString });
|
|
607
|
+
}
|
|
608
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { ref: containerRef, className: "relative w-full h-full flex items-center", children: [
|
|
609
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
610
|
+
"input",
|
|
611
|
+
{
|
|
612
|
+
type: "text",
|
|
613
|
+
dir: "ltr",
|
|
614
|
+
placeholder: "DD/MM/YYYY",
|
|
615
|
+
className: "w-full h-8 pl-8 pr-2 bg-transparent focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 text-sm text-right font-normal text-slate-800",
|
|
616
|
+
value: rawInput,
|
|
617
|
+
onChange: handleInputChange,
|
|
618
|
+
onBlur: handleInputBlur
|
|
619
|
+
}
|
|
620
|
+
),
|
|
621
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
622
|
+
"button",
|
|
623
|
+
{
|
|
624
|
+
type: "button",
|
|
625
|
+
onClick: () => {
|
|
626
|
+
setIsOpen((prev) => {
|
|
627
|
+
const next = !prev;
|
|
628
|
+
if (next) updatePopoverPosition();
|
|
629
|
+
return next;
|
|
630
|
+
});
|
|
631
|
+
},
|
|
632
|
+
className: "absolute left-1.5 p-1 text-slate-400 hover:text-blue-600 rounded transition-colors",
|
|
633
|
+
title: "\u05D1\u05D7\u05E8 \u05EA\u05D0\u05E8\u05D9\u05DA",
|
|
634
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.Calendar, { className: "w-4 h-4" })
|
|
635
|
+
}
|
|
636
|
+
),
|
|
637
|
+
isOpen && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
638
|
+
"div",
|
|
639
|
+
{
|
|
640
|
+
id: "date-picker-popover",
|
|
641
|
+
dir: "rtl",
|
|
642
|
+
style: { top: `${popoverPos.top}px`, right: `${popoverPos.right}px` },
|
|
643
|
+
className: "fixed z-[99999] w-72 bg-white rounded-xl shadow-2xl border border-slate-200 p-3.5 animate-in fade-in zoom-in-95 duration-150",
|
|
644
|
+
children: [
|
|
645
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center justify-between border-b border-slate-100 pb-2.5 mb-2.5", children: [
|
|
646
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "text-xs font-semibold text-slate-500", children: parsedParts ? `${parsedParts.day} \u05D1${HEBREW_MONTHS[parsedParts.month - 1]} ${parsedParts.year}` : "\u05D1\u05D7\u05D9\u05E8\u05EA \u05EA\u05D0\u05E8\u05D9\u05DA" }),
|
|
647
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
648
|
+
"button",
|
|
649
|
+
{
|
|
650
|
+
onClick: () => setIsOpen(false),
|
|
651
|
+
className: "text-slate-400 hover:text-slate-600 p-0.5 rounded-full hover:bg-slate-100",
|
|
652
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.X, { className: "w-4 h-4" })
|
|
653
|
+
}
|
|
654
|
+
)
|
|
655
|
+
] }),
|
|
656
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center justify-between mb-3 px-1", children: [
|
|
657
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
658
|
+
"button",
|
|
659
|
+
{
|
|
660
|
+
type: "button",
|
|
661
|
+
onClick: handleNextMonth,
|
|
662
|
+
className: "p-1 text-slate-600 hover:bg-slate-100 rounded-lg transition-colors",
|
|
663
|
+
title: "\u05D7\u05D5\u05D3\u05E9 \u05D4\u05D1\u05D0",
|
|
664
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.ChevronRight, { className: "w-4 h-4" })
|
|
665
|
+
}
|
|
666
|
+
),
|
|
667
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "font-bold text-sm text-slate-800", children: [
|
|
668
|
+
HEBREW_MONTHS[viewMonth - 1],
|
|
669
|
+
" ",
|
|
670
|
+
viewYear
|
|
671
|
+
] }),
|
|
672
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
673
|
+
"button",
|
|
674
|
+
{
|
|
675
|
+
type: "button",
|
|
676
|
+
onClick: handlePrevMonth,
|
|
677
|
+
className: "p-1 text-slate-600 hover:bg-slate-100 rounded-lg transition-colors",
|
|
678
|
+
title: "\u05D7\u05D5\u05D3\u05E9 \u05E7\u05D5\u05D3\u05DD",
|
|
679
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.ChevronLeft, { className: "w-4 h-4" })
|
|
680
|
+
}
|
|
681
|
+
)
|
|
682
|
+
] }),
|
|
683
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "grid grid-cols-7 gap-1 text-center mb-1.5", children: WEEKDAY_LABELS.map((label, idx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-[11px] font-bold text-slate-400 select-none py-0.5", children: label }, idx)) }),
|
|
684
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "grid grid-cols-7 gap-1 text-center", children: calendarDays.map((item, idx) => {
|
|
685
|
+
const isSelected = item.isCurrentMonth && (parsedParts == null ? void 0 : parsedParts.year) === viewYear && (parsedParts == null ? void 0 : parsedParts.month) === viewMonth && (parsedParts == null ? void 0 : parsedParts.day) === item.day;
|
|
686
|
+
const isToday = item.isCurrentMonth && now.getFullYear() === viewYear && now.getMonth() + 1 === viewMonth && now.getDate() === item.day;
|
|
687
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
688
|
+
"button",
|
|
689
|
+
{
|
|
690
|
+
type: "button",
|
|
691
|
+
disabled: !item.isCurrentMonth,
|
|
692
|
+
onClick: () => item.isCurrentMonth && handleSelectDay(item.day),
|
|
693
|
+
className: `h-8 w-8 mx-auto flex items-center justify-center rounded-lg text-xs transition-all ${!item.isCurrentMonth ? "text-slate-300 cursor-not-allowed" : isSelected ? "bg-blue-600 text-white font-bold shadow-md scale-105" : isToday ? "bg-blue-50 text-blue-700 font-bold border border-blue-300 hover:bg-blue-100" : "text-slate-700 hover:bg-slate-100 font-medium"}`,
|
|
694
|
+
children: item.day
|
|
695
|
+
},
|
|
696
|
+
idx
|
|
697
|
+
);
|
|
698
|
+
}) })
|
|
699
|
+
]
|
|
700
|
+
}
|
|
701
|
+
)
|
|
702
|
+
] });
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// src/components/TableBlock/fields/fieldRegistry.tsx
|
|
706
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
404
707
|
var CURRENCY_SYMBOLS = {
|
|
405
708
|
USD: "$",
|
|
406
709
|
EUR: "\u20AC",
|
|
@@ -436,17 +739,22 @@ function getRelationDisplayLabel(opt, column) {
|
|
|
436
739
|
return "\u05E2\u05E8\u05DA \u05E8\u05D9\u05E7";
|
|
437
740
|
}
|
|
438
741
|
var FORM_INPUTS = {
|
|
742
|
+
DATE: ({ value, onChange, column }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DatePickerCell, { value, onChange, column }),
|
|
439
743
|
CURRENCY: ({ value, column, onChange }) => {
|
|
440
744
|
const symbol = getCurrencySymbol(column.currencySymbol);
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
745
|
+
const [isFocused, setIsFocused] = import_react5.default.useState(false);
|
|
746
|
+
const displayValue = !isFocused && value !== void 0 && value !== null && value !== "" && !isNaN(Number(value)) ? new Intl.NumberFormat("en-US").format(Number(value)) : value !== void 0 && value !== null ? value : "";
|
|
747
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "relative w-full h-full", children: [
|
|
748
|
+
symbol && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "absolute left-2 top-1/2 -translate-y-1/2 text-slate-400 pointer-events-none text-sm", children: symbol }),
|
|
749
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
444
750
|
"input",
|
|
445
751
|
{
|
|
446
|
-
type: "number",
|
|
752
|
+
type: isFocused ? "number" : "text",
|
|
447
753
|
step: "any",
|
|
448
754
|
className: `w-full h-8 ${symbol ? "pl-6 pr-2" : "px-2"} bg-transparent focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 text-sm`,
|
|
449
|
-
value:
|
|
755
|
+
value: displayValue,
|
|
756
|
+
onFocus: () => setIsFocused(true),
|
|
757
|
+
onBlur: () => setIsFocused(false),
|
|
450
758
|
onChange: (e) => {
|
|
451
759
|
const val = e.target.value;
|
|
452
760
|
onChange(val === "" ? "" : Number(val));
|
|
@@ -455,7 +763,7 @@ var FORM_INPUTS = {
|
|
|
455
763
|
)
|
|
456
764
|
] });
|
|
457
765
|
},
|
|
458
|
-
TIME: ({ value, onChange }) => /* @__PURE__ */ (0,
|
|
766
|
+
TIME: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
459
767
|
"input",
|
|
460
768
|
{
|
|
461
769
|
type: "time",
|
|
@@ -465,13 +773,13 @@ var FORM_INPUTS = {
|
|
|
465
773
|
}
|
|
466
774
|
),
|
|
467
775
|
LINK: ({ value, onChange }) => {
|
|
468
|
-
const [isEditing, setIsEditing] =
|
|
776
|
+
const [isEditing, setIsEditing] = import_react5.default.useState(false);
|
|
469
777
|
const label = (value == null ? void 0 : value.label) || "";
|
|
470
778
|
const url = (value == null ? void 0 : value.url) || "";
|
|
471
779
|
if (!isEditing) {
|
|
472
|
-
return /* @__PURE__ */ (0,
|
|
473
|
-
url ? /* @__PURE__ */ (0,
|
|
474
|
-
/* @__PURE__ */ (0,
|
|
780
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-2 px-2 py-1 h-full w-full", children: [
|
|
781
|
+
url ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href: url, target: "_blank", rel: "noopener noreferrer", className: "text-blue-600 hover:underline flex-1 truncate", children: label || url }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-slate-400 italic flex-1 text-sm", children: "\u05E8\u05D9\u05E7" }),
|
|
782
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
475
783
|
"button",
|
|
476
784
|
{
|
|
477
785
|
onClick: () => setIsEditing(true),
|
|
@@ -482,8 +790,8 @@ var FORM_INPUTS = {
|
|
|
482
790
|
)
|
|
483
791
|
] });
|
|
484
792
|
}
|
|
485
|
-
return /* @__PURE__ */ (0,
|
|
486
|
-
/* @__PURE__ */ (0,
|
|
793
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex gap-2 p-1 w-full min-w-[250px] items-center bg-white border border-blue-200 rounded shadow-sm z-10", children: [
|
|
794
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
487
795
|
"input",
|
|
488
796
|
{
|
|
489
797
|
type: "text",
|
|
@@ -493,7 +801,7 @@ var FORM_INPUTS = {
|
|
|
493
801
|
onChange: (e) => onChange({ label: e.target.value, url })
|
|
494
802
|
}
|
|
495
803
|
),
|
|
496
|
-
/* @__PURE__ */ (0,
|
|
804
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
497
805
|
"input",
|
|
498
806
|
{
|
|
499
807
|
type: "url",
|
|
@@ -503,7 +811,7 @@ var FORM_INPUTS = {
|
|
|
503
811
|
onChange: (e) => onChange({ label, url: e.target.value })
|
|
504
812
|
}
|
|
505
813
|
),
|
|
506
|
-
/* @__PURE__ */ (0,
|
|
814
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
507
815
|
"button",
|
|
508
816
|
{
|
|
509
817
|
onClick: () => setIsEditing(false),
|
|
@@ -514,7 +822,7 @@ var FORM_INPUTS = {
|
|
|
514
822
|
)
|
|
515
823
|
] });
|
|
516
824
|
},
|
|
517
|
-
BOOLEAN: ({ value, onChange }) => /* @__PURE__ */ (0,
|
|
825
|
+
BOOLEAN: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex items-center justify-center w-full h-full p-2", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
518
826
|
"input",
|
|
519
827
|
{
|
|
520
828
|
type: "checkbox",
|
|
@@ -523,7 +831,7 @@ var FORM_INPUTS = {
|
|
|
523
831
|
className: "w-4 h-4 rounded border-slate-300 text-brand"
|
|
524
832
|
}
|
|
525
833
|
) }),
|
|
526
|
-
GOOGLE_DRIVE_FILE: ({ value, onChange, context }) => /* @__PURE__ */ (0,
|
|
834
|
+
GOOGLE_DRIVE_FILE: ({ value, onChange, context }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
527
835
|
DrivePickerCell,
|
|
528
836
|
{
|
|
529
837
|
value: value || null,
|
|
@@ -536,7 +844,7 @@ var FORM_INPUTS = {
|
|
|
536
844
|
RELATION: ({ value, onChange, column, context }) => {
|
|
537
845
|
var _a;
|
|
538
846
|
const options = ((_a = context == null ? void 0 : context.relationOptions) == null ? void 0 : _a[column.name]) || [];
|
|
539
|
-
|
|
847
|
+
import_react5.default.useEffect(() => {
|
|
540
848
|
if (typeof value === "string" && value !== "" && options.length > 0) {
|
|
541
849
|
const isValidId = options.some((o) => String(o.id) === String(value));
|
|
542
850
|
if (!isValidId) {
|
|
@@ -555,7 +863,7 @@ var FORM_INPUTS = {
|
|
|
555
863
|
_displayLabel: getRelationDisplayLabel(opt, column)
|
|
556
864
|
}));
|
|
557
865
|
const validOptions = processedOptions.filter((o) => o._displayLabel !== "\u05D4\u05E2\u05E8\u05DA \u05E9\u05D1\u05E8\u05E9\u05D5\u05DE\u05D4 \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05EA \u05E0\u05E9\u05D0\u05E8 \u05E8\u05D9\u05E7");
|
|
558
|
-
return /* @__PURE__ */ (0,
|
|
866
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
559
867
|
"select",
|
|
560
868
|
{
|
|
561
869
|
className: "w-full h-8 px-2 bg-transparent focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 text-sm",
|
|
@@ -567,13 +875,13 @@ var FORM_INPUTS = {
|
|
|
567
875
|
}
|
|
568
876
|
},
|
|
569
877
|
children: [
|
|
570
|
-
/* @__PURE__ */ (0,
|
|
571
|
-
validOptions.length > 0 ? validOptions.map((opt) => /* @__PURE__ */ (0,
|
|
878
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "", children: "\u05D1\u05D7\u05E8..." }),
|
|
879
|
+
validOptions.length > 0 ? validOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: opt.id, children: opt._displayLabel }, opt.id)) : options.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "empty_all", disabled: true, children: "\u05DB\u05DC \u05D4\u05E2\u05E8\u05DB\u05D9\u05DD \u05D1\u05D8\u05D1\u05DC\u05D4 \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05EA \u05E8\u05D9\u05E7\u05D9\u05DD" }) : null
|
|
572
880
|
]
|
|
573
881
|
}
|
|
574
882
|
);
|
|
575
883
|
},
|
|
576
|
-
NUMBER: ({ value, onChange }) => /* @__PURE__ */ (0,
|
|
884
|
+
NUMBER: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
577
885
|
"input",
|
|
578
886
|
{
|
|
579
887
|
type: "number",
|
|
@@ -585,7 +893,7 @@ var FORM_INPUTS = {
|
|
|
585
893
|
}
|
|
586
894
|
}
|
|
587
895
|
),
|
|
588
|
-
DEFAULT: ({ value, onChange }) => /* @__PURE__ */ (0,
|
|
896
|
+
DEFAULT: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
589
897
|
"input",
|
|
590
898
|
{
|
|
591
899
|
type: "text",
|
|
@@ -597,7 +905,8 @@ var FORM_INPUTS = {
|
|
|
597
905
|
};
|
|
598
906
|
|
|
599
907
|
// src/components/TableBlock/TableBlockClient.tsx
|
|
600
|
-
var
|
|
908
|
+
var import_lucide_react4 = require("lucide-react");
|
|
909
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
601
910
|
function TableBlockClient({
|
|
602
911
|
data: initialRecords,
|
|
603
912
|
settings: schema,
|
|
@@ -614,6 +923,68 @@ function TableBlockClient({
|
|
|
614
923
|
"data-testid": dataTestId
|
|
615
924
|
}) {
|
|
616
925
|
const { showError, addToast } = useToast();
|
|
926
|
+
const [columnWidths, setColumnWidths] = (0, import_react6.useState)({});
|
|
927
|
+
const [isMounted, setIsMounted] = (0, import_react6.useState)(false);
|
|
928
|
+
const tableKey = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id) || (schema == null ? void 0 : schema.name) || "default";
|
|
929
|
+
const [page, setPage] = (0, import_react6.useState)(1);
|
|
930
|
+
const [limit, setLimit] = (0, import_react6.useState)(50);
|
|
931
|
+
const [totalRecords, setTotalRecords] = (0, import_react6.useState)(0);
|
|
932
|
+
const [totalPages, setTotalPages] = (0, import_react6.useState)(1);
|
|
933
|
+
(0, import_react6.useEffect)(() => {
|
|
934
|
+
if (typeof window !== "undefined") {
|
|
935
|
+
const savedWidths = localStorage.getItem(`table_widths_${tableKey}`);
|
|
936
|
+
if (savedWidths) {
|
|
937
|
+
try {
|
|
938
|
+
setColumnWidths(JSON.parse(savedWidths));
|
|
939
|
+
} catch (e) {
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
const savedSummary = localStorage.getItem(`table_summary_${tableKey}`);
|
|
943
|
+
if (savedSummary !== null) {
|
|
944
|
+
setShowSummary(savedSummary === "true");
|
|
945
|
+
}
|
|
946
|
+
const savedLimit = localStorage.getItem(`table_limit_${tableKey}`);
|
|
947
|
+
if (savedLimit) {
|
|
948
|
+
const parsed = parseInt(savedLimit, 10);
|
|
949
|
+
if ([20, 50, 100].includes(parsed)) {
|
|
950
|
+
setLimit(parsed);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
setIsMounted(true);
|
|
955
|
+
}, [tableKey]);
|
|
956
|
+
const [showSummary, setShowSummary] = (0, import_react6.useState)(false);
|
|
957
|
+
const toggleSummary = () => {
|
|
958
|
+
setShowSummary((prev) => {
|
|
959
|
+
const next = !prev;
|
|
960
|
+
const tableKey2 = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id) || (schema == null ? void 0 : schema.name) || "default";
|
|
961
|
+
localStorage.setItem(`table_summary_${tableKey2}`, String(next));
|
|
962
|
+
return next;
|
|
963
|
+
});
|
|
964
|
+
};
|
|
965
|
+
const [resizingCol, setResizingCol] = (0, import_react6.useState)(null);
|
|
966
|
+
(0, import_react6.useEffect)(() => {
|
|
967
|
+
if (!resizingCol) return;
|
|
968
|
+
const handleMouseMove = (e) => {
|
|
969
|
+
const diffX = resizingCol.startX - e.clientX;
|
|
970
|
+
const newWidth = Math.max(100, Math.min(500, resizingCol.startWidth + diffX));
|
|
971
|
+
setColumnWidths((prev) => __spreadProps(__spreadValues({}, prev), { [resizingCol.name]: newWidth }));
|
|
972
|
+
};
|
|
973
|
+
const handleMouseUp = () => {
|
|
974
|
+
setResizingCol(null);
|
|
975
|
+
setColumnWidths((prev) => {
|
|
976
|
+
const tableKey2 = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id) || (schema == null ? void 0 : schema.name) || "default";
|
|
977
|
+
localStorage.setItem(`table_widths_${tableKey2}`, JSON.stringify(prev));
|
|
978
|
+
return prev;
|
|
979
|
+
});
|
|
980
|
+
};
|
|
981
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
982
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
983
|
+
return () => {
|
|
984
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
985
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
986
|
+
};
|
|
987
|
+
}, [resizingCol, schema]);
|
|
617
988
|
const normalizeRecords = (records) => {
|
|
618
989
|
return (records || []).map((row) => {
|
|
619
990
|
var _c;
|
|
@@ -639,18 +1010,38 @@ function TableBlockClient({
|
|
|
639
1010
|
return __spreadProps(__spreadValues({}, row), { id: String(row.id || ""), data: rowData });
|
|
640
1011
|
});
|
|
641
1012
|
};
|
|
642
|
-
const
|
|
643
|
-
|
|
1013
|
+
const mergeColumnDefs = (0, import_react6.useCallback)((existingCols, incomingCols) => {
|
|
1014
|
+
if (!incomingCols || incomingCols.length === 0) return existingCols || [];
|
|
1015
|
+
if (!existingCols || existingCols.length === 0) return incomingCols;
|
|
1016
|
+
const existingMap = new Map(existingCols.map((c) => [c.name, c]));
|
|
1017
|
+
const merged = incomingCols.map((inc) => {
|
|
1018
|
+
const ext = existingMap.get(inc.name);
|
|
1019
|
+
if (ext) {
|
|
1020
|
+
existingMap.delete(inc.name);
|
|
1021
|
+
return __spreadValues(__spreadValues({}, ext), inc);
|
|
1022
|
+
}
|
|
1023
|
+
return inc;
|
|
1024
|
+
});
|
|
1025
|
+
for (const [, extCol] of existingMap) {
|
|
1026
|
+
merged.push(extCol);
|
|
1027
|
+
}
|
|
1028
|
+
return merged.sort((a, b) => {
|
|
1029
|
+
var _a, _b;
|
|
1030
|
+
return ((_a = a.order) != null ? _a : 0) - ((_b = b.order) != null ? _b : 0);
|
|
1031
|
+
});
|
|
1032
|
+
}, []);
|
|
1033
|
+
const [localColumns, setLocalColumns] = (0, import_react6.useState)(() => (schema == null ? void 0 : schema.columns) || []);
|
|
1034
|
+
(0, import_react6.useEffect)(() => {
|
|
644
1035
|
if ((schema == null ? void 0 : schema.columns) && schema.columns.length > 0) {
|
|
645
|
-
setLocalColumns(schema.columns);
|
|
1036
|
+
setLocalColumns((prev) => mergeColumnDefs(prev, schema.columns));
|
|
646
1037
|
}
|
|
647
|
-
}, [schema == null ? void 0 : schema.columns]);
|
|
648
|
-
const [dirty, setDirty] = (0,
|
|
649
|
-
const dirtyRef = (0,
|
|
650
|
-
(0,
|
|
1038
|
+
}, [schema == null ? void 0 : schema.columns, mergeColumnDefs]);
|
|
1039
|
+
const [dirty, setDirty] = (0, import_react6.useState)({ added: [], modified: {}, deleted: [] });
|
|
1040
|
+
const dirtyRef = (0, import_react6.useRef)(dirty);
|
|
1041
|
+
(0, import_react6.useEffect)(() => {
|
|
651
1042
|
dirtyRef.current = dirty;
|
|
652
1043
|
}, [dirty]);
|
|
653
|
-
const mergeWithDirty = (0,
|
|
1044
|
+
const mergeWithDirty = (0, import_react6.useCallback)((baseRecords) => {
|
|
654
1045
|
const { added, modified, deleted } = dirtyRef.current;
|
|
655
1046
|
const nonDeleted = (baseRecords || []).filter((r) => !deleted.includes(r.id));
|
|
656
1047
|
const modifiedRecords = nonDeleted.map((r) => {
|
|
@@ -663,8 +1054,8 @@ function TableBlockClient({
|
|
|
663
1054
|
const uniqueAdded = added.filter((r) => !baseIds.has(r.id));
|
|
664
1055
|
return [...uniqueAdded, ...modifiedRecords];
|
|
665
1056
|
}, []);
|
|
666
|
-
const [data, setData] = (0,
|
|
667
|
-
(0,
|
|
1057
|
+
const [data, setData] = (0, import_react6.useState)(() => normalizeRecords(initialRecords));
|
|
1058
|
+
(0, import_react6.useEffect)(() => {
|
|
668
1059
|
if (initialRecords) {
|
|
669
1060
|
setData(mergeWithDirty(normalizeRecords(initialRecords)));
|
|
670
1061
|
}
|
|
@@ -679,54 +1070,82 @@ function TableBlockClient({
|
|
|
679
1070
|
}
|
|
680
1071
|
return false;
|
|
681
1072
|
};
|
|
682
|
-
const [baseRecordsMap, setBaseRecordsMap] = (0,
|
|
1073
|
+
const [baseRecordsMap, setBaseRecordsMap] = (0, import_react6.useState)(() => {
|
|
683
1074
|
const map = /* @__PURE__ */ new Map();
|
|
684
1075
|
(normalizeRecords(initialRecords) || []).forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
|
|
685
1076
|
return map;
|
|
686
1077
|
});
|
|
687
|
-
(0,
|
|
1078
|
+
(0, import_react6.useEffect)(() => {
|
|
688
1079
|
if (initialRecords && initialRecords.length > 0) {
|
|
689
1080
|
const map = /* @__PURE__ */ new Map();
|
|
690
1081
|
(normalizeRecords(initialRecords) || []).forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
|
|
691
1082
|
setBaseRecordsMap(map);
|
|
692
1083
|
}
|
|
693
1084
|
}, [initialRecords]);
|
|
694
|
-
(0,
|
|
1085
|
+
const refetchTableData = (0, import_react6.useCallback)((targetPage) => {
|
|
695
1086
|
const tableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
|
|
696
|
-
if (!tableId || !executeAction) return;
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
1087
|
+
if (!tableId || !executeAction) return Promise.resolve();
|
|
1088
|
+
const activePage = targetPage !== void 0 ? targetPage : page;
|
|
1089
|
+
const skip = (activePage - 1) * limit;
|
|
1090
|
+
return executeAction("FETCH_TABLE_DATA", { tableId, page: activePage, limit, skip }).then((res) => {
|
|
1091
|
+
var _a;
|
|
1092
|
+
if (res) {
|
|
1093
|
+
if (((_a = res.schema) == null ? void 0 : _a.columns) && res.schema.columns.length > 0) {
|
|
1094
|
+
setLocalColumns((prev) => mergeColumnDefs(prev, res.schema.columns));
|
|
1095
|
+
}
|
|
1096
|
+
if (res.records && Array.isArray(res.records)) {
|
|
1097
|
+
const norm = normalizeRecords(res.records);
|
|
1098
|
+
const map = /* @__PURE__ */ new Map();
|
|
1099
|
+
norm.forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
|
|
1100
|
+
setBaseRecordsMap(map);
|
|
1101
|
+
setData(norm);
|
|
1102
|
+
}
|
|
1103
|
+
if (res.meta) {
|
|
1104
|
+
const total = typeof res.meta.totalRecords === "number" ? res.meta.totalRecords : 0;
|
|
1105
|
+
const pages = typeof res.meta.totalPages === "number" ? res.meta.totalPages : Math.ceil(total / limit) || 1;
|
|
1106
|
+
setTotalRecords(total);
|
|
1107
|
+
setTotalPages(pages);
|
|
1108
|
+
if (activePage > pages && pages >= 1) {
|
|
1109
|
+
setPage(pages);
|
|
710
1110
|
}
|
|
1111
|
+
} else if (res.records && Array.isArray(res.records)) {
|
|
1112
|
+
setTotalRecords(res.records.length);
|
|
1113
|
+
setTotalPages(Math.ceil(res.records.length / limit) || 1);
|
|
711
1114
|
}
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
|
|
1115
|
+
}
|
|
1116
|
+
}).catch((err) => {
|
|
1117
|
+
console.error("[TableBlock] Failed to auto-fetch table data:", err);
|
|
1118
|
+
});
|
|
1119
|
+
}, [schema == null ? void 0 : schema.tableMetaId, schema == null ? void 0 : schema.tableId, schema == null ? void 0 : schema.id, page, limit, executeAction, mergeWithDirty, mergeColumnDefs]);
|
|
1120
|
+
(0, import_react6.useEffect)(() => {
|
|
1121
|
+
refetchTableData();
|
|
1122
|
+
}, [refetchTableData]);
|
|
1123
|
+
const handleLimitChange = (newLimit) => {
|
|
1124
|
+
setLimit(newLimit);
|
|
1125
|
+
setPage(1);
|
|
1126
|
+
if (typeof window !== "undefined") {
|
|
1127
|
+
localStorage.setItem(`table_limit_${tableKey}`, String(newLimit));
|
|
715
1128
|
}
|
|
716
|
-
}
|
|
717
|
-
|
|
1129
|
+
};
|
|
1130
|
+
const handlePrevPage = () => {
|
|
1131
|
+
setPage((prev) => Math.max(1, prev - 1));
|
|
1132
|
+
};
|
|
1133
|
+
const handleNextPage = () => {
|
|
1134
|
+
setPage((prev) => Math.min(totalPages, prev + 1));
|
|
1135
|
+
};
|
|
1136
|
+
(0, import_react6.useEffect)(() => {
|
|
718
1137
|
if (error) {
|
|
719
1138
|
showError(error, "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E8\u05DB\u05D9\u05D1");
|
|
720
1139
|
}
|
|
721
1140
|
}, [error, showError]);
|
|
722
|
-
const [searchQuery, setSearchQuery] = (0,
|
|
723
|
-
const [selectedIds, setSelectedIds] = (0,
|
|
724
|
-
const [pendingDeletions, setPendingDeletions] = (0,
|
|
725
|
-
const [isSaving, setIsSaving] = (0,
|
|
726
|
-
const [isSaveSuccess, setIsSaveSuccess] = (0,
|
|
727
|
-
const [relationOptions, setRelationOptions] = (0,
|
|
728
|
-
const schemaColsString = (0,
|
|
729
|
-
const refetchRelation = (0,
|
|
1141
|
+
const [searchQuery, setSearchQuery] = (0, import_react6.useState)("");
|
|
1142
|
+
const [selectedIds, setSelectedIds] = (0, import_react6.useState)(/* @__PURE__ */ new Set());
|
|
1143
|
+
const [pendingDeletions, setPendingDeletions] = (0, import_react6.useState)([]);
|
|
1144
|
+
const [isSaving, setIsSaving] = (0, import_react6.useState)(false);
|
|
1145
|
+
const [isSaveSuccess, setIsSaveSuccess] = (0, import_react6.useState)(false);
|
|
1146
|
+
const [relationOptions, setRelationOptions] = (0, import_react6.useState)({});
|
|
1147
|
+
const schemaColsString = (0, import_react6.useMemo)(() => JSON.stringify(localColumns || []), [localColumns]);
|
|
1148
|
+
const refetchRelation = (0, import_react6.useCallback)(async (colName) => {
|
|
730
1149
|
var _a;
|
|
731
1150
|
let parsedCols = [];
|
|
732
1151
|
try {
|
|
@@ -746,7 +1165,7 @@ function TableBlockClient({
|
|
|
746
1165
|
console.warn(`[TableBlock] Could not fetch relation options for column ${colName}:`, err);
|
|
747
1166
|
}
|
|
748
1167
|
}, [schemaColsString, executeAction]);
|
|
749
|
-
(0,
|
|
1168
|
+
(0, import_react6.useEffect)(() => {
|
|
750
1169
|
let parsedCols = [];
|
|
751
1170
|
try {
|
|
752
1171
|
parsedCols = JSON.parse(schemaColsString);
|
|
@@ -760,10 +1179,144 @@ function TableBlockClient({
|
|
|
760
1179
|
refetchRelation(col.name);
|
|
761
1180
|
});
|
|
762
1181
|
}, [schemaColsString, refetchRelation]);
|
|
763
|
-
const
|
|
764
|
-
|
|
765
|
-
|
|
1182
|
+
const normalizedColumns = (0, import_react6.useMemo)(() => {
|
|
1183
|
+
return (localColumns || []).map((col, idx) => {
|
|
1184
|
+
const isRequired = col.isRequired === true || String(col.isRequired) === "true";
|
|
1185
|
+
const isUnique = col.isUnique === true || String(col.isUnique) === "true";
|
|
1186
|
+
const isProtected = isRequired || isUnique;
|
|
1187
|
+
return __spreadProps(__spreadValues({}, col), {
|
|
1188
|
+
order: typeof col.order === "number" ? col.order : idx,
|
|
1189
|
+
isHidden: isProtected ? false : Boolean(col.isHidden)
|
|
1190
|
+
});
|
|
1191
|
+
}).sort((a, b) => {
|
|
1192
|
+
var _a, _b;
|
|
1193
|
+
return ((_a = a.order) != null ? _a : 0) - ((_b = b.order) != null ? _b : 0);
|
|
1194
|
+
});
|
|
766
1195
|
}, [localColumns]);
|
|
1196
|
+
const filteredColumns = (0, import_react6.useMemo)(() => {
|
|
1197
|
+
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
1198
|
+
return normalizedColumns.filter((col) => !systemFields.includes(col.name) && !col.isHidden);
|
|
1199
|
+
}, [normalizedColumns]);
|
|
1200
|
+
const customizableColumns = (0, import_react6.useMemo)(() => {
|
|
1201
|
+
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
1202
|
+
return normalizedColumns.filter((col) => !systemFields.includes(col.name));
|
|
1203
|
+
}, [normalizedColumns]);
|
|
1204
|
+
const [isColumnsDropdownOpen, setIsColumnsDropdownOpen] = (0, import_react6.useState)(false);
|
|
1205
|
+
const dropdownRef = (0, import_react6.useRef)(null);
|
|
1206
|
+
(0, import_react6.useEffect)(() => {
|
|
1207
|
+
const handleClickOutside = (e) => {
|
|
1208
|
+
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
1209
|
+
setIsColumnsDropdownOpen(false);
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
if (isColumnsDropdownOpen) {
|
|
1213
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
1214
|
+
}
|
|
1215
|
+
return () => {
|
|
1216
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
1217
|
+
};
|
|
1218
|
+
}, [isColumnsDropdownOpen]);
|
|
1219
|
+
const handleShowAllColumns = async () => {
|
|
1220
|
+
var _a;
|
|
1221
|
+
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
1222
|
+
const systemCols = (localColumns || []).filter((c) => systemFields.includes(c.name));
|
|
1223
|
+
const updatedCustomCols = customizableColumns.map((col) => __spreadProps(__spreadValues({}, col), {
|
|
1224
|
+
isHidden: false
|
|
1225
|
+
}));
|
|
1226
|
+
const fullUpdatedColumns = [...systemCols, ...updatedCustomCols];
|
|
1227
|
+
setLocalColumns(fullUpdatedColumns);
|
|
1228
|
+
const targetTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
|
|
1229
|
+
if (targetTableId && executeAction) {
|
|
1230
|
+
try {
|
|
1231
|
+
const res = await executeAction("UPDATE_TABLE_COLUMNS", {
|
|
1232
|
+
tableId: targetTableId,
|
|
1233
|
+
tableMetaId: targetTableId,
|
|
1234
|
+
columns: fullUpdatedColumns
|
|
1235
|
+
});
|
|
1236
|
+
const returnedCols = (res == null ? void 0 : res.columns) || ((_a = res == null ? void 0 : res.data) == null ? void 0 : _a.columns);
|
|
1237
|
+
if (returnedCols && Array.isArray(returnedCols)) {
|
|
1238
|
+
setLocalColumns((prev) => mergeColumnDefs(prev, returnedCols));
|
|
1239
|
+
}
|
|
1240
|
+
} catch (err) {
|
|
1241
|
+
console.error("[TableBlock] Failed to save show all columns:", err);
|
|
1242
|
+
showError((err == null ? void 0 : err.message) || String(err), "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05D4\u05E6\u05D2\u05EA \u05DB\u05DC \u05D4\u05E2\u05DE\u05D5\u05D3\u05D5\u05EA");
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
};
|
|
1246
|
+
const handleToggleColumnVisibility = async (colName, isVisible) => {
|
|
1247
|
+
var _a;
|
|
1248
|
+
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
1249
|
+
const systemCols = (localColumns || []).filter((c) => systemFields.includes(c.name));
|
|
1250
|
+
const updatedCustomCols = customizableColumns.map((col) => {
|
|
1251
|
+
const isRequired = col.isRequired === true || String(col.isRequired) === "true";
|
|
1252
|
+
const isUnique = col.isUnique === true || String(col.isUnique) === "true";
|
|
1253
|
+
const isProtected = isRequired || isUnique;
|
|
1254
|
+
if (col.name === colName) {
|
|
1255
|
+
if (isProtected) {
|
|
1256
|
+
return __spreadProps(__spreadValues({}, col), { isHidden: false });
|
|
1257
|
+
}
|
|
1258
|
+
return __spreadProps(__spreadValues({}, col), { isHidden: !isVisible });
|
|
1259
|
+
}
|
|
1260
|
+
return __spreadProps(__spreadValues({}, col), {
|
|
1261
|
+
isHidden: isProtected ? false : Boolean(col.isHidden)
|
|
1262
|
+
});
|
|
1263
|
+
});
|
|
1264
|
+
const fullUpdatedColumns = [...systemCols, ...updatedCustomCols];
|
|
1265
|
+
setLocalColumns(fullUpdatedColumns);
|
|
1266
|
+
const targetTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
|
|
1267
|
+
if (targetTableId && executeAction) {
|
|
1268
|
+
try {
|
|
1269
|
+
const res = await executeAction("UPDATE_TABLE_COLUMNS", {
|
|
1270
|
+
tableId: targetTableId,
|
|
1271
|
+
tableMetaId: targetTableId,
|
|
1272
|
+
columns: fullUpdatedColumns
|
|
1273
|
+
});
|
|
1274
|
+
const returnedCols = (res == null ? void 0 : res.columns) || ((_a = res == null ? void 0 : res.data) == null ? void 0 : _a.columns);
|
|
1275
|
+
if (returnedCols && Array.isArray(returnedCols)) {
|
|
1276
|
+
setLocalColumns((prev) => mergeColumnDefs(prev, returnedCols));
|
|
1277
|
+
}
|
|
1278
|
+
} catch (err) {
|
|
1279
|
+
console.error("[TableBlock] Failed to save column visibility:", err);
|
|
1280
|
+
showError((err == null ? void 0 : err.message) || String(err), "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E2\u05D3\u05DB\u05D5\u05DF \u05D4\u05E1\u05EA\u05E8\u05EA \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA");
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
};
|
|
1284
|
+
const [draggedColName, setDraggedColName] = (0, import_react6.useState)(null);
|
|
1285
|
+
const [dragOverColName, setDragOverColName] = (0, import_react6.useState)(null);
|
|
1286
|
+
const handleColumnReorder = async (draggedName, dropTargetName) => {
|
|
1287
|
+
var _a;
|
|
1288
|
+
if (draggedName === dropTargetName) return;
|
|
1289
|
+
const currentCustomCols = [...customizableColumns];
|
|
1290
|
+
const fromIndex = currentCustomCols.findIndex((c) => c.name === draggedName);
|
|
1291
|
+
const toIndex = currentCustomCols.findIndex((c) => c.name === dropTargetName);
|
|
1292
|
+
if (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) return;
|
|
1293
|
+
const [draggedItem] = currentCustomCols.splice(fromIndex, 1);
|
|
1294
|
+
currentCustomCols.splice(toIndex, 0, draggedItem);
|
|
1295
|
+
const updatedCustomCols = currentCustomCols.map((col, idx) => __spreadProps(__spreadValues({}, col), {
|
|
1296
|
+
order: idx
|
|
1297
|
+
}));
|
|
1298
|
+
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
1299
|
+
const systemCols = (localColumns || []).filter((c) => systemFields.includes(c.name));
|
|
1300
|
+
const fullUpdatedColumns = [...systemCols, ...updatedCustomCols];
|
|
1301
|
+
setLocalColumns(fullUpdatedColumns);
|
|
1302
|
+
const targetTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
|
|
1303
|
+
if (targetTableId && executeAction) {
|
|
1304
|
+
try {
|
|
1305
|
+
const res = await executeAction("UPDATE_TABLE_COLUMNS", {
|
|
1306
|
+
tableId: targetTableId,
|
|
1307
|
+
tableMetaId: targetTableId,
|
|
1308
|
+
columns: fullUpdatedColumns
|
|
1309
|
+
});
|
|
1310
|
+
const returnedCols = (res == null ? void 0 : res.columns) || ((_a = res == null ? void 0 : res.data) == null ? void 0 : _a.columns);
|
|
1311
|
+
if (returnedCols && Array.isArray(returnedCols)) {
|
|
1312
|
+
setLocalColumns((prev) => mergeColumnDefs(prev, returnedCols));
|
|
1313
|
+
}
|
|
1314
|
+
} catch (err) {
|
|
1315
|
+
console.error("[TableBlock] Failed to save column reorder:", err);
|
|
1316
|
+
showError((err == null ? void 0 : err.message) || String(err), "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E2\u05D3\u05DB\u05D5\u05DF \u05E1\u05D3\u05E8 \u05D4\u05E2\u05DE\u05D5\u05D3\u05D5\u05EA");
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
};
|
|
767
1320
|
const generateTempId = () => `temp_${Math.random().toString(36).substr(2, 9)}`;
|
|
768
1321
|
const handleAddRow = () => {
|
|
769
1322
|
const defaultData = {};
|
|
@@ -793,6 +1346,34 @@ function TableBlockClient({
|
|
|
793
1346
|
setData((prev) => [newRow, ...prev]);
|
|
794
1347
|
setDirty((prev) => __spreadProps(__spreadValues({}, prev), { added: [newRow, ...prev.added] }));
|
|
795
1348
|
};
|
|
1349
|
+
const handleDuplicateRow = () => {
|
|
1350
|
+
if (selectedIds.size !== 1) return;
|
|
1351
|
+
const targetId = Array.from(selectedIds)[0];
|
|
1352
|
+
const sourceRow = data.find((r) => r.id === targetId);
|
|
1353
|
+
if (!sourceRow) return;
|
|
1354
|
+
const uniqueColNames = new Set(
|
|
1355
|
+
(localColumns || []).filter((c) => c.isUnique === true || String(c.isUnique) === "true").map((c) => c.name)
|
|
1356
|
+
);
|
|
1357
|
+
const fieldsToScrub = /* @__PURE__ */ new Set(["id", "_id", "createdAt", "updatedAt", "created_at", "updated_at"]);
|
|
1358
|
+
const clonedData = __spreadValues({}, sourceRow.data);
|
|
1359
|
+
Object.keys(clonedData).forEach((key) => {
|
|
1360
|
+
var _a;
|
|
1361
|
+
if (fieldsToScrub.has(key) || uniqueColNames.has(key)) {
|
|
1362
|
+
const col = (localColumns || []).find((c) => c.name === key);
|
|
1363
|
+
const typeUpper = (_a = col == null ? void 0 : col.type) == null ? void 0 : _a.toUpperCase();
|
|
1364
|
+
if (typeUpper === "NUMBER" || typeUpper === "CURRENCY") {
|
|
1365
|
+
clonedData[key] = 0;
|
|
1366
|
+
} else if (typeUpper === "BOOLEAN") {
|
|
1367
|
+
clonedData[key] = false;
|
|
1368
|
+
} else {
|
|
1369
|
+
clonedData[key] = "";
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
});
|
|
1373
|
+
const newRow = { id: generateTempId(), data: clonedData };
|
|
1374
|
+
setData((prev) => [newRow, ...prev]);
|
|
1375
|
+
setDirty((prev) => __spreadProps(__spreadValues({}, prev), { added: [newRow, ...prev.added] }));
|
|
1376
|
+
};
|
|
796
1377
|
const handleCellChange = (rowId, colName, value) => {
|
|
797
1378
|
setData((prev) => prev.map(
|
|
798
1379
|
(row) => row.id === rowId ? __spreadProps(__spreadValues({}, row), { data: __spreadProps(__spreadValues({}, row.data), { [colName]: value }) }) : row
|
|
@@ -1013,6 +1594,7 @@ function TableBlockClient({
|
|
|
1013
1594
|
return next;
|
|
1014
1595
|
});
|
|
1015
1596
|
setDirty({ added: [], modified: {}, deleted: [] });
|
|
1597
|
+
await refetchTableData();
|
|
1016
1598
|
setIsSaveSuccess(true);
|
|
1017
1599
|
setTimeout(() => {
|
|
1018
1600
|
setIsSaveSuccess(false);
|
|
@@ -1025,7 +1607,7 @@ function TableBlockClient({
|
|
|
1025
1607
|
setIsSaving(false);
|
|
1026
1608
|
}
|
|
1027
1609
|
};
|
|
1028
|
-
const filteredData = (0,
|
|
1610
|
+
const filteredData = (0, import_react6.useMemo)(() => {
|
|
1029
1611
|
if (!searchQuery) return data;
|
|
1030
1612
|
const lowerQuery = searchQuery.toLowerCase();
|
|
1031
1613
|
return data.filter(
|
|
@@ -1036,32 +1618,60 @@ function TableBlockClient({
|
|
|
1036
1618
|
}, [data, searchQuery]);
|
|
1037
1619
|
const isUpdatingActive = Boolean(isUpdating || isSaving);
|
|
1038
1620
|
const errorMessage = error ? typeof error === "string" ? error : error.message || String(error) : null;
|
|
1039
|
-
|
|
1621
|
+
const columnTotals = (0, import_react6.useMemo)(() => {
|
|
1622
|
+
const totals = {};
|
|
1623
|
+
if (!showSummary) return totals;
|
|
1624
|
+
filteredColumns.forEach((col) => {
|
|
1625
|
+
var _a;
|
|
1626
|
+
const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
|
|
1627
|
+
if (typeUpper === "CURRENCY" || typeUpper === "NUMBER") {
|
|
1628
|
+
const sum = filteredData.reduce((acc, row) => {
|
|
1629
|
+
var _a2;
|
|
1630
|
+
const val = (_a2 = row.data) == null ? void 0 : _a2[col.name];
|
|
1631
|
+
const num = Number(val);
|
|
1632
|
+
return acc + (isNaN(num) ? 0 : num);
|
|
1633
|
+
}, 0);
|
|
1634
|
+
totals[col.name] = sum;
|
|
1635
|
+
}
|
|
1636
|
+
});
|
|
1637
|
+
return totals;
|
|
1638
|
+
}, [filteredData, filteredColumns, showSummary]);
|
|
1639
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1040
1640
|
"div",
|
|
1041
1641
|
{
|
|
1042
1642
|
id: componentId,
|
|
1043
1643
|
"data-testid": dataTestId || (componentId ? `table-block-${componentId}` : void 0),
|
|
1044
|
-
className: `flex flex-col w-full bg-white border border-slate-200 rounded-xl shadow-xs overflow-hidden ${className}`,
|
|
1644
|
+
className: `flex flex-col w-full bg-white border border-slate-200 rounded-xl shadow-xs min-h-[350px] overflow-hidden ${className}`,
|
|
1045
1645
|
dir: "rtl",
|
|
1046
1646
|
children: [
|
|
1047
|
-
errorMessage && /* @__PURE__ */ (0,
|
|
1048
|
-
/* @__PURE__ */ (0,
|
|
1049
|
-
/* @__PURE__ */ (0,
|
|
1647
|
+
errorMessage && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "p-3 bg-rose-50 border-b border-rose-200 text-rose-700 text-sm flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1648
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4 h-4 text-rose-500 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
|
|
1649
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: errorMessage })
|
|
1050
1650
|
] }) }),
|
|
1051
|
-
/* @__PURE__ */ (0,
|
|
1052
|
-
/* @__PURE__ */ (0,
|
|
1053
|
-
((schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.name)) && /* @__PURE__ */ (0,
|
|
1054
|
-
/* @__PURE__ */ (0,
|
|
1651
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-3 p-3.5 sm:p-4 bg-slate-50 border-b border-slate-200", children: [
|
|
1652
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-wrap items-center gap-2.5", children: [
|
|
1653
|
+
((schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.name)) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "font-bold text-slate-800 text-sm sm:text-base border-l border-slate-300 pl-3 ml-1", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: schema.title || schema.name }) }),
|
|
1654
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1055
1655
|
"button",
|
|
1056
1656
|
{
|
|
1057
1657
|
onClick: handleAddRow,
|
|
1058
1658
|
disabled: isLoading || isUpdatingActive,
|
|
1059
1659
|
className: "w-9 h-9 bg-emerald-600 hover:bg-emerald-700 active:bg-emerald-800 text-white rounded-lg shadow-xs flex items-center justify-center transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer",
|
|
1060
1660
|
title: "\u05D4\u05D5\u05E1\u05E3 \u05E9\u05D5\u05E8\u05D4 \u05D7\u05D3\u05E9\u05D4",
|
|
1061
|
-
children: /* @__PURE__ */ (0,
|
|
1661
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4.5 h-4.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M12 4v16m8-8H4" }) })
|
|
1662
|
+
}
|
|
1663
|
+
),
|
|
1664
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1665
|
+
"button",
|
|
1666
|
+
{
|
|
1667
|
+
onClick: handleDuplicateRow,
|
|
1668
|
+
disabled: isLoading || isUpdatingActive || selectedIds.size !== 1,
|
|
1669
|
+
className: "w-9 h-9 bg-blue-50 hover:bg-blue-100 border border-blue-200 text-blue-700 rounded-lg shadow-2xs flex items-center justify-center transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer",
|
|
1670
|
+
title: "\u05E9\u05DB\u05E4\u05DC \u05E9\u05D5\u05E8\u05D4 \u05E0\u05D1\u05D7\u05E8\u05EA",
|
|
1671
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react4.Copy, { className: "w-4 h-4 text-blue-600 shrink-0" })
|
|
1062
1672
|
}
|
|
1063
1673
|
),
|
|
1064
|
-
/* @__PURE__ */ (0,
|
|
1674
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1065
1675
|
"button",
|
|
1066
1676
|
{
|
|
1067
1677
|
onClick: handleDeleteSelected,
|
|
@@ -1069,14 +1679,120 @@ function TableBlockClient({
|
|
|
1069
1679
|
className: "w-9 h-9 bg-rose-50 hover:bg-rose-100 border border-rose-200 text-rose-700 rounded-lg shadow-2xs flex items-center justify-center relative transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer",
|
|
1070
1680
|
title: "\u05DE\u05D7\u05E7 \u05E9\u05D5\u05E8\u05D5\u05EA \u05E0\u05D1\u05D7\u05E8\u05D5\u05EA",
|
|
1071
1681
|
children: [
|
|
1072
|
-
/* @__PURE__ */ (0,
|
|
1073
|
-
selectedIds.size > 0 && /* @__PURE__ */ (0,
|
|
1682
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4.5 h-4.5 text-rose-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }),
|
|
1683
|
+
selectedIds.size > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "absolute -top-1.5 -right-1.5 bg-rose-600 text-white min-w-[18px] h-[18px] px-1 rounded-full text-[10px] font-bold flex items-center justify-center shadow-xs", children: selectedIds.size })
|
|
1074
1684
|
]
|
|
1075
1685
|
}
|
|
1076
1686
|
),
|
|
1077
|
-
/* @__PURE__ */ (0,
|
|
1078
|
-
|
|
1079
|
-
|
|
1687
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1688
|
+
"button",
|
|
1689
|
+
{
|
|
1690
|
+
onClick: toggleSummary,
|
|
1691
|
+
disabled: isLoading || isUpdatingActive,
|
|
1692
|
+
className: `h-9 px-3 border font-semibold rounded-lg shadow-2xs flex items-center gap-1.5 text-xs transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer ${showSummary ? "bg-indigo-50 border-indigo-200 text-indigo-700 hover:bg-indigo-100" : "bg-white border-slate-300 text-slate-700 hover:bg-slate-100"}`,
|
|
1693
|
+
title: "\u05D4\u05E6\u05D2/\u05D4\u05E1\u05EA\u05E8 \u05E9\u05D5\u05E8\u05EA \u05E1\u05D9\u05DB\u05D5\u05DD",
|
|
1694
|
+
children: [
|
|
1695
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) }),
|
|
1696
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "hidden sm:inline", children: "\u05E1\u05DB\u05D9\u05DE\u05D4" })
|
|
1697
|
+
]
|
|
1698
|
+
}
|
|
1699
|
+
),
|
|
1700
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "relative", ref: dropdownRef, children: [
|
|
1701
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1702
|
+
"button",
|
|
1703
|
+
{
|
|
1704
|
+
onClick: () => setIsColumnsDropdownOpen((prev) => !prev),
|
|
1705
|
+
disabled: isLoading || isUpdatingActive,
|
|
1706
|
+
className: "h-9 px-3 bg-white hover:bg-slate-100 border border-slate-300 text-slate-700 font-semibold rounded-lg shadow-2xs flex items-center gap-1.5 text-xs transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer",
|
|
1707
|
+
title: "\u05D4\u05E6\u05D2/\u05D4\u05E1\u05EA\u05E8 \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA",
|
|
1708
|
+
children: [
|
|
1709
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4 h-4 text-slate-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2" }) }),
|
|
1710
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: `w-3.5 h-3.5 text-slate-500 transition-transform ${isColumnsDropdownOpen ? "rotate-180" : ""}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M19 9l-7 7-7-7" }) })
|
|
1711
|
+
]
|
|
1712
|
+
}
|
|
1713
|
+
),
|
|
1714
|
+
isColumnsDropdownOpen && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "absolute right-0 top-full mt-1.5 w-56 bg-white border border-slate-200 rounded-xl shadow-xl z-50 p-1.5 dir-rtl animate-in fade-in slide-in-from-top-2 duration-150", children: [
|
|
1715
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "px-2 py-1.5 text-xs font-bold text-slate-500 border-b border-slate-100 mb-1 flex items-center justify-between", children: [
|
|
1716
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
1717
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u05D4\u05E6\u05D2\u05EA \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA" }),
|
|
1718
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-[10px] font-normal text-slate-400", children: [
|
|
1719
|
+
"(",
|
|
1720
|
+
customizableColumns.filter((c) => !c.isHidden).length,
|
|
1721
|
+
"/",
|
|
1722
|
+
customizableColumns.length,
|
|
1723
|
+
")"
|
|
1724
|
+
] })
|
|
1725
|
+
] }),
|
|
1726
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1727
|
+
"button",
|
|
1728
|
+
{
|
|
1729
|
+
type: "button",
|
|
1730
|
+
onClick: handleShowAllColumns,
|
|
1731
|
+
className: "text-xs text-brand hover:text-brand-hover font-semibold hover:underline cursor-pointer",
|
|
1732
|
+
children: "\u05D4\u05E6\u05D2 \u05D4\u05DB\u05DC"
|
|
1733
|
+
}
|
|
1734
|
+
)
|
|
1735
|
+
] }),
|
|
1736
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "max-h-60 overflow-y-auto space-y-0.5", children: customizableColumns.map((col) => {
|
|
1737
|
+
const isRequired = col.isRequired === true || String(col.isRequired) === "true";
|
|
1738
|
+
const isUnique = col.isUnique === true || String(col.isUnique) === "true";
|
|
1739
|
+
const isProtected = isRequired || isUnique;
|
|
1740
|
+
const isVisible = !col.isHidden;
|
|
1741
|
+
let protectedExplanation = "";
|
|
1742
|
+
if (isRequired && isUnique) {
|
|
1743
|
+
protectedExplanation = "\u05E9\u05D3\u05D4 \u05D7\u05D5\u05D1\u05D4 \u05D5\u05D9\u05D9\u05D7\u05D5\u05D3\u05D9 - \u05DC\u05D0 \u05E0\u05D9\u05EA\u05DF \u05DC\u05D4\u05D5\u05E8\u05D9\u05D3 \u05E2\u05DE\u05D5\u05D3\u05D4 \u05D6\u05D5 \u05DE\u05D4\u05EA\u05E6\u05D5\u05D2\u05D4";
|
|
1744
|
+
} else if (isRequired) {
|
|
1745
|
+
protectedExplanation = "\u05E9\u05D3\u05D4 \u05D7\u05D5\u05D1\u05D4 - \u05DC\u05D0 \u05E0\u05D9\u05EA\u05DF \u05DC\u05D4\u05D5\u05E8\u05D9\u05D3 \u05E2\u05DE\u05D5\u05D3\u05D4 \u05D6\u05D5 \u05DE\u05D4\u05EA\u05E6\u05D5\u05D2\u05D4";
|
|
1746
|
+
} else if (isUnique) {
|
|
1747
|
+
protectedExplanation = "\u05E9\u05D3\u05D4 \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9 - \u05DC\u05D0 \u05E0\u05D9\u05EA\u05DF \u05DC\u05D4\u05D5\u05E8\u05D9\u05D3 \u05E2\u05DE\u05D5\u05D3\u05D4 \u05D6\u05D5 \u05DE\u05D4\u05EA\u05E6\u05D5\u05D2\u05D4";
|
|
1748
|
+
}
|
|
1749
|
+
const badgeLabel = isRequired && isUnique ? "\u05D7\u05D5\u05D1\u05D4 + \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9" : isRequired ? "\u05E9\u05D3\u05D4 \u05D7\u05D5\u05D1\u05D4" : "\u05E9\u05D3\u05D4 \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9";
|
|
1750
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1751
|
+
"div",
|
|
1752
|
+
{
|
|
1753
|
+
onClick: () => {
|
|
1754
|
+
if (!isProtected) {
|
|
1755
|
+
handleToggleColumnVisibility(col.name, !isVisible);
|
|
1756
|
+
}
|
|
1757
|
+
},
|
|
1758
|
+
title: isProtected ? protectedExplanation : void 0,
|
|
1759
|
+
className: `group flex items-center justify-between px-2.5 py-1.5 rounded-lg text-xs transition-colors select-none ${isProtected ? "opacity-75 bg-slate-50 border border-slate-100/70 cursor-not-allowed" : "hover:bg-slate-100 active:bg-slate-200 cursor-pointer"}`,
|
|
1760
|
+
children: [
|
|
1761
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
1762
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1763
|
+
"input",
|
|
1764
|
+
{
|
|
1765
|
+
type: "checkbox",
|
|
1766
|
+
checked: isVisible,
|
|
1767
|
+
disabled: isProtected,
|
|
1768
|
+
onChange: () => {
|
|
1769
|
+
},
|
|
1770
|
+
className: "w-3.5 h-3.5 rounded border-slate-300 text-brand focus:ring-brand/20 cursor-pointer disabled:cursor-not-allowed disabled:opacity-60"
|
|
1771
|
+
}
|
|
1772
|
+
),
|
|
1773
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: `font-medium truncate ${isProtected ? "text-slate-500" : "text-slate-700"}`, children: col.name })
|
|
1774
|
+
] }),
|
|
1775
|
+
isProtected && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1776
|
+
"div",
|
|
1777
|
+
{
|
|
1778
|
+
className: "flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] font-semibold bg-amber-50 text-amber-800 border border-amber-200/80 cursor-help",
|
|
1779
|
+
title: protectedExplanation,
|
|
1780
|
+
children: [
|
|
1781
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3 h-3 text-amber-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: "2.2", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" }) }),
|
|
1782
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: badgeLabel })
|
|
1783
|
+
]
|
|
1784
|
+
}
|
|
1785
|
+
)
|
|
1786
|
+
]
|
|
1787
|
+
},
|
|
1788
|
+
col.name
|
|
1789
|
+
);
|
|
1790
|
+
}) })
|
|
1791
|
+
] })
|
|
1792
|
+
] }),
|
|
1793
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-5 w-px bg-slate-300 mx-1 hidden sm:block" }),
|
|
1794
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "relative flex-1 sm:w-64 max-w-xs", children: [
|
|
1795
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1080
1796
|
"input",
|
|
1081
1797
|
{
|
|
1082
1798
|
placeholder: "\u05D7\u05D9\u05E4\u05D5\u05E9 \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA...",
|
|
@@ -1086,36 +1802,45 @@ function TableBlockClient({
|
|
|
1086
1802
|
className: "w-full h-9 px-3 pr-9 text-xs border border-slate-300 rounded-lg bg-white shadow-2xs focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 text-slate-800 disabled:opacity-50"
|
|
1087
1803
|
}
|
|
1088
1804
|
),
|
|
1089
|
-
|
|
1805
|
+
searchQuery ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1806
|
+
"button",
|
|
1807
|
+
{
|
|
1808
|
+
type: "button",
|
|
1809
|
+
onClick: () => setSearchQuery(""),
|
|
1810
|
+
className: "absolute right-2.5 top-2.5 text-slate-400 hover:text-slate-600 transition-colors p-0.5 rounded-full hover:bg-slate-100 cursor-pointer",
|
|
1811
|
+
title: "Clear search",
|
|
1812
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react4.X, { className: "w-3.5 h-3.5" })
|
|
1813
|
+
}
|
|
1814
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4 h-4 text-slate-400 absolute right-2.5 top-2.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) })
|
|
1090
1815
|
] })
|
|
1091
1816
|
] }),
|
|
1092
|
-
/* @__PURE__ */ (0,
|
|
1093
|
-
isUpdatingActive ? /* @__PURE__ */ (0,
|
|
1094
|
-
/* @__PURE__ */ (0,
|
|
1817
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
1818
|
+
isUpdatingActive ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-xs text-blue-600 font-semibold flex items-center gap-1.5 bg-blue-50 border border-blue-200 px-3 py-1.5 rounded-lg animate-pulse", children: [
|
|
1819
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w-2 h-2 rounded-full bg-blue-500 inline-block" }),
|
|
1095
1820
|
"\u05DE\u05E2\u05D3\u05DB\u05DF..."
|
|
1096
|
-
] }) : isSaveSuccess ? /* @__PURE__ */ (0,
|
|
1097
|
-
/* @__PURE__ */ (0,
|
|
1821
|
+
] }) : isSaveSuccess ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-xs text-emerald-700 font-semibold flex items-center gap-1.5 bg-emerald-50 border border-emerald-200 px-3 py-1.5 rounded-lg animate-in fade-in duration-200", children: [
|
|
1822
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4 h-4 text-emerald-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M5 13l4 4L19 7" }) }),
|
|
1098
1823
|
"\u05E2\u05D5\u05D3\u05DB\u05DF \u05D1\u05D4\u05E6\u05DC\u05D7\u05D4"
|
|
1099
|
-
] }) : hasChanges ? /* @__PURE__ */ (0,
|
|
1100
|
-
/* @__PURE__ */ (0,
|
|
1824
|
+
] }) : hasChanges ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-xs font-semibold text-amber-700 animate-in fade-in", children: "\u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD \u05E9\u05DC\u05D0 \u05E0\u05E9\u05DE\u05E8\u05D5" }) : null,
|
|
1825
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1101
1826
|
"button",
|
|
1102
1827
|
{
|
|
1103
1828
|
onClick: handleSave,
|
|
1104
1829
|
disabled: isUpdatingActive || isLoading || !hasChanges,
|
|
1105
1830
|
className: `h-9 px-4 text-xs font-bold rounded-lg shadow-2xs transition-all flex items-center justify-center cursor-pointer ${hasChanges && !isUpdatingActive && !isLoading ? "bg-brand hover:bg-brand-hover active:bg-[#00897b] text-white shadow-teal-500/20" : "opacity-50 grayscale bg-slate-200 text-slate-400 cursor-not-allowed"}`,
|
|
1106
|
-
children: /* @__PURE__ */ (0,
|
|
1831
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: isUpdatingActive ? "\u05E9\u05D5\u05DE\u05E8..." : "\u05E9\u05DE\u05D9\u05E8\u05EA \u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD" })
|
|
1107
1832
|
}
|
|
1108
1833
|
)
|
|
1109
1834
|
] })
|
|
1110
1835
|
] }),
|
|
1111
|
-
/* @__PURE__ */ (0,
|
|
1112
|
-
isLoading && /* @__PURE__ */ (0,
|
|
1113
|
-
/* @__PURE__ */ (0,
|
|
1114
|
-
/* @__PURE__ */ (0,
|
|
1836
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `overflow-x-auto relative min-h-[260px] flex-1 transition-opacity duration-200 ${isMounted ? "opacity-100" : "opacity-0"}`, children: [
|
|
1837
|
+
isLoading && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "absolute inset-0 bg-white/80 backdrop-blur-xs z-20 flex flex-col items-center justify-center gap-2", children: [
|
|
1838
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-6 h-6 border-2 border-brand border-t-transparent rounded-full animate-spin" }),
|
|
1839
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-sm font-medium text-slate-600", children: "\u05D8\u05D5\u05E2\u05DF \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD..." })
|
|
1115
1840
|
] }),
|
|
1116
|
-
/* @__PURE__ */ (0,
|
|
1117
|
-
/* @__PURE__ */ (0,
|
|
1118
|
-
/* @__PURE__ */ (0,
|
|
1841
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("table", { className: "w-full text-sm text-right border-collapse table-auto", children: [
|
|
1842
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("thead", { className: "bg-slate-100/80 text-slate-700 sticky top-0 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { children: [
|
|
1843
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "border-b border-l border-slate-200 p-2.5 w-10 text-center shrink-0", style: { width: 50, minWidth: 50, maxWidth: 50 }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1119
1844
|
"input",
|
|
1120
1845
|
{
|
|
1121
1846
|
type: "checkbox",
|
|
@@ -1125,13 +1850,83 @@ function TableBlockClient({
|
|
|
1125
1850
|
className: "w-4 h-4 rounded border-slate-300 text-brand"
|
|
1126
1851
|
}
|
|
1127
1852
|
) }),
|
|
1128
|
-
filteredColumns.map((col) =>
|
|
1853
|
+
filteredColumns.map((col) => {
|
|
1854
|
+
const isDragging = draggedColName === col.name;
|
|
1855
|
+
const isDragOver = dragOverColName === col.name;
|
|
1856
|
+
const currentWidth = columnWidths[col.name] || 200;
|
|
1857
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1858
|
+
"th",
|
|
1859
|
+
{
|
|
1860
|
+
style: { width: currentWidth, minWidth: currentWidth, maxWidth: currentWidth },
|
|
1861
|
+
draggable: !isLoading && !isUpdatingActive,
|
|
1862
|
+
onDragStart: (e) => {
|
|
1863
|
+
e.dataTransfer.setData("text/plain", col.name);
|
|
1864
|
+
e.dataTransfer.effectAllowed = "move";
|
|
1865
|
+
setDraggedColName(col.name);
|
|
1866
|
+
},
|
|
1867
|
+
onDragOver: (e) => {
|
|
1868
|
+
e.preventDefault();
|
|
1869
|
+
e.dataTransfer.dropEffect = "move";
|
|
1870
|
+
if (dragOverColName !== col.name) {
|
|
1871
|
+
setDragOverColName(col.name);
|
|
1872
|
+
}
|
|
1873
|
+
},
|
|
1874
|
+
onDragLeave: () => {
|
|
1875
|
+
if (dragOverColName === col.name) {
|
|
1876
|
+
setDragOverColName(null);
|
|
1877
|
+
}
|
|
1878
|
+
},
|
|
1879
|
+
onDrop: (e) => {
|
|
1880
|
+
e.preventDefault();
|
|
1881
|
+
if (draggedColName && draggedColName !== col.name) {
|
|
1882
|
+
handleColumnReorder(draggedColName, col.name);
|
|
1883
|
+
}
|
|
1884
|
+
setDraggedColName(null);
|
|
1885
|
+
setDragOverColName(null);
|
|
1886
|
+
},
|
|
1887
|
+
onDragEnd: () => {
|
|
1888
|
+
setDraggedColName(null);
|
|
1889
|
+
setDragOverColName(null);
|
|
1890
|
+
},
|
|
1891
|
+
className: `relative border-b border-l border-slate-200 px-4 py-2.5 font-semibold text-slate-700 whitespace-nowrap select-none cursor-grab active:cursor-grabbing transition-colors ${isDragging ? "opacity-40 bg-slate-200 border-dashed border-2 border-brand" : ""} ${isDragOver ? "bg-blue-50 border-r-4 border-r-brand text-brand font-bold" : "hover:bg-slate-200/60"}`,
|
|
1892
|
+
children: [
|
|
1893
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1894
|
+
"div",
|
|
1895
|
+
{
|
|
1896
|
+
onMouseDown: (e) => {
|
|
1897
|
+
e.preventDefault();
|
|
1898
|
+
e.stopPropagation();
|
|
1899
|
+
setResizingCol({ name: col.name, startWidth: currentWidth, startX: e.clientX });
|
|
1900
|
+
},
|
|
1901
|
+
className: "absolute left-0 top-0 bottom-0 w-1.5 cursor-col-resize hover:bg-brand active:bg-brand-hover z-20",
|
|
1902
|
+
title: "\u05E9\u05E0\u05D4 \u05D2\u05D5\u05D3\u05DC \u05E2\u05DE\u05D5\u05D3\u05D4"
|
|
1903
|
+
}
|
|
1904
|
+
),
|
|
1905
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between gap-2 group overflow-hidden", title: "\u05D2\u05E8\u05D5\u05E8 \u05DC\u05E9\u05D9\u05E0\u05D5\u05D9 \u05E1\u05D3\u05E8 \u05D4\u05E2\u05DE\u05D5\u05D3\u05D4", children: [
|
|
1906
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "truncate", children: col.name }),
|
|
1907
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1908
|
+
"svg",
|
|
1909
|
+
{
|
|
1910
|
+
className: "w-3.5 h-3.5 text-slate-400 opacity-40 group-hover:opacity-100 transition-opacity shrink-0 cursor-grab",
|
|
1911
|
+
fill: "none",
|
|
1912
|
+
viewBox: "0 0 24 24",
|
|
1913
|
+
stroke: "currentColor",
|
|
1914
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M8 9h.01M8 15h.01M16 9h.01M16 15h.01" })
|
|
1915
|
+
}
|
|
1916
|
+
)
|
|
1917
|
+
] })
|
|
1918
|
+
]
|
|
1919
|
+
},
|
|
1920
|
+
col.name
|
|
1921
|
+
);
|
|
1922
|
+
}),
|
|
1923
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "w-full min-w-[50px] border-b border-slate-200 pointer-events-none" })
|
|
1129
1924
|
] }) }),
|
|
1130
|
-
/* @__PURE__ */ (0,
|
|
1131
|
-
/* @__PURE__ */ (0,
|
|
1132
|
-
/* @__PURE__ */ (0,
|
|
1133
|
-
] }) }) }) : filteredData.map((row) => /* @__PURE__ */ (0,
|
|
1134
|
-
/* @__PURE__ */ (0,
|
|
1925
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tbody", { className: "bg-white", children: (isStateEmpty || filteredData.length === 0) && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { colSpan: filteredColumns.length + 2, className: "text-center py-12 text-slate-400", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col items-center justify-center gap-2", children: [
|
|
1926
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-8 h-8 text-slate-300", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", d: "M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4" }) }),
|
|
1927
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05DC\u05D4\u05E6\u05D2\u05D4." })
|
|
1928
|
+
] }) }) }) : filteredData.map((row) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { className: "hover:bg-blue-50/30 transition-colors group", children: [
|
|
1929
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-l border-slate-200 p-1.5 text-center bg-white group-hover:bg-transparent", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1135
1930
|
"input",
|
|
1136
1931
|
{
|
|
1137
1932
|
type: "checkbox",
|
|
@@ -1153,7 +1948,7 @@ function TableBlockClient({
|
|
|
1153
1948
|
}
|
|
1154
1949
|
}
|
|
1155
1950
|
if (value === void 0) value = null;
|
|
1156
|
-
return /* @__PURE__ */ (0,
|
|
1951
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-l border-slate-200 p-0 relative", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1157
1952
|
InputComponent,
|
|
1158
1953
|
{
|
|
1159
1954
|
value,
|
|
@@ -1173,8 +1968,82 @@ function TableBlockClient({
|
|
|
1173
1968
|
}
|
|
1174
1969
|
}
|
|
1175
1970
|
) }, col.name);
|
|
1176
|
-
})
|
|
1177
|
-
|
|
1971
|
+
}),
|
|
1972
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-slate-200 bg-white pointer-events-none" })
|
|
1973
|
+
] }, row.id)) }),
|
|
1974
|
+
showSummary && filteredData.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tfoot", { className: "bg-slate-50 border-t-2 border-slate-300 sticky bottom-0 z-10 shadow-[0_-2px_4px_rgba(0,0,0,0.02)]", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { children: [
|
|
1975
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-l border-slate-200 p-1.5 text-center font-bold text-slate-600 text-xs", children: '\u05E1\u05D4"\u05DB' }),
|
|
1976
|
+
filteredColumns.map((col) => {
|
|
1977
|
+
var _a;
|
|
1978
|
+
const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
|
|
1979
|
+
const isNumeric = typeUpper === "CURRENCY" || typeUpper === "NUMBER";
|
|
1980
|
+
const total = columnTotals[col.name];
|
|
1981
|
+
let displayVal = "";
|
|
1982
|
+
if (isNumeric && total !== void 0) {
|
|
1983
|
+
displayVal = new Intl.NumberFormat("en-US").format(total);
|
|
1984
|
+
if (typeUpper === "CURRENCY") {
|
|
1985
|
+
const symbol = getCurrencySymbol(col.currencySymbol);
|
|
1986
|
+
displayVal = symbol ? `${symbol} ${displayVal}` : displayVal;
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-l border-slate-200 p-2 text-sm font-semibold text-slate-700 bg-slate-50 relative", children: isNumeric && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex items-center text-right justify-start", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "truncate", children: displayVal }) }) }, col.name);
|
|
1990
|
+
}),
|
|
1991
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-slate-200 bg-slate-50 pointer-events-none" })
|
|
1992
|
+
] }) })
|
|
1993
|
+
] })
|
|
1994
|
+
] }),
|
|
1995
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col sm:flex-row items-center justify-between gap-3 px-4 py-3 bg-slate-50 border-t border-slate-200 text-xs text-slate-600 rounded-b-xl", children: [
|
|
1996
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1997
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-medium text-slate-700", children: "\u05E9\u05D5\u05E8\u05D5\u05EA \u05DC\u05E2\u05DE\u05D5\u05D3:" }),
|
|
1998
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1999
|
+
"select",
|
|
2000
|
+
{
|
|
2001
|
+
value: limit,
|
|
2002
|
+
onChange: (e) => handleLimitChange(Number(e.target.value)),
|
|
2003
|
+
disabled: isLoading || isUpdatingActive,
|
|
2004
|
+
className: "bg-white border border-slate-300 rounded-lg px-2.5 py-1 text-slate-700 font-semibold shadow-2xs cursor-pointer focus:outline-none focus:ring-2 focus:ring-brand disabled:opacity-50",
|
|
2005
|
+
children: [
|
|
2006
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: 20, children: "20" }),
|
|
2007
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: 50, children: "50" }),
|
|
2008
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: 100, children: "100" })
|
|
2009
|
+
]
|
|
2010
|
+
}
|
|
2011
|
+
)
|
|
2012
|
+
] }),
|
|
2013
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-4", children: [
|
|
2014
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-medium text-slate-600", children: [
|
|
2015
|
+
"\u05E2\u05DE\u05D5\u05D3 ",
|
|
2016
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { className: "text-slate-900", children: page }),
|
|
2017
|
+
" \u05DE\u05EA\u05D5\u05DA ",
|
|
2018
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { className: "text-slate-900", children: totalPages || 1 }),
|
|
2019
|
+
totalRecords > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-slate-500 font-normal", children: [
|
|
2020
|
+
" (",
|
|
2021
|
+
totalRecords,
|
|
2022
|
+
' \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D1\u05E1\u05D4"\u05DB)'
|
|
2023
|
+
] })
|
|
2024
|
+
] }),
|
|
2025
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
2026
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2027
|
+
"button",
|
|
2028
|
+
{
|
|
2029
|
+
onClick: handlePrevPage,
|
|
2030
|
+
disabled: page <= 1 || isLoading || isUpdatingActive,
|
|
2031
|
+
className: "px-3 py-1.5 bg-white border border-slate-300 hover:bg-slate-100 font-semibold text-slate-700 rounded-lg shadow-2xs disabled:opacity-40 disabled:pointer-events-none transition-colors cursor-pointer",
|
|
2032
|
+
title: "\u05E2\u05DE\u05D5\u05D3 \u05E7\u05D5\u05D3\u05DD",
|
|
2033
|
+
children: "\u05D4\u05E7\u05D5\u05D3\u05DD"
|
|
2034
|
+
}
|
|
2035
|
+
),
|
|
2036
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2037
|
+
"button",
|
|
2038
|
+
{
|
|
2039
|
+
onClick: handleNextPage,
|
|
2040
|
+
disabled: page >= totalPages || isLoading || isUpdatingActive,
|
|
2041
|
+
className: "px-3 py-1.5 bg-white border border-slate-300 hover:bg-slate-100 font-semibold text-slate-700 rounded-lg shadow-2xs disabled:opacity-40 disabled:pointer-events-none transition-colors cursor-pointer",
|
|
2042
|
+
title: "\u05E2\u05DE\u05D5\u05D3 \u05D4\u05D1\u05D0",
|
|
2043
|
+
children: "\u05D4\u05D1\u05D0"
|
|
2044
|
+
}
|
|
2045
|
+
)
|
|
2046
|
+
] })
|
|
1178
2047
|
] })
|
|
1179
2048
|
] })
|
|
1180
2049
|
]
|
|
@@ -1183,9 +2052,9 @@ function TableBlockClient({
|
|
|
1183
2052
|
}
|
|
1184
2053
|
|
|
1185
2054
|
// src/components/TableBlock/TableBlock.tsx
|
|
1186
|
-
var
|
|
2055
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1187
2056
|
function TableBlock(props) {
|
|
1188
|
-
return /* @__PURE__ */ (0,
|
|
2057
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TableBlockClient, __spreadValues({}, props));
|
|
1189
2058
|
}
|
|
1190
2059
|
|
|
1191
2060
|
// src/registry.ts
|