@universe-platform/ui 0.1.0-beta.5 → 0.1.0-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/globals.css +334 -2
- package/dist/index.d.mts +15 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +1597 -181
- package/dist/index.mjs +1598 -182
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -39,7 +39,7 @@ function cn(...inputs) {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// src/components/TableBlock/TableBlockClient.tsx
|
|
42
|
-
import { useState as
|
|
42
|
+
import React6, { useState as useState5, useMemo as useMemo2, useEffect as useEffect4, useCallback as useCallback4, useRef as useRef4 } from "react";
|
|
43
43
|
|
|
44
44
|
// src/hooks/useToast.ts
|
|
45
45
|
import { useContext as useContext2 } from "react";
|
|
@@ -242,12 +242,36 @@ function useToast() {
|
|
|
242
242
|
import React4 from "react";
|
|
243
243
|
|
|
244
244
|
// src/components/TableBlock/fields/DrivePickerCell.tsx
|
|
245
|
-
import { useState as useState2 } from "react";
|
|
245
|
+
import React2, { useState as useState2, useEffect } from "react";
|
|
246
246
|
import { FileText, Upload, X as X2 } from "lucide-react";
|
|
247
247
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
248
|
-
function DrivePickerCell({ value, onChange, tableName, onMarkForDeletion, context }) {
|
|
248
|
+
function DrivePickerCell({ value, onChange, tableName, column, rowId, onMarkForDeletion, context }) {
|
|
249
249
|
const [isOpening, setIsOpening] = useState2(false);
|
|
250
250
|
const { showError } = useToast();
|
|
251
|
+
const cellContextId = React2.useMemo(() => {
|
|
252
|
+
const colName = (column == null ? void 0 : column.name) || "col";
|
|
253
|
+
const rId = rowId || "row";
|
|
254
|
+
return `${rId}-${colName}`;
|
|
255
|
+
}, [rowId, column == null ? void 0 : column.name]);
|
|
256
|
+
const fileList = React2.useMemo(() => {
|
|
257
|
+
if (!value) return [];
|
|
258
|
+
if (Array.isArray(value)) return value;
|
|
259
|
+
if (typeof value === "object" && (value.fileId || value.fileUrl || value.url)) {
|
|
260
|
+
return [value];
|
|
261
|
+
}
|
|
262
|
+
return [];
|
|
263
|
+
}, [value]);
|
|
264
|
+
useEffect(() => {
|
|
265
|
+
const handleMessage = (event) => {
|
|
266
|
+
var _a, _b, _c;
|
|
267
|
+
if (((_a = event.data) == null ? void 0 : _a.type) === "DRIVE_UPLOAD_SUCCESS" && ((_b = event.data) == null ? void 0 : _b.payload) && ((_c = event.data) == null ? void 0 : _c.cellContextId) === cellContextId) {
|
|
268
|
+
const incoming = Array.isArray(event.data.payload) ? event.data.payload : [event.data.payload];
|
|
269
|
+
onChange([...fileList, ...incoming]);
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
window.addEventListener("message", handleMessage);
|
|
273
|
+
return () => window.removeEventListener("message", handleMessage);
|
|
274
|
+
}, [fileList, onChange, cellContextId]);
|
|
251
275
|
const openUploadPopup = async () => {
|
|
252
276
|
if (isOpening) return;
|
|
253
277
|
setIsOpening(true);
|
|
@@ -276,34 +300,35 @@ function DrivePickerCell({ value, onChange, tableName, onMarkForDeletion, contex
|
|
|
276
300
|
} catch (e) {
|
|
277
301
|
}
|
|
278
302
|
}
|
|
279
|
-
const actionResult = await context.executeAction("UPLOAD_DRIVE_FILE", { tableName });
|
|
303
|
+
const actionResult = await context.executeAction("UPLOAD_DRIVE_FILE", { tableName, cellContextId });
|
|
280
304
|
const folderId = actionResult == null ? void 0 : actionResult.folderId;
|
|
281
|
-
|
|
305
|
+
let pickerUrl = (actionResult == null ? void 0 : actionResult.pickerUrl) || (folderId ? `/embed/picker?folderId=${encodeURIComponent(folderId)}` : `/embed/picker`);
|
|
306
|
+
if (!pickerUrl.includes("cellContextId=")) {
|
|
307
|
+
const separator = pickerUrl.includes("?") ? "&" : "?";
|
|
308
|
+
pickerUrl = `${pickerUrl}${separator}cellContextId=${encodeURIComponent(cellContextId)}`;
|
|
309
|
+
}
|
|
282
310
|
if (popup) {
|
|
283
311
|
popup.location.href = pickerUrl;
|
|
284
312
|
}
|
|
285
|
-
|
|
313
|
+
await new Promise((resolve) => {
|
|
286
314
|
let timer = null;
|
|
287
|
-
const
|
|
315
|
+
const handlePopupMessage = (event) => {
|
|
288
316
|
var _a, _b;
|
|
289
|
-
if (((_a = event.data) == null ? void 0 : _a.type) === "DRIVE_UPLOAD_SUCCESS" && ((_b = event.data) == null ? void 0 : _b.
|
|
290
|
-
window.removeEventListener("message",
|
|
317
|
+
if (((_a = event.data) == null ? void 0 : _a.type) === "DRIVE_UPLOAD_SUCCESS" && ((_b = event.data) == null ? void 0 : _b.cellContextId) === cellContextId) {
|
|
318
|
+
window.removeEventListener("message", handlePopupMessage);
|
|
291
319
|
if (timer) clearInterval(timer);
|
|
292
|
-
resolve(
|
|
320
|
+
resolve();
|
|
293
321
|
}
|
|
294
322
|
};
|
|
295
323
|
timer = setInterval(() => {
|
|
296
324
|
if (!popup || popup.closed) {
|
|
297
325
|
if (timer) clearInterval(timer);
|
|
298
|
-
window.removeEventListener("message",
|
|
299
|
-
resolve(
|
|
326
|
+
window.removeEventListener("message", handlePopupMessage);
|
|
327
|
+
resolve();
|
|
300
328
|
}
|
|
301
329
|
}, 800);
|
|
302
|
-
window.addEventListener("message",
|
|
330
|
+
window.addEventListener("message", handlePopupMessage);
|
|
303
331
|
});
|
|
304
|
-
if (newFile) {
|
|
305
|
-
onChange(newFile);
|
|
306
|
-
}
|
|
307
332
|
}
|
|
308
333
|
} catch (error) {
|
|
309
334
|
console.error("[DrivePickerCell] Error uploading file:", error);
|
|
@@ -313,40 +338,15 @@ function DrivePickerCell({ value, onChange, tableName, onMarkForDeletion, contex
|
|
|
313
338
|
setIsOpening(false);
|
|
314
339
|
}
|
|
315
340
|
};
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
title: value.fileName || "Open file",
|
|
326
|
-
children: [
|
|
327
|
-
/* @__PURE__ */ jsx2(FileText, { className: "w-3.5 h-3.5 shrink-0" }),
|
|
328
|
-
/* @__PURE__ */ jsx2("span", { className: "truncate", children: value.fileName || "Unnamed file" })
|
|
329
|
-
]
|
|
330
|
-
}
|
|
331
|
-
),
|
|
332
|
-
/* @__PURE__ */ jsx2(
|
|
333
|
-
"button",
|
|
334
|
-
{
|
|
335
|
-
type: "button",
|
|
336
|
-
onClick: () => {
|
|
337
|
-
if ((value == null ? void 0 : value.fileId) && onMarkForDeletion) {
|
|
338
|
-
onMarkForDeletion(value.fileId);
|
|
339
|
-
}
|
|
340
|
-
onChange(null);
|
|
341
|
-
},
|
|
342
|
-
className: "shrink-0 p-0.5 rounded hover:bg-rose-100 text-slate-400 hover:text-rose-500 transition-colors",
|
|
343
|
-
title: "Remove file",
|
|
344
|
-
children: /* @__PURE__ */ jsx2(X2, { className: "w-3.5 h-3.5" })
|
|
345
|
-
}
|
|
346
|
-
)
|
|
347
|
-
] });
|
|
348
|
-
}
|
|
349
|
-
return /* @__PURE__ */ jsx2("div", { className: "flex items-center w-full h-8 px-2", children: /* @__PURE__ */ jsxs2(
|
|
341
|
+
const handleRemoveFile = (indexToRemove) => {
|
|
342
|
+
const fileToRemove = fileList[indexToRemove];
|
|
343
|
+
if ((fileToRemove == null ? void 0 : fileToRemove.fileId) && onMarkForDeletion) {
|
|
344
|
+
onMarkForDeletion(fileToRemove.fileId);
|
|
345
|
+
}
|
|
346
|
+
const updated = fileList.filter((_, idx) => idx !== indexToRemove);
|
|
347
|
+
onChange(updated);
|
|
348
|
+
};
|
|
349
|
+
const renderUploadButton = () => /* @__PURE__ */ jsx2("div", { className: "flex items-center w-full h-8 px-2", children: /* @__PURE__ */ jsxs2(
|
|
350
350
|
"button",
|
|
351
351
|
{
|
|
352
352
|
type: "button",
|
|
@@ -359,10 +359,42 @@ function DrivePickerCell({ value, onChange, tableName, onMarkForDeletion, contex
|
|
|
359
359
|
]
|
|
360
360
|
}
|
|
361
361
|
) });
|
|
362
|
+
if (fileList.length > 0) {
|
|
363
|
+
return /* @__PURE__ */ jsxs2("div", { className: "flex flex-col w-full py-1 gap-1", children: [
|
|
364
|
+
fileList.map((file, idx) => /* @__PURE__ */ jsxs2("div", { className: "flex items-center w-full h-8 px-2 gap-1", children: [
|
|
365
|
+
/* @__PURE__ */ jsxs2(
|
|
366
|
+
"a",
|
|
367
|
+
{
|
|
368
|
+
href: file.fileUrl || file.url,
|
|
369
|
+
target: "_blank",
|
|
370
|
+
rel: "noopener noreferrer",
|
|
371
|
+
className: "inline-flex items-center gap-1.5 max-w-[calc(100%-24px)] px-2 py-1 rounded-md text-xs font-medium text-blue-700 bg-blue-50 hover:bg-blue-100 transition-colors truncate",
|
|
372
|
+
title: file.fileName || "Open file",
|
|
373
|
+
children: [
|
|
374
|
+
/* @__PURE__ */ jsx2(FileText, { className: "w-3.5 h-3.5 shrink-0" }),
|
|
375
|
+
/* @__PURE__ */ jsx2("span", { className: "truncate", children: file.fileName || "Unnamed file" })
|
|
376
|
+
]
|
|
377
|
+
}
|
|
378
|
+
),
|
|
379
|
+
/* @__PURE__ */ jsx2(
|
|
380
|
+
"button",
|
|
381
|
+
{
|
|
382
|
+
type: "button",
|
|
383
|
+
onClick: () => handleRemoveFile(idx),
|
|
384
|
+
className: "shrink-0 p-0.5 rounded hover:bg-rose-100 text-slate-400 hover:text-rose-500 transition-colors",
|
|
385
|
+
title: "Remove file",
|
|
386
|
+
children: /* @__PURE__ */ jsx2(X2, { className: "w-3.5 h-3.5" })
|
|
387
|
+
}
|
|
388
|
+
)
|
|
389
|
+
] }, file.fileId || idx)),
|
|
390
|
+
renderUploadButton()
|
|
391
|
+
] });
|
|
392
|
+
}
|
|
393
|
+
return renderUploadButton();
|
|
362
394
|
}
|
|
363
395
|
|
|
364
396
|
// src/components/TableBlock/fields/DatePickerCell.tsx
|
|
365
|
-
import { useState as useState3, useRef as useRef2, useEffect, useMemo, useCallback as useCallback2 } from "react";
|
|
397
|
+
import { useState as useState3, useRef as useRef2, useEffect as useEffect2, useMemo, useCallback as useCallback2 } from "react";
|
|
366
398
|
import { Calendar as CalendarIcon, ChevronLeft, ChevronRight, X as X3 } from "lucide-react";
|
|
367
399
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
368
400
|
function parseDateParts(val) {
|
|
@@ -447,13 +479,13 @@ function DatePickerCell({ value, onChange, readOnly = false }) {
|
|
|
447
479
|
const parsedParts = useMemo(() => parseDateParts(value), [value]);
|
|
448
480
|
const displayString = useMemo(() => formatDateDisplay(parsedParts), [parsedParts]);
|
|
449
481
|
const [rawInput, setRawInput] = useState3(displayString);
|
|
450
|
-
|
|
482
|
+
useEffect2(() => {
|
|
451
483
|
setRawInput(displayString);
|
|
452
484
|
}, [displayString]);
|
|
453
485
|
const now = /* @__PURE__ */ new Date();
|
|
454
486
|
const [viewYear, setViewYear] = useState3((parsedParts == null ? void 0 : parsedParts.year) || now.getFullYear());
|
|
455
487
|
const [viewMonth, setViewMonth] = useState3((parsedParts == null ? void 0 : parsedParts.month) || now.getMonth() + 1);
|
|
456
|
-
|
|
488
|
+
useEffect2(() => {
|
|
457
489
|
if (parsedParts) {
|
|
458
490
|
setViewYear(parsedParts.year);
|
|
459
491
|
setViewMonth(parsedParts.month);
|
|
@@ -478,7 +510,7 @@ function DatePickerCell({ value, onChange, readOnly = false }) {
|
|
|
478
510
|
}
|
|
479
511
|
}
|
|
480
512
|
}, []);
|
|
481
|
-
|
|
513
|
+
useEffect2(() => {
|
|
482
514
|
if (!isOpen) return;
|
|
483
515
|
updatePopoverPosition();
|
|
484
516
|
function handleScrollOrResize() {
|
|
@@ -704,15 +736,19 @@ var FORM_INPUTS = {
|
|
|
704
736
|
DATE: ({ value, onChange, column }) => /* @__PURE__ */ jsx4(DatePickerCell, { value, onChange, column }),
|
|
705
737
|
CURRENCY: ({ value, column, onChange }) => {
|
|
706
738
|
const symbol = getCurrencySymbol(column.currencySymbol);
|
|
739
|
+
const [isFocused, setIsFocused] = React4.useState(false);
|
|
740
|
+
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 : "";
|
|
707
741
|
return /* @__PURE__ */ jsxs4("div", { className: "relative w-full h-full", children: [
|
|
708
742
|
symbol && /* @__PURE__ */ jsx4("span", { className: "absolute left-2 top-1/2 -translate-y-1/2 text-slate-400 pointer-events-none text-sm", children: symbol }),
|
|
709
743
|
/* @__PURE__ */ jsx4(
|
|
710
744
|
"input",
|
|
711
745
|
{
|
|
712
|
-
type: "number",
|
|
746
|
+
type: isFocused ? "number" : "text",
|
|
713
747
|
step: "any",
|
|
714
748
|
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`,
|
|
715
|
-
value:
|
|
749
|
+
value: displayValue,
|
|
750
|
+
onFocus: () => setIsFocused(true),
|
|
751
|
+
onBlur: () => setIsFocused(false),
|
|
716
752
|
onChange: (e) => {
|
|
717
753
|
const val = e.target.value;
|
|
718
754
|
onChange(val === "" ? "" : Number(val));
|
|
@@ -789,11 +825,13 @@ var FORM_INPUTS = {
|
|
|
789
825
|
className: "w-4 h-4 rounded border-slate-300 text-brand"
|
|
790
826
|
}
|
|
791
827
|
) }),
|
|
792
|
-
GOOGLE_DRIVE_FILE: ({ value, onChange, context }) => /* @__PURE__ */ jsx4(
|
|
828
|
+
GOOGLE_DRIVE_FILE: ({ value, onChange, column, rowId, context }) => /* @__PURE__ */ jsx4(
|
|
793
829
|
DrivePickerCell,
|
|
794
830
|
{
|
|
795
|
-
value: value ||
|
|
831
|
+
value: value || [],
|
|
796
832
|
onChange,
|
|
833
|
+
column,
|
|
834
|
+
rowId,
|
|
797
835
|
tableName: context == null ? void 0 : context.tableName,
|
|
798
836
|
onMarkForDeletion: context == null ? void 0 : context.onMarkForDeletion,
|
|
799
837
|
context
|
|
@@ -851,6 +889,228 @@ var FORM_INPUTS = {
|
|
|
851
889
|
}
|
|
852
890
|
}
|
|
853
891
|
),
|
|
892
|
+
PHONE: ({ value, onChange }) => /* @__PURE__ */ jsx4(
|
|
893
|
+
"input",
|
|
894
|
+
{
|
|
895
|
+
type: "tel",
|
|
896
|
+
className: "w-full h-8 px-2 bg-transparent focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 text-sm",
|
|
897
|
+
value: value !== void 0 && value !== null ? String(value) : "",
|
|
898
|
+
onChange: (e) => onChange(e.target.value),
|
|
899
|
+
dir: "ltr"
|
|
900
|
+
}
|
|
901
|
+
),
|
|
902
|
+
GOOGLE_CONTACT: ({ value, column, rowId, onChange, context }) => {
|
|
903
|
+
const [isSyncing, setIsSyncing] = React4.useState(false);
|
|
904
|
+
const { addToast } = useToast();
|
|
905
|
+
const googleClientIdRef = React4.useRef(null);
|
|
906
|
+
const ensureGisScript = React4.useCallback(() => {
|
|
907
|
+
return new Promise((resolve, reject) => {
|
|
908
|
+
var _a, _b, _c;
|
|
909
|
+
if ((_c = (_b = (_a = window.google) == null ? void 0 : _a.accounts) == null ? void 0 : _b.oauth2) == null ? void 0 : _c.initTokenClient) {
|
|
910
|
+
resolve();
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
if (document.querySelector('script[src*="accounts.google.com/gsi/client"]')) {
|
|
914
|
+
const waitForLoad = setInterval(() => {
|
|
915
|
+
var _a2, _b2, _c2;
|
|
916
|
+
if ((_c2 = (_b2 = (_a2 = window.google) == null ? void 0 : _a2.accounts) == null ? void 0 : _b2.oauth2) == null ? void 0 : _c2.initTokenClient) {
|
|
917
|
+
clearInterval(waitForLoad);
|
|
918
|
+
resolve();
|
|
919
|
+
}
|
|
920
|
+
}, 100);
|
|
921
|
+
setTimeout(() => {
|
|
922
|
+
clearInterval(waitForLoad);
|
|
923
|
+
reject(new Error("GIS script load timeout"));
|
|
924
|
+
}, 1e4);
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
const script = document.createElement("script");
|
|
928
|
+
script.src = "https://accounts.google.com/gsi/client";
|
|
929
|
+
script.async = true;
|
|
930
|
+
script.onload = () => resolve();
|
|
931
|
+
script.onerror = () => reject(new Error("Failed to load Google Identity Services"));
|
|
932
|
+
document.head.appendChild(script);
|
|
933
|
+
});
|
|
934
|
+
}, []);
|
|
935
|
+
const requestGisToken = React4.useCallback(async (hint) => {
|
|
936
|
+
await ensureGisScript();
|
|
937
|
+
if (!googleClientIdRef.current && (context == null ? void 0 : context.executeAction)) {
|
|
938
|
+
try {
|
|
939
|
+
const config = await context.executeAction("GET_GOOGLE_CONFIG", {});
|
|
940
|
+
googleClientIdRef.current = (config == null ? void 0 : config.clientId) || "";
|
|
941
|
+
} catch (e) {
|
|
942
|
+
throw new Error("Failed to fetch Google configuration");
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
const clientId = googleClientIdRef.current;
|
|
946
|
+
if (!clientId) {
|
|
947
|
+
throw new Error("Google Client ID is not configured");
|
|
948
|
+
}
|
|
949
|
+
const accessToken = await new Promise((resolve, reject) => {
|
|
950
|
+
const tokenClient = window.google.accounts.oauth2.initTokenClient({
|
|
951
|
+
client_id: clientId,
|
|
952
|
+
scope: "https://www.googleapis.com/auth/contacts https://www.googleapis.com/auth/userinfo.email",
|
|
953
|
+
prompt: hint ? "" : "select_account",
|
|
954
|
+
hint: hint || void 0,
|
|
955
|
+
callback: (tokenResponse) => {
|
|
956
|
+
if (tokenResponse == null ? void 0 : tokenResponse.access_token) {
|
|
957
|
+
resolve(tokenResponse.access_token);
|
|
958
|
+
} else {
|
|
959
|
+
reject(new Error("Google authorization was cancelled or failed"));
|
|
960
|
+
}
|
|
961
|
+
},
|
|
962
|
+
error_callback: (err) => {
|
|
963
|
+
reject(new Error((err == null ? void 0 : err.message) || "Google authorization error"));
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
tokenClient.requestAccessToken({ hint: hint || void 0 });
|
|
967
|
+
});
|
|
968
|
+
let email = "";
|
|
969
|
+
try {
|
|
970
|
+
const res = await fetch("https://www.googleapis.com/oauth2/v3/userinfo", {
|
|
971
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
972
|
+
});
|
|
973
|
+
if (res.ok) {
|
|
974
|
+
const info = await res.json();
|
|
975
|
+
email = info.email || "";
|
|
976
|
+
}
|
|
977
|
+
} catch (e) {
|
|
978
|
+
}
|
|
979
|
+
return { accessToken, email };
|
|
980
|
+
}, [ensureGisScript, context]);
|
|
981
|
+
const handleSync = async () => {
|
|
982
|
+
var _a, _b, _c;
|
|
983
|
+
if (!(context == null ? void 0 : context.executeAction)) return;
|
|
984
|
+
setIsSyncing(true);
|
|
985
|
+
try {
|
|
986
|
+
const mapping = column.contactMapping || {};
|
|
987
|
+
const rowData = context.rowData || {};
|
|
988
|
+
let hasPhone = false;
|
|
989
|
+
if (mapping.phoneCol && rowData[mapping.phoneCol]) hasPhone = true;
|
|
990
|
+
let hasName = false;
|
|
991
|
+
if (mapping.nameParts && Array.isArray(mapping.nameParts)) {
|
|
992
|
+
for (const part of mapping.nameParts) {
|
|
993
|
+
if (part.type === "LOCAL" && rowData[part.columnId]) hasName = true;
|
|
994
|
+
if (part.type === "PARENT" && ((_a = context.parentRecord) == null ? void 0 : _a.tableId) === part.parentTableId && ((_c = (_b = context.parentRecord) == null ? void 0 : _b.data) == null ? void 0 : _c[part.columnId])) hasName = true;
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
if (!hasPhone) {
|
|
998
|
+
addToast({ type: "warning", message: "\u05E0\u05D0 \u05DC\u05DE\u05DC\u05D0 \u05DE\u05E1\u05E4\u05E8 \u05D8\u05DC\u05E4\u05D5\u05DF \u05DB\u05D3\u05D9 \u05DC\u05E1\u05E0\u05DB\u05E8\u05DF \u05D0\u05D9\u05E9 \u05E7\u05E9\u05E8 \u05DC\u05D2\u05D5\u05D2\u05DC" });
|
|
999
|
+
setIsSyncing(false);
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
if (!hasName) {
|
|
1003
|
+
addToast({ type: "warning", message: "\u05E0\u05D0 \u05DC\u05DE\u05DC\u05D0 \u05E9\u05DD \u05DB\u05D3\u05D9 \u05DC\u05E1\u05E0\u05DB\u05E8\u05DF \u05D0\u05D9\u05E9 \u05E7\u05E9\u05E8 \u05DC\u05D2\u05D5\u05D2\u05DC" });
|
|
1004
|
+
setIsSyncing(false);
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
1007
|
+
let accessToken;
|
|
1008
|
+
let userEmail = "";
|
|
1009
|
+
try {
|
|
1010
|
+
const gisResult = await requestGisToken();
|
|
1011
|
+
accessToken = gisResult.accessToken;
|
|
1012
|
+
userEmail = gisResult.email;
|
|
1013
|
+
} catch (gisError) {
|
|
1014
|
+
addToast({ type: "warning", message: gisError.message || "\u05D4\u05D4\u05E8\u05E9\u05D0\u05D4 \u05DC\u05D2\u05D5\u05D2\u05DC \u05E0\u05DB\u05E9\u05DC\u05D4" });
|
|
1015
|
+
setIsSyncing(false);
|
|
1016
|
+
return;
|
|
1017
|
+
}
|
|
1018
|
+
const payload = {
|
|
1019
|
+
nameParts: mapping.nameParts || [],
|
|
1020
|
+
phoneCol: mapping.phoneCol,
|
|
1021
|
+
emailCol: mapping.emailCol,
|
|
1022
|
+
localRowData: rowData,
|
|
1023
|
+
parentRecord: context.parentRecord,
|
|
1024
|
+
accessToken,
|
|
1025
|
+
userEmail
|
|
1026
|
+
};
|
|
1027
|
+
const res = await context.executeAction("SYNC_GOOGLE_CONTACT", payload);
|
|
1028
|
+
if (res && res.synced) {
|
|
1029
|
+
if (context.updateQuietly) {
|
|
1030
|
+
context.updateQuietly(rowId, column.name, res);
|
|
1031
|
+
} else {
|
|
1032
|
+
onChange(res);
|
|
1033
|
+
}
|
|
1034
|
+
if (context.tableId && !rowId.startsWith("temp_")) {
|
|
1035
|
+
await context.executeAction("UPDATE_RECORD", {
|
|
1036
|
+
tableId: context.tableId,
|
|
1037
|
+
recordId: rowId,
|
|
1038
|
+
data: { [column.name]: res }
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
} catch (error) {
|
|
1043
|
+
console.error("Failed to sync contact:", error);
|
|
1044
|
+
addToast({ type: "warning", message: "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E1\u05E0\u05DB\u05E8\u05D5\u05DF \u05D0\u05D9\u05E9 \u05E7\u05E9\u05E8: " + error.message });
|
|
1045
|
+
} finally {
|
|
1046
|
+
setIsSyncing(false);
|
|
1047
|
+
}
|
|
1048
|
+
};
|
|
1049
|
+
const handleUnlink = async () => {
|
|
1050
|
+
let accessToken;
|
|
1051
|
+
try {
|
|
1052
|
+
let emailHint = value == null ? void 0 : value.userEmail;
|
|
1053
|
+
if (!emailHint && (value == null ? void 0 : value.url)) {
|
|
1054
|
+
try {
|
|
1055
|
+
const parsed = new URL(value.url);
|
|
1056
|
+
emailHint = parsed.searchParams.get("authuser") || void 0;
|
|
1057
|
+
} catch (e) {
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
const auth = await requestGisToken(emailHint);
|
|
1061
|
+
accessToken = auth.accessToken;
|
|
1062
|
+
} catch (err) {
|
|
1063
|
+
console.warn("[handleUnlink] Could not obtain token via GIS, falling back to server default token:", err);
|
|
1064
|
+
}
|
|
1065
|
+
if ((value == null ? void 0 : value.resourceName) && (context == null ? void 0 : context.executeAction)) {
|
|
1066
|
+
await context.executeAction("DELETE_GOOGLE_CONTACT", {
|
|
1067
|
+
resourceName: value.resourceName,
|
|
1068
|
+
accessToken
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
if (context == null ? void 0 : context.updateQuietly) {
|
|
1072
|
+
context.updateQuietly(rowId, column.name, null);
|
|
1073
|
+
} else {
|
|
1074
|
+
onChange(null);
|
|
1075
|
+
}
|
|
1076
|
+
if ((context == null ? void 0 : context.tableId) && (context == null ? void 0 : context.executeAction) && !rowId.startsWith("temp_")) {
|
|
1077
|
+
await context.executeAction("UPDATE_RECORD", {
|
|
1078
|
+
tableId: context.tableId,
|
|
1079
|
+
recordId: rowId,
|
|
1080
|
+
data: { [column.name]: null }
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
1084
|
+
if (value && value.synced && value.url) {
|
|
1085
|
+
return /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 h-8 px-2 group", children: [
|
|
1086
|
+
/* @__PURE__ */ jsx4("a", { href: value.url, target: "_blank", rel: "noopener noreferrer", className: "text-blue-600 hover:underline flex-1 truncate text-sm", children: "\u05D0\u05D9\u05E9 \u05E7\u05E9\u05E8 \u05D2\u05D5\u05D2\u05DC" }),
|
|
1087
|
+
/* @__PURE__ */ jsx4(
|
|
1088
|
+
"button",
|
|
1089
|
+
{
|
|
1090
|
+
onClick: handleUnlink,
|
|
1091
|
+
className: "text-slate-400 hover:text-rose-500 opacity-0 group-hover:opacity-100 transition-opacity p-1",
|
|
1092
|
+
title: "\u05D1\u05D8\u05DC \u05E1\u05E0\u05DB\u05E8\u05D5\u05DF",
|
|
1093
|
+
children: /* @__PURE__ */ jsx4("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M6 18L18 6M6 6l12 12" }) })
|
|
1094
|
+
}
|
|
1095
|
+
)
|
|
1096
|
+
] });
|
|
1097
|
+
}
|
|
1098
|
+
return /* @__PURE__ */ jsx4("div", { className: "flex items-center h-8 px-2", children: /* @__PURE__ */ jsxs4(
|
|
1099
|
+
"button",
|
|
1100
|
+
{
|
|
1101
|
+
onClick: handleSync,
|
|
1102
|
+
disabled: isSyncing,
|
|
1103
|
+
className: "flex items-center gap-1.5 px-3 py-1 bg-blue-50 text-blue-600 hover:bg-blue-100 border border-blue-200 rounded-md text-xs font-medium transition-colors disabled:opacity-50",
|
|
1104
|
+
children: [
|
|
1105
|
+
isSyncing ? /* @__PURE__ */ jsxs4("svg", { className: "w-3.5 h-3.5 animate-spin", viewBox: "0 0 24 24", fill: "none", children: [
|
|
1106
|
+
/* @__PURE__ */ jsx4("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
1107
|
+
/* @__PURE__ */ jsx4("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })
|
|
1108
|
+
] }) : /* @__PURE__ */ jsx4("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 4v16m8-8H4" }) }),
|
|
1109
|
+
"\u05E1\u05E0\u05DB\u05E8\u05DF \u05DC\u05D2\u05D5\u05D2\u05DC"
|
|
1110
|
+
]
|
|
1111
|
+
}
|
|
1112
|
+
) });
|
|
1113
|
+
},
|
|
854
1114
|
DEFAULT: ({ value, onChange }) => /* @__PURE__ */ jsx4(
|
|
855
1115
|
"input",
|
|
856
1116
|
{
|
|
@@ -859,11 +1119,459 @@ var FORM_INPUTS = {
|
|
|
859
1119
|
value: value !== void 0 && value !== null ? String(value) : "",
|
|
860
1120
|
onChange: (e) => onChange(e.target.value)
|
|
861
1121
|
}
|
|
862
|
-
)
|
|
1122
|
+
),
|
|
1123
|
+
SUB_TABLE: ({ value, column }) => {
|
|
1124
|
+
if (!Array.isArray(value)) return /* @__PURE__ */ jsx4("span", { className: "px-2 py-1 flex items-center h-full text-slate-300 text-xs italic", children: "\u05E8\u05D9\u05E7" });
|
|
1125
|
+
const selected = value.filter((e) => e == null ? void 0 : e.isSelected);
|
|
1126
|
+
if (selected.length === 0) return /* @__PURE__ */ jsx4("span", { className: "px-2 py-1 flex items-center h-full text-slate-300 text-xs italic", children: "\u05E8\u05D9\u05E7" });
|
|
1127
|
+
const displayFields = column.subTableDisplayFields || [];
|
|
1128
|
+
return /* @__PURE__ */ jsx4("div", { className: "px-1.5 py-1 flex flex-wrap items-center gap-1 h-full", children: selected.map((entry, idx) => {
|
|
1129
|
+
var _a;
|
|
1130
|
+
let label = "";
|
|
1131
|
+
if (entry._resolvedData && displayFields.length > 0) {
|
|
1132
|
+
label = displayFields.map((f) => String(entry._resolvedData[f] || "")).filter(Boolean).join(" ");
|
|
1133
|
+
}
|
|
1134
|
+
if (!label) label = ((_a = entry.recordId) == null ? void 0 : _a.slice(-6)) || "...";
|
|
1135
|
+
return /* @__PURE__ */ jsx4(
|
|
1136
|
+
"span",
|
|
1137
|
+
{
|
|
1138
|
+
className: "inline-flex items-center px-1.5 py-0.5 bg-amber-50 text-amber-800 border border-amber-200 rounded-full text-xs font-medium max-w-[140px] truncate",
|
|
1139
|
+
title: label,
|
|
1140
|
+
children: label
|
|
1141
|
+
},
|
|
1142
|
+
entry.recordId || idx
|
|
1143
|
+
);
|
|
1144
|
+
}) });
|
|
1145
|
+
}
|
|
863
1146
|
};
|
|
864
1147
|
|
|
865
|
-
// src/components/TableBlock/
|
|
1148
|
+
// src/components/TableBlock/fields/SubTableViewer.tsx
|
|
1149
|
+
import { useState as useState4, useEffect as useEffect3, useRef as useRef3, useCallback as useCallback3 } from "react";
|
|
866
1150
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1151
|
+
function SubTableViewer({ rowId, column, value, onChange, context }) {
|
|
1152
|
+
var _a;
|
|
1153
|
+
const { addToast } = useToast();
|
|
1154
|
+
const entries = Array.isArray(value) ? value : [];
|
|
1155
|
+
const [linkedRecords, setLinkedRecords] = useState4([]);
|
|
1156
|
+
const [targetSchema, setTargetSchema] = useState4(null);
|
|
1157
|
+
const [isLoading, setIsLoading] = useState4(true);
|
|
1158
|
+
const [isSearchOpen, setIsSearchOpen] = useState4(false);
|
|
1159
|
+
const [searchQuery, setSearchQuery] = useState4("");
|
|
1160
|
+
const [searchResults, setSearchResults] = useState4([]);
|
|
1161
|
+
const [isSearching, setIsSearching] = useState4(false);
|
|
1162
|
+
const [isCreating, setIsCreating] = useState4(false);
|
|
1163
|
+
const [newRecordData, setNewRecordData] = useState4({});
|
|
1164
|
+
const searchRef = useRef3(null);
|
|
1165
|
+
const searchTimerRef = useRef3(null);
|
|
1166
|
+
const executeAction = context == null ? void 0 : context.executeAction;
|
|
1167
|
+
const referencedTableId = column.referencedTableId;
|
|
1168
|
+
const fetchedIdsRef = useRef3(/* @__PURE__ */ new Set());
|
|
1169
|
+
useEffect3(() => {
|
|
1170
|
+
if (!referencedTableId || !executeAction) {
|
|
1171
|
+
setIsLoading(false);
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
const recordIdsToFetch = entries.map((e) => e.recordId).filter((id) => !fetchedIdsRef.current.has(id));
|
|
1175
|
+
if (recordIdsToFetch.length === 0 && targetSchema) return;
|
|
1176
|
+
if (recordIdsToFetch.length > 0) {
|
|
1177
|
+
recordIdsToFetch.forEach((id) => fetchedIdsRef.current.add(id));
|
|
1178
|
+
}
|
|
1179
|
+
setIsLoading(true);
|
|
1180
|
+
executeAction("FETCH_SUB_TABLE_RECORDS", { referencedTableId, recordIds: recordIdsToFetch }).then((res) => {
|
|
1181
|
+
const payload = (res == null ? void 0 : res.data) || res;
|
|
1182
|
+
if (payload == null ? void 0 : payload.records) {
|
|
1183
|
+
setLinkedRecords((prev) => {
|
|
1184
|
+
const map = new Map(prev.map((r) => [r.id, r]));
|
|
1185
|
+
payload.records.forEach((r) => map.set(r.id, r));
|
|
1186
|
+
return Array.from(map.values());
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
if (payload == null ? void 0 : payload.schema) {
|
|
1190
|
+
setTargetSchema(payload.schema);
|
|
1191
|
+
}
|
|
1192
|
+
}).catch(() => {
|
|
1193
|
+
recordIdsToFetch.forEach((id) => fetchedIdsRef.current.delete(id));
|
|
1194
|
+
}).finally(() => setIsLoading(false));
|
|
1195
|
+
}, [referencedTableId, executeAction, entries, targetSchema]);
|
|
1196
|
+
useEffect3(() => {
|
|
1197
|
+
const handleClick = (e) => {
|
|
1198
|
+
if (searchRef.current && !searchRef.current.contains(e.target)) {
|
|
1199
|
+
setIsSearchOpen(false);
|
|
1200
|
+
}
|
|
1201
|
+
};
|
|
1202
|
+
if (isSearchOpen) document.addEventListener("mousedown", handleClick);
|
|
1203
|
+
return () => document.removeEventListener("mousedown", handleClick);
|
|
1204
|
+
}, [isSearchOpen]);
|
|
1205
|
+
const handleSearch = useCallback3((query) => {
|
|
1206
|
+
setSearchQuery(query);
|
|
1207
|
+
if (searchTimerRef.current) clearTimeout(searchTimerRef.current);
|
|
1208
|
+
if (!query.trim()) {
|
|
1209
|
+
setSearchResults([]);
|
|
1210
|
+
return;
|
|
1211
|
+
}
|
|
1212
|
+
searchTimerRef.current = setTimeout(async () => {
|
|
1213
|
+
if (!executeAction || !referencedTableId) return;
|
|
1214
|
+
setIsSearching(true);
|
|
1215
|
+
try {
|
|
1216
|
+
const excludeIds = entries.map((e) => e.recordId);
|
|
1217
|
+
const res = await executeAction("SEARCH_SUB_TABLE_RECORDS", {
|
|
1218
|
+
referencedTableId,
|
|
1219
|
+
query: query.trim(),
|
|
1220
|
+
excludeIds,
|
|
1221
|
+
limit: 15
|
|
1222
|
+
});
|
|
1223
|
+
setSearchResults(Array.isArray(res) ? res : []);
|
|
1224
|
+
} catch (e) {
|
|
1225
|
+
setSearchResults([]);
|
|
1226
|
+
} finally {
|
|
1227
|
+
setIsSearching(false);
|
|
1228
|
+
}
|
|
1229
|
+
}, 300);
|
|
1230
|
+
}, [executeAction, referencedTableId, entries]);
|
|
1231
|
+
const targetColumns = ((targetSchema == null ? void 0 : targetSchema.columns) || []).filter(
|
|
1232
|
+
(c) => {
|
|
1233
|
+
if (c.name === "_id" || c.type === "SUB_TABLE") return false;
|
|
1234
|
+
return true;
|
|
1235
|
+
}
|
|
1236
|
+
);
|
|
1237
|
+
const [relationOptions, setRelationOptions] = useState4({});
|
|
1238
|
+
useEffect3(() => {
|
|
1239
|
+
if (!executeAction || targetColumns.length === 0) return;
|
|
1240
|
+
const relationCols = targetColumns.filter((c) => {
|
|
1241
|
+
var _a2;
|
|
1242
|
+
return ((_a2 = c.type) == null ? void 0 : _a2.toUpperCase()) === "RELATION" && c.referencedTableId;
|
|
1243
|
+
});
|
|
1244
|
+
relationCols.forEach(async (col) => {
|
|
1245
|
+
try {
|
|
1246
|
+
const options = await executeAction("FETCH_RELATION", {
|
|
1247
|
+
referencedTableId: col.referencedTableId,
|
|
1248
|
+
displayField: col.displayField
|
|
1249
|
+
});
|
|
1250
|
+
if (options && Array.isArray(options)) {
|
|
1251
|
+
setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [col.name]: options }));
|
|
1252
|
+
}
|
|
1253
|
+
} catch (err) {
|
|
1254
|
+
console.warn(`[SubTableViewer] Could not fetch relation options for column ${col.name}:`, err);
|
|
1255
|
+
}
|
|
1256
|
+
});
|
|
1257
|
+
}, [executeAction, targetColumns]);
|
|
1258
|
+
const refetchRelation = useCallback3(async (colName) => {
|
|
1259
|
+
var _a2;
|
|
1260
|
+
const col = targetColumns.find((c) => c.name === colName);
|
|
1261
|
+
if (!col || ((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) !== "RELATION" || !col.referencedTableId || !executeAction) return;
|
|
1262
|
+
try {
|
|
1263
|
+
const options = await executeAction("FETCH_RELATION", { referencedTableId: col.referencedTableId, displayField: col.displayField });
|
|
1264
|
+
if (options && Array.isArray(options)) {
|
|
1265
|
+
setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [col.name]: options }));
|
|
1266
|
+
}
|
|
1267
|
+
} catch (err) {
|
|
1268
|
+
console.warn(`[SubTableViewer] Could not refetch relation options for column ${col.name}:`, err);
|
|
1269
|
+
}
|
|
1270
|
+
}, [targetColumns, executeAction]);
|
|
1271
|
+
const updateParentLinkage = async (updated) => {
|
|
1272
|
+
const isNewRow = rowId.startsWith("temp_");
|
|
1273
|
+
if (context == null ? void 0 : context.updateQuietly) {
|
|
1274
|
+
context.updateQuietly(rowId, column.name, updated);
|
|
1275
|
+
} else {
|
|
1276
|
+
onChange(updated);
|
|
1277
|
+
}
|
|
1278
|
+
if (executeAction && (context == null ? void 0 : context.parentTableId) && !isNewRow) {
|
|
1279
|
+
try {
|
|
1280
|
+
const payloadToSave = updated.map(({ recordId, isSelected }) => ({ recordId, isSelected }));
|
|
1281
|
+
await executeAction("UPDATE_RECORD", {
|
|
1282
|
+
tableId: context.parentTableId,
|
|
1283
|
+
recordId: rowId,
|
|
1284
|
+
data: { [column.name]: payloadToSave }
|
|
1285
|
+
});
|
|
1286
|
+
if (context == null ? void 0 : context.triggerSaveSuccess) {
|
|
1287
|
+
context.triggerSaveSuccess();
|
|
1288
|
+
}
|
|
1289
|
+
} catch (err) {
|
|
1290
|
+
console.error("Failed to auto-save parent linkage", err);
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
};
|
|
1294
|
+
const handleLinkRecord = (record) => {
|
|
1295
|
+
fetchedIdsRef.current.add(record.id);
|
|
1296
|
+
const newEntry = { recordId: record.id, isSelected: true, _resolvedData: record.data };
|
|
1297
|
+
const updated = [...entries, newEntry];
|
|
1298
|
+
updateParentLinkage(updated);
|
|
1299
|
+
setLinkedRecords((prev) => {
|
|
1300
|
+
const exists = prev.find((r) => r.id === record.id);
|
|
1301
|
+
if (exists) return prev;
|
|
1302
|
+
return [...prev, record];
|
|
1303
|
+
});
|
|
1304
|
+
setSearchQuery("");
|
|
1305
|
+
setSearchResults([]);
|
|
1306
|
+
setIsSearchOpen(false);
|
|
1307
|
+
};
|
|
1308
|
+
const handleUnlinkRecord = (recordId) => {
|
|
1309
|
+
const updated = entries.filter((e) => e.recordId !== recordId);
|
|
1310
|
+
updateParentLinkage(updated);
|
|
1311
|
+
setLinkedRecords((prev) => prev.filter((r) => r.id !== recordId));
|
|
1312
|
+
};
|
|
1313
|
+
const handleToggleSelected = (recordId) => {
|
|
1314
|
+
const record = linkedRecords.find((r) => r.id === recordId);
|
|
1315
|
+
const updated = entries.map(
|
|
1316
|
+
(e) => e.recordId === recordId ? __spreadProps(__spreadValues({}, e), { isSelected: !e.isSelected, _resolvedData: (record == null ? void 0 : record.data) || e._resolvedData }) : e
|
|
1317
|
+
);
|
|
1318
|
+
updateParentLinkage(updated);
|
|
1319
|
+
};
|
|
1320
|
+
const handleRecordCellChange = async (recordId, colName, value2) => {
|
|
1321
|
+
const updatedRecords = linkedRecords.map(
|
|
1322
|
+
(r) => r.id === recordId ? __spreadProps(__spreadValues({}, r), { data: __spreadProps(__spreadValues({}, r.data), { [colName]: value2 }) }) : r
|
|
1323
|
+
);
|
|
1324
|
+
setLinkedRecords(updatedRecords);
|
|
1325
|
+
const targetRecord = updatedRecords.find((r) => r.id === recordId);
|
|
1326
|
+
const updatedEntries = entries.map(
|
|
1327
|
+
(e) => e.recordId === recordId ? __spreadProps(__spreadValues({}, e), { _resolvedData: targetRecord == null ? void 0 : targetRecord.data }) : e
|
|
1328
|
+
);
|
|
1329
|
+
if (context == null ? void 0 : context.updateQuietly) {
|
|
1330
|
+
context.updateQuietly(rowId, column.name, updatedEntries);
|
|
1331
|
+
} else {
|
|
1332
|
+
onChange(updatedEntries);
|
|
1333
|
+
}
|
|
1334
|
+
if (executeAction && referencedTableId && !recordId.startsWith("temp_")) {
|
|
1335
|
+
try {
|
|
1336
|
+
await executeAction("UPDATE_RECORD", {
|
|
1337
|
+
tableId: referencedTableId,
|
|
1338
|
+
recordId,
|
|
1339
|
+
data: { [colName]: value2 }
|
|
1340
|
+
});
|
|
1341
|
+
if (context == null ? void 0 : context.triggerSaveSuccess) {
|
|
1342
|
+
context.triggerSaveSuccess();
|
|
1343
|
+
}
|
|
1344
|
+
} catch (err) {
|
|
1345
|
+
console.error("[SubTableViewer] Failed to auto-save linked record field", err);
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
};
|
|
1349
|
+
const handleCreateRecord = async () => {
|
|
1350
|
+
var _a2;
|
|
1351
|
+
if (!executeAction || !referencedTableId) return;
|
|
1352
|
+
for (const col of targetColumns) {
|
|
1353
|
+
if (col.isRequired) {
|
|
1354
|
+
const val = newRecordData[col.name];
|
|
1355
|
+
if (val === void 0 || val === null || typeof val === "string" && val.trim() === "") {
|
|
1356
|
+
addToast({
|
|
1357
|
+
type: "error",
|
|
1358
|
+
message: `Validation Error: Field '${col.name}' is required but was not provided.`
|
|
1359
|
+
});
|
|
1360
|
+
return;
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
try {
|
|
1365
|
+
const res = await executeAction("CREATE_RECORD", {
|
|
1366
|
+
tableId: referencedTableId,
|
|
1367
|
+
records: [newRecordData]
|
|
1368
|
+
});
|
|
1369
|
+
if (res && res.success === false) {
|
|
1370
|
+
throw new Error(res.error || "Action execution failed");
|
|
1371
|
+
}
|
|
1372
|
+
const created = Array.isArray(res) ? res[0] : ((_a2 = res == null ? void 0 : res.data) == null ? void 0 : _a2[0]) || res;
|
|
1373
|
+
if (created) {
|
|
1374
|
+
const newRecord = {
|
|
1375
|
+
id: String(created.id || created._id),
|
|
1376
|
+
data: created.data || newRecordData
|
|
1377
|
+
};
|
|
1378
|
+
handleLinkRecord(newRecord);
|
|
1379
|
+
setIsCreating(false);
|
|
1380
|
+
setNewRecordData({});
|
|
1381
|
+
}
|
|
1382
|
+
} catch (err) {
|
|
1383
|
+
const msg = (err == null ? void 0 : err.message) || String(err);
|
|
1384
|
+
addToast({
|
|
1385
|
+
type: "error",
|
|
1386
|
+
message: msg
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
};
|
|
1390
|
+
const getDisplayLabel = (record) => {
|
|
1391
|
+
const fields = column.subTableDisplayFields || [];
|
|
1392
|
+
if (fields.length === 0) {
|
|
1393
|
+
const firstField = Object.keys(record.data).find((k) => k !== "_id");
|
|
1394
|
+
return firstField ? String(record.data[firstField] || "") : record.id;
|
|
1395
|
+
}
|
|
1396
|
+
return fields.map((f) => String(record.data[f] || "")).filter(Boolean).join(" ");
|
|
1397
|
+
};
|
|
1398
|
+
return /* @__PURE__ */ jsxs5("div", { className: "p-3 animate-in fade-in slide-in-from-top-2 duration-200", dir: "rtl", children: [
|
|
1399
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-4 mb-2.5", children: [
|
|
1400
|
+
/* @__PURE__ */ jsx5("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx5("span", { className: "text-xs font-bold text-slate-600", children: (_a = targetSchema == null ? void 0 : targetSchema.name) != null ? _a : column.referencedTableName }) }),
|
|
1401
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1.5", children: [
|
|
1402
|
+
/* @__PURE__ */ jsxs5("div", { className: "relative", ref: searchRef, children: [
|
|
1403
|
+
/* @__PURE__ */ jsxs5(
|
|
1404
|
+
"button",
|
|
1405
|
+
{
|
|
1406
|
+
type: "button",
|
|
1407
|
+
onClick: () => setIsSearchOpen((prev) => !prev),
|
|
1408
|
+
className: "h-7 px-2.5 text-[11px] font-semibold bg-blue-50 hover:bg-blue-100 text-blue-700 border border-blue-200 rounded-md transition-colors cursor-pointer flex items-center gap-1",
|
|
1409
|
+
children: [
|
|
1410
|
+
/* @__PURE__ */ jsx5("svg", { className: "w-3 h-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }),
|
|
1411
|
+
"\u05E7\u05D9\u05E9\u05D5\u05E8 \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA"
|
|
1412
|
+
]
|
|
1413
|
+
}
|
|
1414
|
+
),
|
|
1415
|
+
isSearchOpen && /* @__PURE__ */ jsxs5("div", { className: "absolute right-0 top-full mt-1 w-72 bg-white border border-slate-200 rounded-lg shadow-xl z-50 p-2", children: [
|
|
1416
|
+
/* @__PURE__ */ jsx5(
|
|
1417
|
+
"input",
|
|
1418
|
+
{
|
|
1419
|
+
type: "text",
|
|
1420
|
+
value: searchQuery,
|
|
1421
|
+
onChange: (e) => handleSearch(e.target.value),
|
|
1422
|
+
placeholder: "\u05D7\u05E4\u05E9 \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA...",
|
|
1423
|
+
className: "w-full h-8 px-2.5 text-xs border border-slate-300 rounded-md focus:outline-none focus:ring-1 focus:ring-blue-400 mb-1.5",
|
|
1424
|
+
autoFocus: true
|
|
1425
|
+
}
|
|
1426
|
+
),
|
|
1427
|
+
/* @__PURE__ */ jsx5("div", { className: "max-h-48 overflow-y-auto", children: isSearching ? /* @__PURE__ */ jsx5("div", { className: "flex items-center justify-center py-4", children: /* @__PURE__ */ jsx5("div", { className: "w-4 h-4 border-2 border-blue-400 border-t-transparent rounded-full animate-spin" }) }) : searchResults.length > 0 ? searchResults.map((r) => /* @__PURE__ */ jsx5(
|
|
1428
|
+
"button",
|
|
1429
|
+
{
|
|
1430
|
+
type: "button",
|
|
1431
|
+
onClick: () => handleLinkRecord(r),
|
|
1432
|
+
className: "w-full text-right px-2 py-1.5 text-xs hover:bg-blue-50 rounded cursor-pointer transition-colors",
|
|
1433
|
+
children: getDisplayLabel(r)
|
|
1434
|
+
},
|
|
1435
|
+
r.id
|
|
1436
|
+
)) : searchQuery.trim() ? /* @__PURE__ */ jsx5("p", { className: "text-xs text-slate-400 text-center py-3", children: "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D5 \u05EA\u05D5\u05E6\u05D0\u05D5\u05EA" }) : /* @__PURE__ */ jsx5("p", { className: "text-xs text-slate-400 text-center py-3", children: "\u05D4\u05E7\u05DC\u05D3 \u05DC\u05D7\u05D9\u05E4\u05D5\u05E9..." }) })
|
|
1437
|
+
] })
|
|
1438
|
+
] }),
|
|
1439
|
+
/* @__PURE__ */ jsxs5(
|
|
1440
|
+
"button",
|
|
1441
|
+
{
|
|
1442
|
+
type: "button",
|
|
1443
|
+
onClick: () => {
|
|
1444
|
+
setIsCreating(true);
|
|
1445
|
+
const initialData = {};
|
|
1446
|
+
targetColumns.forEach((c) => {
|
|
1447
|
+
if (c.defaultValue !== void 0 && c.defaultValue !== null) {
|
|
1448
|
+
initialData[c.name] = c.type === "NUMBER" || c.type === "CURRENCY" ? parseFloat(c.defaultValue) : c.type === "BOOLEAN" ? c.defaultValue === "true" || c.defaultValue === true : c.defaultValue;
|
|
1449
|
+
} else {
|
|
1450
|
+
if (c.type === "NUMBER" || c.type === "CURRENCY") initialData[c.name] = 0;
|
|
1451
|
+
else if (c.type === "BOOLEAN") initialData[c.name] = false;
|
|
1452
|
+
else initialData[c.name] = "";
|
|
1453
|
+
}
|
|
1454
|
+
});
|
|
1455
|
+
setNewRecordData(initialData);
|
|
1456
|
+
},
|
|
1457
|
+
className: "h-7 px-2.5 text-[11px] font-semibold bg-emerald-50 hover:bg-emerald-100 text-emerald-700 border border-emerald-200 rounded-md transition-colors cursor-pointer flex items-center gap-1",
|
|
1458
|
+
children: [
|
|
1459
|
+
/* @__PURE__ */ jsx5("svg", { className: "w-3 h-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M12 4v16m8-8H4" }) }),
|
|
1460
|
+
"\u05E8\u05E9\u05D5\u05DE\u05D4 \u05D7\u05D3\u05E9\u05D4"
|
|
1461
|
+
]
|
|
1462
|
+
}
|
|
1463
|
+
)
|
|
1464
|
+
] })
|
|
1465
|
+
] }),
|
|
1466
|
+
isLoading ? /* @__PURE__ */ jsx5("div", { className: "flex items-center justify-center py-6", children: /* @__PURE__ */ jsx5("div", { className: "w-5 h-5 border-2 border-blue-400 border-t-transparent rounded-full animate-spin" }) }) : entries.length === 0 && !isCreating ? /* @__PURE__ */ jsx5("div", { className: "text-center py-6 text-xs text-slate-400", children: "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05DE\u05E7\u05D5\u05E9\u05E8\u05D5\u05EA. \u05D4\u05E9\u05EA\u05DE\u05E9 \u05D1\u05D7\u05D9\u05E4\u05D5\u05E9 \u05DB\u05D3\u05D9 \u05DC\u05E7\u05E9\u05E8 \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05E7\u05D9\u05D9\u05DE\u05D5\u05EA, \u05D0\u05D5 \u05D4\u05D5\u05E1\u05E3 \u05E8\u05E9\u05D5\u05DE\u05D4 \u05D7\u05D3\u05E9\u05D4." }) : /* @__PURE__ */ jsx5("div", { className: "overflow-x-auto pb-1", children: /* @__PURE__ */ jsxs5("table", { className: "w-full text-xs border-collapse", children: [
|
|
1467
|
+
/* @__PURE__ */ jsx5("thead", { children: /* @__PURE__ */ jsxs5("tr", { className: "bg-slate-100/80", children: [
|
|
1468
|
+
/* @__PURE__ */ jsx5("th", { className: "border border-slate-200 px-2 py-1.5 text-center w-10 font-semibold text-slate-500", children: "\u05E0\u05D1\u05D7\u05E8" }),
|
|
1469
|
+
targetColumns.map((col) => /* @__PURE__ */ jsx5("th", { className: "border border-slate-200 px-2 py-1.5 text-right font-semibold text-slate-600 whitespace-nowrap", children: col.name }, col.name)),
|
|
1470
|
+
/* @__PURE__ */ jsx5("th", { className: "border border-slate-200 px-2 py-1.5 w-14" })
|
|
1471
|
+
] }) }),
|
|
1472
|
+
/* @__PURE__ */ jsxs5("tbody", { children: [
|
|
1473
|
+
entries.map((entry) => {
|
|
1474
|
+
const record = linkedRecords.find((r) => r.id === entry.recordId);
|
|
1475
|
+
return /* @__PURE__ */ jsxs5("tr", { className: "hover:bg-blue-50/30 transition-colors", children: [
|
|
1476
|
+
/* @__PURE__ */ jsx5("td", { className: "border border-slate-200 px-2 py-1 text-center", children: /* @__PURE__ */ jsx5(
|
|
1477
|
+
"input",
|
|
1478
|
+
{
|
|
1479
|
+
type: "checkbox",
|
|
1480
|
+
checked: entry.isSelected,
|
|
1481
|
+
onChange: () => handleToggleSelected(entry.recordId),
|
|
1482
|
+
className: "w-3.5 h-3.5 rounded border-slate-300 text-blue-600 cursor-pointer"
|
|
1483
|
+
}
|
|
1484
|
+
) }),
|
|
1485
|
+
targetColumns.map((col) => {
|
|
1486
|
+
var _a2, _b;
|
|
1487
|
+
const colType = ((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) || "DEFAULT";
|
|
1488
|
+
const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
|
|
1489
|
+
return /* @__PURE__ */ jsx5("td", { className: "border border-slate-200 p-0 relative h-8", children: record ? /* @__PURE__ */ jsx5(
|
|
1490
|
+
InputComponent,
|
|
1491
|
+
{
|
|
1492
|
+
value: (_b = record.data[col.name]) != null ? _b : colType === "BOOLEAN" ? false : "",
|
|
1493
|
+
column: col,
|
|
1494
|
+
rowId: record.id,
|
|
1495
|
+
onChange: (v) => handleRecordCellChange(record.id, col.name, v),
|
|
1496
|
+
context: __spreadProps(__spreadValues({}, context), {
|
|
1497
|
+
tableName: (targetSchema == null ? void 0 : targetSchema.name) || (targetSchema == null ? void 0 : targetSchema.tableName) || (targetSchema == null ? void 0 : targetSchema.title) || (targetSchema == null ? void 0 : targetSchema.id) || "Table",
|
|
1498
|
+
relationOptions,
|
|
1499
|
+
updateRelationOptions: (name, opts) => setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [name]: opts })),
|
|
1500
|
+
refetchRelation,
|
|
1501
|
+
parentRecord: { tableId: (context == null ? void 0 : context.parentTableId) || (context == null ? void 0 : context.tableId), data: context == null ? void 0 : context.rowData },
|
|
1502
|
+
rowData: record.data,
|
|
1503
|
+
tableId: targetSchema == null ? void 0 : targetSchema.id,
|
|
1504
|
+
updateQuietly: (rid, colName, val) => handleRecordCellChange(rid, colName, val)
|
|
1505
|
+
})
|
|
1506
|
+
}
|
|
1507
|
+
) : /* @__PURE__ */ jsx5("span", { className: "text-slate-300 italic px-2", children: "\u05D8\u05D5\u05E2\u05DF..." }) }, col.name);
|
|
1508
|
+
}),
|
|
1509
|
+
/* @__PURE__ */ jsx5("td", { className: "border border-slate-200 px-1 py-1 text-center", children: /* @__PURE__ */ jsx5(
|
|
1510
|
+
"button",
|
|
1511
|
+
{
|
|
1512
|
+
type: "button",
|
|
1513
|
+
onClick: () => handleUnlinkRecord(entry.recordId),
|
|
1514
|
+
className: "text-slate-400 hover:text-rose-500 p-0.5 rounded transition-colors cursor-pointer inline-flex items-center justify-center w-full",
|
|
1515
|
+
title: "\u05D4\u05E1\u05E8 \u05E7\u05D9\u05E9\u05D5\u05E8",
|
|
1516
|
+
children: /* @__PURE__ */ jsx5("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M6 18L18 6M6 6l12 12" }) })
|
|
1517
|
+
}
|
|
1518
|
+
) })
|
|
1519
|
+
] }, entry.recordId);
|
|
1520
|
+
}),
|
|
1521
|
+
isCreating && /* @__PURE__ */ jsxs5("tr", { className: "bg-emerald-50/40", children: [
|
|
1522
|
+
/* @__PURE__ */ jsx5("td", { className: "border border-emerald-200 px-2 py-1 text-center", children: /* @__PURE__ */ jsx5("span", { className: "text-emerald-500 font-bold text-[10px]", children: "\u05D7\u05D3\u05E9" }) }),
|
|
1523
|
+
targetColumns.map((col) => {
|
|
1524
|
+
var _a2, _b;
|
|
1525
|
+
const colType = ((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) || "DEFAULT";
|
|
1526
|
+
const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
|
|
1527
|
+
return /* @__PURE__ */ jsx5("td", { className: "border border-emerald-200 p-0 relative h-8", children: /* @__PURE__ */ jsx5(
|
|
1528
|
+
InputComponent,
|
|
1529
|
+
{
|
|
1530
|
+
value: (_b = newRecordData[col.name]) != null ? _b : colType === "BOOLEAN" ? false : "",
|
|
1531
|
+
column: col,
|
|
1532
|
+
rowId: "new_record",
|
|
1533
|
+
onChange: (v) => setNewRecordData((prev) => __spreadProps(__spreadValues({}, prev), { [col.name]: v })),
|
|
1534
|
+
context: __spreadProps(__spreadValues({}, context), {
|
|
1535
|
+
tableName: (targetSchema == null ? void 0 : targetSchema.name) || (targetSchema == null ? void 0 : targetSchema.tableName) || (targetSchema == null ? void 0 : targetSchema.title) || (targetSchema == null ? void 0 : targetSchema.id) || "Table",
|
|
1536
|
+
relationOptions,
|
|
1537
|
+
refetchRelation
|
|
1538
|
+
})
|
|
1539
|
+
}
|
|
1540
|
+
) }, `new_${col.name}`);
|
|
1541
|
+
}),
|
|
1542
|
+
/* @__PURE__ */ jsx5("td", { className: "border border-emerald-200 px-1 py-1 text-center", children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-center gap-1", children: [
|
|
1543
|
+
/* @__PURE__ */ jsx5(
|
|
1544
|
+
"button",
|
|
1545
|
+
{
|
|
1546
|
+
type: "button",
|
|
1547
|
+
onClick: handleCreateRecord,
|
|
1548
|
+
className: "p-1 text-emerald-600 hover:bg-emerald-100 rounded transition-colors",
|
|
1549
|
+
title: "\u05E9\u05DE\u05D5\u05E8",
|
|
1550
|
+
children: /* @__PURE__ */ jsx5("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M5 13l4 4L19 7" }) })
|
|
1551
|
+
}
|
|
1552
|
+
),
|
|
1553
|
+
/* @__PURE__ */ jsx5(
|
|
1554
|
+
"button",
|
|
1555
|
+
{
|
|
1556
|
+
type: "button",
|
|
1557
|
+
onClick: () => {
|
|
1558
|
+
setIsCreating(false);
|
|
1559
|
+
},
|
|
1560
|
+
className: "p-1 text-rose-500 hover:bg-rose-100 rounded transition-colors",
|
|
1561
|
+
title: "\u05D1\u05D9\u05D8\u05D5\u05DC",
|
|
1562
|
+
children: /* @__PURE__ */ jsx5("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M6 18L18 6M6 6l12 12" }) })
|
|
1563
|
+
}
|
|
1564
|
+
)
|
|
1565
|
+
] }) })
|
|
1566
|
+
] })
|
|
1567
|
+
] })
|
|
1568
|
+
] }) })
|
|
1569
|
+
] });
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
// src/components/TableBlock/TableBlockClient.tsx
|
|
1573
|
+
import { X as X4, Copy as Copy2 } from "lucide-react";
|
|
1574
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
867
1575
|
function TableBlockClient({
|
|
868
1576
|
data: initialRecords,
|
|
869
1577
|
settings: schema,
|
|
@@ -880,6 +1588,68 @@ function TableBlockClient({
|
|
|
880
1588
|
"data-testid": dataTestId
|
|
881
1589
|
}) {
|
|
882
1590
|
const { showError, addToast } = useToast();
|
|
1591
|
+
const [columnWidths, setColumnWidths] = useState5({});
|
|
1592
|
+
const [isMounted, setIsMounted] = useState5(false);
|
|
1593
|
+
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";
|
|
1594
|
+
const [page, setPage] = useState5(1);
|
|
1595
|
+
const [limit, setLimit] = useState5(50);
|
|
1596
|
+
const [totalRecords, setTotalRecords] = useState5(0);
|
|
1597
|
+
const [totalPages, setTotalPages] = useState5(1);
|
|
1598
|
+
useEffect4(() => {
|
|
1599
|
+
if (typeof window !== "undefined") {
|
|
1600
|
+
const savedWidths = localStorage.getItem(`table_widths_${tableKey}`);
|
|
1601
|
+
if (savedWidths) {
|
|
1602
|
+
try {
|
|
1603
|
+
setColumnWidths(JSON.parse(savedWidths));
|
|
1604
|
+
} catch (e) {
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
const savedSummary = localStorage.getItem(`table_summary_${tableKey}`);
|
|
1608
|
+
if (savedSummary !== null) {
|
|
1609
|
+
setShowSummary(savedSummary === "true");
|
|
1610
|
+
}
|
|
1611
|
+
const savedLimit = localStorage.getItem(`table_limit_${tableKey}`);
|
|
1612
|
+
if (savedLimit) {
|
|
1613
|
+
const parsed = parseInt(savedLimit, 10);
|
|
1614
|
+
if ([20, 50, 100].includes(parsed)) {
|
|
1615
|
+
setLimit(parsed);
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
setIsMounted(true);
|
|
1620
|
+
}, [tableKey]);
|
|
1621
|
+
const [showSummary, setShowSummary] = useState5(false);
|
|
1622
|
+
const toggleSummary = () => {
|
|
1623
|
+
setShowSummary((prev) => {
|
|
1624
|
+
const next = !prev;
|
|
1625
|
+
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";
|
|
1626
|
+
localStorage.setItem(`table_summary_${tableKey2}`, String(next));
|
|
1627
|
+
return next;
|
|
1628
|
+
});
|
|
1629
|
+
};
|
|
1630
|
+
const [resizingCol, setResizingCol] = useState5(null);
|
|
1631
|
+
useEffect4(() => {
|
|
1632
|
+
if (!resizingCol) return;
|
|
1633
|
+
const handleMouseMove = (e) => {
|
|
1634
|
+
const diffX = resizingCol.startX - e.clientX;
|
|
1635
|
+
const newWidth = Math.max(100, Math.min(500, resizingCol.startWidth + diffX));
|
|
1636
|
+
setColumnWidths((prev) => __spreadProps(__spreadValues({}, prev), { [resizingCol.name]: newWidth }));
|
|
1637
|
+
};
|
|
1638
|
+
const handleMouseUp = () => {
|
|
1639
|
+
setResizingCol(null);
|
|
1640
|
+
setColumnWidths((prev) => {
|
|
1641
|
+
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";
|
|
1642
|
+
localStorage.setItem(`table_widths_${tableKey2}`, JSON.stringify(prev));
|
|
1643
|
+
return prev;
|
|
1644
|
+
});
|
|
1645
|
+
};
|
|
1646
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
1647
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
1648
|
+
return () => {
|
|
1649
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
1650
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
1651
|
+
};
|
|
1652
|
+
}, [resizingCol, schema]);
|
|
883
1653
|
const normalizeRecords = (records) => {
|
|
884
1654
|
return (records || []).map((row) => {
|
|
885
1655
|
var _c;
|
|
@@ -905,18 +1675,38 @@ function TableBlockClient({
|
|
|
905
1675
|
return __spreadProps(__spreadValues({}, row), { id: String(row.id || ""), data: rowData });
|
|
906
1676
|
});
|
|
907
1677
|
};
|
|
908
|
-
const
|
|
909
|
-
|
|
1678
|
+
const mergeColumnDefs = useCallback4((existingCols, incomingCols) => {
|
|
1679
|
+
if (!incomingCols || incomingCols.length === 0) return existingCols || [];
|
|
1680
|
+
if (!existingCols || existingCols.length === 0) return incomingCols;
|
|
1681
|
+
const existingMap = new Map(existingCols.map((c) => [c.name, c]));
|
|
1682
|
+
const merged = incomingCols.map((inc) => {
|
|
1683
|
+
const ext = existingMap.get(inc.name);
|
|
1684
|
+
if (ext) {
|
|
1685
|
+
existingMap.delete(inc.name);
|
|
1686
|
+
return __spreadValues(__spreadValues({}, ext), inc);
|
|
1687
|
+
}
|
|
1688
|
+
return inc;
|
|
1689
|
+
});
|
|
1690
|
+
for (const [, extCol] of existingMap) {
|
|
1691
|
+
merged.push(extCol);
|
|
1692
|
+
}
|
|
1693
|
+
return merged.sort((a, b) => {
|
|
1694
|
+
var _a, _b;
|
|
1695
|
+
return ((_a = a.order) != null ? _a : 0) - ((_b = b.order) != null ? _b : 0);
|
|
1696
|
+
});
|
|
1697
|
+
}, []);
|
|
1698
|
+
const [localColumns, setLocalColumns] = useState5(() => (schema == null ? void 0 : schema.columns) || []);
|
|
1699
|
+
useEffect4(() => {
|
|
910
1700
|
if ((schema == null ? void 0 : schema.columns) && schema.columns.length > 0) {
|
|
911
|
-
setLocalColumns(schema.columns);
|
|
1701
|
+
setLocalColumns((prev) => mergeColumnDefs(prev, schema.columns));
|
|
912
1702
|
}
|
|
913
|
-
}, [schema == null ? void 0 : schema.columns]);
|
|
914
|
-
const [dirty, setDirty] =
|
|
915
|
-
const dirtyRef =
|
|
916
|
-
|
|
1703
|
+
}, [schema == null ? void 0 : schema.columns, mergeColumnDefs]);
|
|
1704
|
+
const [dirty, setDirty] = useState5({ added: [], modified: {}, deleted: [] });
|
|
1705
|
+
const dirtyRef = useRef4(dirty);
|
|
1706
|
+
useEffect4(() => {
|
|
917
1707
|
dirtyRef.current = dirty;
|
|
918
1708
|
}, [dirty]);
|
|
919
|
-
const mergeWithDirty =
|
|
1709
|
+
const mergeWithDirty = useCallback4((baseRecords) => {
|
|
920
1710
|
const { added, modified, deleted } = dirtyRef.current;
|
|
921
1711
|
const nonDeleted = (baseRecords || []).filter((r) => !deleted.includes(r.id));
|
|
922
1712
|
const modifiedRecords = nonDeleted.map((r) => {
|
|
@@ -929,8 +1719,8 @@ function TableBlockClient({
|
|
|
929
1719
|
const uniqueAdded = added.filter((r) => !baseIds.has(r.id));
|
|
930
1720
|
return [...uniqueAdded, ...modifiedRecords];
|
|
931
1721
|
}, []);
|
|
932
|
-
const [data, setData] =
|
|
933
|
-
|
|
1722
|
+
const [data, setData] = useState5(() => normalizeRecords(initialRecords));
|
|
1723
|
+
useEffect4(() => {
|
|
934
1724
|
if (initialRecords) {
|
|
935
1725
|
setData(mergeWithDirty(normalizeRecords(initialRecords)));
|
|
936
1726
|
}
|
|
@@ -945,54 +1735,83 @@ function TableBlockClient({
|
|
|
945
1735
|
}
|
|
946
1736
|
return false;
|
|
947
1737
|
};
|
|
948
|
-
const [baseRecordsMap, setBaseRecordsMap] =
|
|
1738
|
+
const [baseRecordsMap, setBaseRecordsMap] = useState5(() => {
|
|
949
1739
|
const map = /* @__PURE__ */ new Map();
|
|
950
1740
|
(normalizeRecords(initialRecords) || []).forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
|
|
951
1741
|
return map;
|
|
952
1742
|
});
|
|
953
|
-
|
|
1743
|
+
useEffect4(() => {
|
|
954
1744
|
if (initialRecords && initialRecords.length > 0) {
|
|
955
1745
|
const map = /* @__PURE__ */ new Map();
|
|
956
1746
|
(normalizeRecords(initialRecords) || []).forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
|
|
957
1747
|
setBaseRecordsMap(map);
|
|
958
1748
|
}
|
|
959
1749
|
}, [initialRecords]);
|
|
960
|
-
|
|
1750
|
+
const refetchTableData = useCallback4((targetPage) => {
|
|
961
1751
|
const tableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
|
|
962
|
-
if (!tableId || !executeAction) return;
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
1752
|
+
if (!tableId || !executeAction) return Promise.resolve();
|
|
1753
|
+
const activePage = targetPage !== void 0 ? targetPage : page;
|
|
1754
|
+
const skip = (activePage - 1) * limit;
|
|
1755
|
+
return executeAction("FETCH_TABLE_DATA", { tableId, page: activePage, limit, skip }).then((res) => {
|
|
1756
|
+
var _a;
|
|
1757
|
+
if (res) {
|
|
1758
|
+
if (((_a = res.schema) == null ? void 0 : _a.columns) && res.schema.columns.length > 0) {
|
|
1759
|
+
setLocalColumns((prev) => mergeColumnDefs(prev, res.schema.columns));
|
|
1760
|
+
}
|
|
1761
|
+
if (res.records && Array.isArray(res.records)) {
|
|
1762
|
+
const norm = normalizeRecords(res.records);
|
|
1763
|
+
const map = /* @__PURE__ */ new Map();
|
|
1764
|
+
norm.forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
|
|
1765
|
+
setBaseRecordsMap(map);
|
|
1766
|
+
setData(norm);
|
|
1767
|
+
}
|
|
1768
|
+
if (res.meta) {
|
|
1769
|
+
const total = typeof res.meta.totalRecords === "number" ? res.meta.totalRecords : 0;
|
|
1770
|
+
const pages = typeof res.meta.totalPages === "number" ? res.meta.totalPages : Math.ceil(total / limit) || 1;
|
|
1771
|
+
setTotalRecords(total);
|
|
1772
|
+
setTotalPages(pages);
|
|
1773
|
+
if (activePage > pages && pages >= 1) {
|
|
1774
|
+
setPage(pages);
|
|
976
1775
|
}
|
|
1776
|
+
} else if (res.records && Array.isArray(res.records)) {
|
|
1777
|
+
setTotalRecords(res.records.length);
|
|
1778
|
+
setTotalPages(Math.ceil(res.records.length / limit) || 1);
|
|
977
1779
|
}
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
|
|
1780
|
+
}
|
|
1781
|
+
}).catch((err) => {
|
|
1782
|
+
console.error("[TableBlock] Failed to auto-fetch table data:", err);
|
|
1783
|
+
});
|
|
1784
|
+
}, [schema == null ? void 0 : schema.tableMetaId, schema == null ? void 0 : schema.tableId, schema == null ? void 0 : schema.id, page, limit, executeAction, mergeColumnDefs]);
|
|
1785
|
+
useEffect4(() => {
|
|
1786
|
+
refetchTableData();
|
|
1787
|
+
}, [refetchTableData]);
|
|
1788
|
+
const handleLimitChange = (newLimit) => {
|
|
1789
|
+
setLimit(newLimit);
|
|
1790
|
+
setPage(1);
|
|
1791
|
+
if (typeof window !== "undefined") {
|
|
1792
|
+
localStorage.setItem(`table_limit_${tableKey}`, String(newLimit));
|
|
981
1793
|
}
|
|
982
|
-
}
|
|
983
|
-
|
|
1794
|
+
};
|
|
1795
|
+
const handlePrevPage = () => {
|
|
1796
|
+
setPage((prev) => Math.max(1, prev - 1));
|
|
1797
|
+
};
|
|
1798
|
+
const handleNextPage = () => {
|
|
1799
|
+
setPage((prev) => Math.min(totalPages, prev + 1));
|
|
1800
|
+
};
|
|
1801
|
+
useEffect4(() => {
|
|
984
1802
|
if (error) {
|
|
985
1803
|
showError(error, "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E8\u05DB\u05D9\u05D1");
|
|
986
1804
|
}
|
|
987
1805
|
}, [error, showError]);
|
|
988
|
-
const [searchQuery, setSearchQuery] =
|
|
989
|
-
const [selectedIds, setSelectedIds] =
|
|
990
|
-
const [pendingDeletions, setPendingDeletions] =
|
|
991
|
-
const [isSaving, setIsSaving] =
|
|
992
|
-
const [isSaveSuccess, setIsSaveSuccess] =
|
|
993
|
-
const [relationOptions, setRelationOptions] =
|
|
1806
|
+
const [searchQuery, setSearchQuery] = useState5("");
|
|
1807
|
+
const [selectedIds, setSelectedIds] = useState5(/* @__PURE__ */ new Set());
|
|
1808
|
+
const [pendingDeletions, setPendingDeletions] = useState5([]);
|
|
1809
|
+
const [isSaving, setIsSaving] = useState5(false);
|
|
1810
|
+
const [isSaveSuccess, setIsSaveSuccess] = useState5(false);
|
|
1811
|
+
const [relationOptions, setRelationOptions] = useState5({});
|
|
1812
|
+
const [expandedRowIds, setExpandedRowIds] = useState5(/* @__PURE__ */ new Set());
|
|
994
1813
|
const schemaColsString = useMemo2(() => JSON.stringify(localColumns || []), [localColumns]);
|
|
995
|
-
const refetchRelation =
|
|
1814
|
+
const refetchRelation = useCallback4(async (colName) => {
|
|
996
1815
|
var _a;
|
|
997
1816
|
let parsedCols = [];
|
|
998
1817
|
try {
|
|
@@ -1012,7 +1831,7 @@ function TableBlockClient({
|
|
|
1012
1831
|
console.warn(`[TableBlock] Could not fetch relation options for column ${colName}:`, err);
|
|
1013
1832
|
}
|
|
1014
1833
|
}, [schemaColsString, executeAction]);
|
|
1015
|
-
|
|
1834
|
+
useEffect4(() => {
|
|
1016
1835
|
let parsedCols = [];
|
|
1017
1836
|
try {
|
|
1018
1837
|
parsedCols = JSON.parse(schemaColsString);
|
|
@@ -1026,10 +1845,144 @@ function TableBlockClient({
|
|
|
1026
1845
|
refetchRelation(col.name);
|
|
1027
1846
|
});
|
|
1028
1847
|
}, [schemaColsString, refetchRelation]);
|
|
1848
|
+
const normalizedColumns = useMemo2(() => {
|
|
1849
|
+
return (localColumns || []).map((col, idx) => {
|
|
1850
|
+
const isRequired = col.isRequired === true || String(col.isRequired) === "true";
|
|
1851
|
+
const isUnique = col.isUnique === true || String(col.isUnique) === "true";
|
|
1852
|
+
const isProtected = isRequired || isUnique;
|
|
1853
|
+
return __spreadProps(__spreadValues({}, col), {
|
|
1854
|
+
order: typeof col.order === "number" ? col.order : idx,
|
|
1855
|
+
isHidden: isProtected ? false : Boolean(col.isHidden)
|
|
1856
|
+
});
|
|
1857
|
+
}).sort((a, b) => {
|
|
1858
|
+
var _a, _b;
|
|
1859
|
+
return ((_a = a.order) != null ? _a : 0) - ((_b = b.order) != null ? _b : 0);
|
|
1860
|
+
});
|
|
1861
|
+
}, [localColumns]);
|
|
1029
1862
|
const filteredColumns = useMemo2(() => {
|
|
1030
1863
|
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
1031
|
-
return
|
|
1032
|
-
}, [
|
|
1864
|
+
return normalizedColumns.filter((col) => !systemFields.includes(col.name) && !col.isHidden);
|
|
1865
|
+
}, [normalizedColumns]);
|
|
1866
|
+
const customizableColumns = useMemo2(() => {
|
|
1867
|
+
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
1868
|
+
return normalizedColumns.filter((col) => !systemFields.includes(col.name));
|
|
1869
|
+
}, [normalizedColumns]);
|
|
1870
|
+
const [isColumnsDropdownOpen, setIsColumnsDropdownOpen] = useState5(false);
|
|
1871
|
+
const dropdownRef = useRef4(null);
|
|
1872
|
+
useEffect4(() => {
|
|
1873
|
+
const handleClickOutside = (e) => {
|
|
1874
|
+
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
1875
|
+
setIsColumnsDropdownOpen(false);
|
|
1876
|
+
}
|
|
1877
|
+
};
|
|
1878
|
+
if (isColumnsDropdownOpen) {
|
|
1879
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
1880
|
+
}
|
|
1881
|
+
return () => {
|
|
1882
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
1883
|
+
};
|
|
1884
|
+
}, [isColumnsDropdownOpen]);
|
|
1885
|
+
const handleShowAllColumns = async () => {
|
|
1886
|
+
var _a;
|
|
1887
|
+
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
1888
|
+
const systemCols = (localColumns || []).filter((c) => systemFields.includes(c.name));
|
|
1889
|
+
const updatedCustomCols = customizableColumns.map((col) => __spreadProps(__spreadValues({}, col), {
|
|
1890
|
+
isHidden: false
|
|
1891
|
+
}));
|
|
1892
|
+
const fullUpdatedColumns = [...systemCols, ...updatedCustomCols];
|
|
1893
|
+
setLocalColumns(fullUpdatedColumns);
|
|
1894
|
+
const targetTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
|
|
1895
|
+
if (targetTableId && executeAction) {
|
|
1896
|
+
try {
|
|
1897
|
+
const res = await executeAction("UPDATE_TABLE_COLUMNS", {
|
|
1898
|
+
tableId: targetTableId,
|
|
1899
|
+
tableMetaId: targetTableId,
|
|
1900
|
+
columns: fullUpdatedColumns
|
|
1901
|
+
});
|
|
1902
|
+
const returnedCols = (res == null ? void 0 : res.columns) || ((_a = res == null ? void 0 : res.data) == null ? void 0 : _a.columns);
|
|
1903
|
+
if (returnedCols && Array.isArray(returnedCols)) {
|
|
1904
|
+
setLocalColumns((prev) => mergeColumnDefs(prev, returnedCols));
|
|
1905
|
+
}
|
|
1906
|
+
} catch (err) {
|
|
1907
|
+
console.error("[TableBlock] Failed to save show all columns:", err);
|
|
1908
|
+
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");
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
};
|
|
1912
|
+
const handleToggleColumnVisibility = async (colName, isVisible) => {
|
|
1913
|
+
var _a;
|
|
1914
|
+
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
1915
|
+
const systemCols = (localColumns || []).filter((c) => systemFields.includes(c.name));
|
|
1916
|
+
const updatedCustomCols = customizableColumns.map((col) => {
|
|
1917
|
+
const isRequired = col.isRequired === true || String(col.isRequired) === "true";
|
|
1918
|
+
const isUnique = col.isUnique === true || String(col.isUnique) === "true";
|
|
1919
|
+
const isProtected = isRequired || isUnique;
|
|
1920
|
+
if (col.name === colName) {
|
|
1921
|
+
if (isProtected) {
|
|
1922
|
+
return __spreadProps(__spreadValues({}, col), { isHidden: false });
|
|
1923
|
+
}
|
|
1924
|
+
return __spreadProps(__spreadValues({}, col), { isHidden: !isVisible });
|
|
1925
|
+
}
|
|
1926
|
+
return __spreadProps(__spreadValues({}, col), {
|
|
1927
|
+
isHidden: isProtected ? false : Boolean(col.isHidden)
|
|
1928
|
+
});
|
|
1929
|
+
});
|
|
1930
|
+
const fullUpdatedColumns = [...systemCols, ...updatedCustomCols];
|
|
1931
|
+
setLocalColumns(fullUpdatedColumns);
|
|
1932
|
+
const targetTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
|
|
1933
|
+
if (targetTableId && executeAction) {
|
|
1934
|
+
try {
|
|
1935
|
+
const res = await executeAction("UPDATE_TABLE_COLUMNS", {
|
|
1936
|
+
tableId: targetTableId,
|
|
1937
|
+
tableMetaId: targetTableId,
|
|
1938
|
+
columns: fullUpdatedColumns
|
|
1939
|
+
});
|
|
1940
|
+
const returnedCols = (res == null ? void 0 : res.columns) || ((_a = res == null ? void 0 : res.data) == null ? void 0 : _a.columns);
|
|
1941
|
+
if (returnedCols && Array.isArray(returnedCols)) {
|
|
1942
|
+
setLocalColumns((prev) => mergeColumnDefs(prev, returnedCols));
|
|
1943
|
+
}
|
|
1944
|
+
} catch (err) {
|
|
1945
|
+
console.error("[TableBlock] Failed to save column visibility:", err);
|
|
1946
|
+
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");
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
};
|
|
1950
|
+
const [draggedColName, setDraggedColName] = useState5(null);
|
|
1951
|
+
const [dragOverColName, setDragOverColName] = useState5(null);
|
|
1952
|
+
const handleColumnReorder = async (draggedName, dropTargetName) => {
|
|
1953
|
+
var _a;
|
|
1954
|
+
if (draggedName === dropTargetName) return;
|
|
1955
|
+
const currentCustomCols = [...customizableColumns];
|
|
1956
|
+
const fromIndex = currentCustomCols.findIndex((c) => c.name === draggedName);
|
|
1957
|
+
const toIndex = currentCustomCols.findIndex((c) => c.name === dropTargetName);
|
|
1958
|
+
if (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) return;
|
|
1959
|
+
const [draggedItem] = currentCustomCols.splice(fromIndex, 1);
|
|
1960
|
+
currentCustomCols.splice(toIndex, 0, draggedItem);
|
|
1961
|
+
const updatedCustomCols = currentCustomCols.map((col, idx) => __spreadProps(__spreadValues({}, col), {
|
|
1962
|
+
order: idx
|
|
1963
|
+
}));
|
|
1964
|
+
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
1965
|
+
const systemCols = (localColumns || []).filter((c) => systemFields.includes(c.name));
|
|
1966
|
+
const fullUpdatedColumns = [...systemCols, ...updatedCustomCols];
|
|
1967
|
+
setLocalColumns(fullUpdatedColumns);
|
|
1968
|
+
const targetTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
|
|
1969
|
+
if (targetTableId && executeAction) {
|
|
1970
|
+
try {
|
|
1971
|
+
const res = await executeAction("UPDATE_TABLE_COLUMNS", {
|
|
1972
|
+
tableId: targetTableId,
|
|
1973
|
+
tableMetaId: targetTableId,
|
|
1974
|
+
columns: fullUpdatedColumns
|
|
1975
|
+
});
|
|
1976
|
+
const returnedCols = (res == null ? void 0 : res.columns) || ((_a = res == null ? void 0 : res.data) == null ? void 0 : _a.columns);
|
|
1977
|
+
if (returnedCols && Array.isArray(returnedCols)) {
|
|
1978
|
+
setLocalColumns((prev) => mergeColumnDefs(prev, returnedCols));
|
|
1979
|
+
}
|
|
1980
|
+
} catch (err) {
|
|
1981
|
+
console.error("[TableBlock] Failed to save column reorder:", err);
|
|
1982
|
+
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");
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
};
|
|
1033
1986
|
const generateTempId = () => `temp_${Math.random().toString(36).substr(2, 9)}`;
|
|
1034
1987
|
const handleAddRow = () => {
|
|
1035
1988
|
const defaultData = {};
|
|
@@ -1037,6 +1990,10 @@ function TableBlockClient({
|
|
|
1037
1990
|
var _a;
|
|
1038
1991
|
const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
|
|
1039
1992
|
let initialValue = col.defaultValue;
|
|
1993
|
+
if (typeUpper === "SUB_TABLE") {
|
|
1994
|
+
defaultData[col.name] = [];
|
|
1995
|
+
return;
|
|
1996
|
+
}
|
|
1040
1997
|
if (initialValue !== void 0 && initialValue !== null && initialValue !== "") {
|
|
1041
1998
|
if (typeUpper === "CURRENCY" || typeUpper === "NUMBER") {
|
|
1042
1999
|
initialValue = parseFloat(initialValue);
|
|
@@ -1059,6 +2016,34 @@ function TableBlockClient({
|
|
|
1059
2016
|
setData((prev) => [newRow, ...prev]);
|
|
1060
2017
|
setDirty((prev) => __spreadProps(__spreadValues({}, prev), { added: [newRow, ...prev.added] }));
|
|
1061
2018
|
};
|
|
2019
|
+
const handleDuplicateRow = () => {
|
|
2020
|
+
if (selectedIds.size !== 1) return;
|
|
2021
|
+
const targetId = Array.from(selectedIds)[0];
|
|
2022
|
+
const sourceRow = data.find((r) => r.id === targetId);
|
|
2023
|
+
if (!sourceRow) return;
|
|
2024
|
+
const uniqueColNames = new Set(
|
|
2025
|
+
(localColumns || []).filter((c) => c.isUnique === true || String(c.isUnique) === "true").map((c) => c.name)
|
|
2026
|
+
);
|
|
2027
|
+
const fieldsToScrub = /* @__PURE__ */ new Set(["id", "_id", "createdAt", "updatedAt", "created_at", "updated_at"]);
|
|
2028
|
+
const clonedData = __spreadValues({}, sourceRow.data);
|
|
2029
|
+
Object.keys(clonedData).forEach((key) => {
|
|
2030
|
+
var _a;
|
|
2031
|
+
if (fieldsToScrub.has(key) || uniqueColNames.has(key)) {
|
|
2032
|
+
const col = (localColumns || []).find((c) => c.name === key);
|
|
2033
|
+
const typeUpper = (_a = col == null ? void 0 : col.type) == null ? void 0 : _a.toUpperCase();
|
|
2034
|
+
if (typeUpper === "NUMBER" || typeUpper === "CURRENCY") {
|
|
2035
|
+
clonedData[key] = 0;
|
|
2036
|
+
} else if (typeUpper === "BOOLEAN") {
|
|
2037
|
+
clonedData[key] = false;
|
|
2038
|
+
} else {
|
|
2039
|
+
clonedData[key] = "";
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
});
|
|
2043
|
+
const newRow = { id: generateTempId(), data: clonedData };
|
|
2044
|
+
setData((prev) => [newRow, ...prev]);
|
|
2045
|
+
setDirty((prev) => __spreadProps(__spreadValues({}, prev), { added: [newRow, ...prev.added] }));
|
|
2046
|
+
};
|
|
1062
2047
|
const handleCellChange = (rowId, colName, value) => {
|
|
1063
2048
|
setData((prev) => prev.map(
|
|
1064
2049
|
(row) => row.id === rowId ? __spreadProps(__spreadValues({}, row), { data: __spreadProps(__spreadValues({}, row.data), { [colName]: value }) }) : row
|
|
@@ -1092,6 +2077,36 @@ function TableBlockClient({
|
|
|
1092
2077
|
});
|
|
1093
2078
|
}
|
|
1094
2079
|
};
|
|
2080
|
+
const triggerSaveSuccess = useCallback4(() => {
|
|
2081
|
+
setIsSaveSuccess(true);
|
|
2082
|
+
setTimeout(() => {
|
|
2083
|
+
setIsSaveSuccess(false);
|
|
2084
|
+
}, 2500);
|
|
2085
|
+
}, []);
|
|
2086
|
+
const handleQuietCellChange = useCallback4((rowId, colName, value) => {
|
|
2087
|
+
setData((prev) => prev.map(
|
|
2088
|
+
(row) => row.id === rowId ? __spreadProps(__spreadValues({}, row), { data: __spreadProps(__spreadValues({}, row.data), { [colName]: value }) }) : row
|
|
2089
|
+
));
|
|
2090
|
+
if (rowId.startsWith("temp_")) {
|
|
2091
|
+
setDirty((prev) => {
|
|
2092
|
+
if (!prev.added.some((r) => r.id === rowId)) return prev;
|
|
2093
|
+
return __spreadProps(__spreadValues({}, prev), {
|
|
2094
|
+
added: prev.added.map(
|
|
2095
|
+
(r) => r.id === rowId ? __spreadProps(__spreadValues({}, r), { data: __spreadProps(__spreadValues({}, r.data), { [colName]: value }) }) : r
|
|
2096
|
+
)
|
|
2097
|
+
});
|
|
2098
|
+
});
|
|
2099
|
+
} else {
|
|
2100
|
+
setBaseRecordsMap((prev) => {
|
|
2101
|
+
const next = new Map(prev);
|
|
2102
|
+
const rowData = next.get(rowId);
|
|
2103
|
+
if (rowData) {
|
|
2104
|
+
next.set(rowId, __spreadProps(__spreadValues({}, rowData), { [colName]: value }));
|
|
2105
|
+
}
|
|
2106
|
+
return next;
|
|
2107
|
+
});
|
|
2108
|
+
}
|
|
2109
|
+
}, []);
|
|
1095
2110
|
const toggleSelectAll = (checked) => {
|
|
1096
2111
|
const nextSelected = checked ? new Set(filteredData.map((r) => r.id)) : /* @__PURE__ */ new Set();
|
|
1097
2112
|
setSelectedIds(nextSelected);
|
|
@@ -1121,9 +2136,15 @@ function TableBlockClient({
|
|
|
1121
2136
|
const row = data.find((r) => r.id === id);
|
|
1122
2137
|
if (row) {
|
|
1123
2138
|
driveCols.forEach((col) => {
|
|
1124
|
-
const
|
|
1125
|
-
if (
|
|
1126
|
-
|
|
2139
|
+
const fileVal = row.data[col.name];
|
|
2140
|
+
if (Array.isArray(fileVal)) {
|
|
2141
|
+
fileVal.forEach((fileObj) => {
|
|
2142
|
+
if (fileObj && fileObj.fileId) {
|
|
2143
|
+
filesToDelete.push(fileObj.fileId);
|
|
2144
|
+
}
|
|
2145
|
+
});
|
|
2146
|
+
} else if (fileVal && fileVal.fileId) {
|
|
2147
|
+
filesToDelete.push(fileVal.fileId);
|
|
1127
2148
|
}
|
|
1128
2149
|
});
|
|
1129
2150
|
}
|
|
@@ -1150,7 +2171,7 @@ function TableBlockClient({
|
|
|
1150
2171
|
const formatPayload = (payload) => {
|
|
1151
2172
|
const formatted = {};
|
|
1152
2173
|
(localColumns || []).forEach((col) => {
|
|
1153
|
-
var _a;
|
|
2174
|
+
var _a, _b;
|
|
1154
2175
|
if (["_id", "id", "createdAt", "updatedAt", "orgId", "tableId", "isSelected"].includes(col.name)) return;
|
|
1155
2176
|
let val = payload[col.name];
|
|
1156
2177
|
if (val !== void 0) {
|
|
@@ -1160,6 +2181,11 @@ function TableBlockClient({
|
|
|
1160
2181
|
if (((_a = col.type) == null ? void 0 : _a.toUpperCase()) === "NUMBER") {
|
|
1161
2182
|
val = val === "" ? 0 : Number(val);
|
|
1162
2183
|
if (isNaN(val)) val = 0;
|
|
2184
|
+
} else if (((_b = col.type) == null ? void 0 : _b.toUpperCase()) === "SUB_TABLE" && Array.isArray(val)) {
|
|
2185
|
+
val = val.map((item) => {
|
|
2186
|
+
const _a2 = item, { _resolvedData } = _a2, rest = __objRest(_a2, ["_resolvedData"]);
|
|
2187
|
+
return rest;
|
|
2188
|
+
});
|
|
1163
2189
|
}
|
|
1164
2190
|
formatted[col.name] = val;
|
|
1165
2191
|
}
|
|
@@ -1279,6 +2305,7 @@ function TableBlockClient({
|
|
|
1279
2305
|
return next;
|
|
1280
2306
|
});
|
|
1281
2307
|
setDirty({ added: [], modified: {}, deleted: [] });
|
|
2308
|
+
await refetchTableData();
|
|
1282
2309
|
setIsSaveSuccess(true);
|
|
1283
2310
|
setTimeout(() => {
|
|
1284
2311
|
setIsSaveSuccess(false);
|
|
@@ -1302,32 +2329,60 @@ function TableBlockClient({
|
|
|
1302
2329
|
}, [data, searchQuery]);
|
|
1303
2330
|
const isUpdatingActive = Boolean(isUpdating || isSaving);
|
|
1304
2331
|
const errorMessage = error ? typeof error === "string" ? error : error.message || String(error) : null;
|
|
1305
|
-
|
|
2332
|
+
const columnTotals = useMemo2(() => {
|
|
2333
|
+
const totals = {};
|
|
2334
|
+
if (!showSummary) return totals;
|
|
2335
|
+
filteredColumns.forEach((col) => {
|
|
2336
|
+
var _a;
|
|
2337
|
+
const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
|
|
2338
|
+
if (typeUpper === "CURRENCY" || typeUpper === "NUMBER") {
|
|
2339
|
+
const sum = filteredData.reduce((acc, row) => {
|
|
2340
|
+
var _a2;
|
|
2341
|
+
const val = (_a2 = row.data) == null ? void 0 : _a2[col.name];
|
|
2342
|
+
const num = Number(val);
|
|
2343
|
+
return acc + (isNaN(num) ? 0 : num);
|
|
2344
|
+
}, 0);
|
|
2345
|
+
totals[col.name] = sum;
|
|
2346
|
+
}
|
|
2347
|
+
});
|
|
2348
|
+
return totals;
|
|
2349
|
+
}, [filteredData, filteredColumns, showSummary]);
|
|
2350
|
+
return /* @__PURE__ */ jsxs6(
|
|
1306
2351
|
"div",
|
|
1307
2352
|
{
|
|
1308
2353
|
id: componentId,
|
|
1309
2354
|
"data-testid": dataTestId || (componentId ? `table-block-${componentId}` : void 0),
|
|
1310
|
-
className: `flex flex-col w-full bg-white border border-slate-200 rounded-xl shadow-xs overflow-hidden ${className}`,
|
|
2355
|
+
className: `flex flex-col w-full bg-white border border-slate-200 rounded-xl shadow-xs min-h-[350px] overflow-hidden ${className}`,
|
|
1311
2356
|
dir: "rtl",
|
|
1312
2357
|
children: [
|
|
1313
|
-
errorMessage && /* @__PURE__ */
|
|
1314
|
-
/* @__PURE__ */
|
|
1315
|
-
/* @__PURE__ */
|
|
2358
|
+
errorMessage && /* @__PURE__ */ jsx6("div", { className: "p-3 bg-rose-50 border-b border-rose-200 text-rose-700 text-sm flex items-center justify-between", children: /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
2359
|
+
/* @__PURE__ */ jsx6("svg", { className: "w-4 h-4 text-rose-500 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
|
|
2360
|
+
/* @__PURE__ */ jsx6("span", { children: errorMessage })
|
|
1316
2361
|
] }) }),
|
|
1317
|
-
/* @__PURE__ */
|
|
1318
|
-
/* @__PURE__ */
|
|
1319
|
-
((schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.name)) && /* @__PURE__ */
|
|
1320
|
-
/* @__PURE__ */
|
|
2362
|
+
/* @__PURE__ */ jsxs6("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: [
|
|
2363
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex flex-wrap items-center gap-2.5", children: [
|
|
2364
|
+
((schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.name)) && /* @__PURE__ */ jsx6("div", { className: "font-bold text-slate-800 text-sm sm:text-base border-l border-slate-300 pl-3 ml-1", children: /* @__PURE__ */ jsx6("span", { children: schema.title || schema.name }) }),
|
|
2365
|
+
/* @__PURE__ */ jsx6(
|
|
1321
2366
|
"button",
|
|
1322
2367
|
{
|
|
1323
2368
|
onClick: handleAddRow,
|
|
1324
2369
|
disabled: isLoading || isUpdatingActive,
|
|
1325
2370
|
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",
|
|
1326
2371
|
title: "\u05D4\u05D5\u05E1\u05E3 \u05E9\u05D5\u05E8\u05D4 \u05D7\u05D3\u05E9\u05D4",
|
|
1327
|
-
children: /* @__PURE__ */
|
|
2372
|
+
children: /* @__PURE__ */ jsx6("svg", { className: "w-4.5 h-4.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M12 4v16m8-8H4" }) })
|
|
1328
2373
|
}
|
|
1329
2374
|
),
|
|
1330
|
-
/* @__PURE__ */
|
|
2375
|
+
/* @__PURE__ */ jsx6(
|
|
2376
|
+
"button",
|
|
2377
|
+
{
|
|
2378
|
+
onClick: handleDuplicateRow,
|
|
2379
|
+
disabled: isLoading || isUpdatingActive || selectedIds.size !== 1,
|
|
2380
|
+
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",
|
|
2381
|
+
title: "\u05E9\u05DB\u05E4\u05DC \u05E9\u05D5\u05E8\u05D4 \u05E0\u05D1\u05D7\u05E8\u05EA",
|
|
2382
|
+
children: /* @__PURE__ */ jsx6(Copy2, { className: "w-4 h-4 text-blue-600 shrink-0" })
|
|
2383
|
+
}
|
|
2384
|
+
),
|
|
2385
|
+
/* @__PURE__ */ jsxs6(
|
|
1331
2386
|
"button",
|
|
1332
2387
|
{
|
|
1333
2388
|
onClick: handleDeleteSelected,
|
|
@@ -1335,14 +2390,120 @@ function TableBlockClient({
|
|
|
1335
2390
|
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",
|
|
1336
2391
|
title: "\u05DE\u05D7\u05E7 \u05E9\u05D5\u05E8\u05D5\u05EA \u05E0\u05D1\u05D7\u05E8\u05D5\u05EA",
|
|
1337
2392
|
children: [
|
|
1338
|
-
/* @__PURE__ */
|
|
1339
|
-
selectedIds.size > 0 && /* @__PURE__ */
|
|
2393
|
+
/* @__PURE__ */ jsx6("svg", { className: "w-4.5 h-4.5 text-rose-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx6("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" }) }),
|
|
2394
|
+
selectedIds.size > 0 && /* @__PURE__ */ jsx6("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 })
|
|
1340
2395
|
]
|
|
1341
2396
|
}
|
|
1342
2397
|
),
|
|
1343
|
-
/* @__PURE__ */
|
|
1344
|
-
|
|
1345
|
-
|
|
2398
|
+
/* @__PURE__ */ jsxs6(
|
|
2399
|
+
"button",
|
|
2400
|
+
{
|
|
2401
|
+
onClick: toggleSummary,
|
|
2402
|
+
disabled: isLoading || isUpdatingActive,
|
|
2403
|
+
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"}`,
|
|
2404
|
+
title: "\u05D4\u05E6\u05D2/\u05D4\u05E1\u05EA\u05E8 \u05E9\u05D5\u05E8\u05EA \u05E1\u05D9\u05DB\u05D5\u05DD",
|
|
2405
|
+
children: [
|
|
2406
|
+
/* @__PURE__ */ jsx6("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) }),
|
|
2407
|
+
/* @__PURE__ */ jsx6("span", { className: "hidden sm:inline", children: "\u05E1\u05DB\u05D9\u05DE\u05D4" })
|
|
2408
|
+
]
|
|
2409
|
+
}
|
|
2410
|
+
),
|
|
2411
|
+
/* @__PURE__ */ jsxs6("div", { className: "relative", ref: dropdownRef, children: [
|
|
2412
|
+
/* @__PURE__ */ jsxs6(
|
|
2413
|
+
"button",
|
|
2414
|
+
{
|
|
2415
|
+
onClick: () => setIsColumnsDropdownOpen((prev) => !prev),
|
|
2416
|
+
disabled: isLoading || isUpdatingActive,
|
|
2417
|
+
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",
|
|
2418
|
+
title: "\u05D4\u05E6\u05D2/\u05D4\u05E1\u05EA\u05E8 \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA",
|
|
2419
|
+
children: [
|
|
2420
|
+
/* @__PURE__ */ jsx6("svg", { className: "w-4 h-4 text-slate-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx6("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" }) }),
|
|
2421
|
+
/* @__PURE__ */ jsx6("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__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M19 9l-7 7-7-7" }) })
|
|
2422
|
+
]
|
|
2423
|
+
}
|
|
2424
|
+
),
|
|
2425
|
+
isColumnsDropdownOpen && /* @__PURE__ */ jsxs6("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: [
|
|
2426
|
+
/* @__PURE__ */ jsxs6("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: [
|
|
2427
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1.5", children: [
|
|
2428
|
+
/* @__PURE__ */ jsx6("span", { children: "\u05D4\u05E6\u05D2\u05EA \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA" }),
|
|
2429
|
+
/* @__PURE__ */ jsxs6("span", { className: "text-[10px] font-normal text-slate-400", children: [
|
|
2430
|
+
"(",
|
|
2431
|
+
customizableColumns.filter((c) => !c.isHidden).length,
|
|
2432
|
+
"/",
|
|
2433
|
+
customizableColumns.length,
|
|
2434
|
+
")"
|
|
2435
|
+
] })
|
|
2436
|
+
] }),
|
|
2437
|
+
/* @__PURE__ */ jsx6(
|
|
2438
|
+
"button",
|
|
2439
|
+
{
|
|
2440
|
+
type: "button",
|
|
2441
|
+
onClick: handleShowAllColumns,
|
|
2442
|
+
className: "text-xs text-brand hover:text-brand-hover font-semibold hover:underline cursor-pointer",
|
|
2443
|
+
children: "\u05D4\u05E6\u05D2 \u05D4\u05DB\u05DC"
|
|
2444
|
+
}
|
|
2445
|
+
)
|
|
2446
|
+
] }),
|
|
2447
|
+
/* @__PURE__ */ jsx6("div", { className: "max-h-60 overflow-y-auto space-y-0.5", children: customizableColumns.map((col) => {
|
|
2448
|
+
const isRequired = col.isRequired === true || String(col.isRequired) === "true";
|
|
2449
|
+
const isUnique = col.isUnique === true || String(col.isUnique) === "true";
|
|
2450
|
+
const isProtected = isRequired || isUnique;
|
|
2451
|
+
const isVisible = !col.isHidden;
|
|
2452
|
+
let protectedExplanation = "";
|
|
2453
|
+
if (isRequired && isUnique) {
|
|
2454
|
+
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";
|
|
2455
|
+
} else if (isRequired) {
|
|
2456
|
+
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";
|
|
2457
|
+
} else if (isUnique) {
|
|
2458
|
+
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";
|
|
2459
|
+
}
|
|
2460
|
+
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";
|
|
2461
|
+
return /* @__PURE__ */ jsxs6(
|
|
2462
|
+
"div",
|
|
2463
|
+
{
|
|
2464
|
+
onClick: () => {
|
|
2465
|
+
if (!isProtected) {
|
|
2466
|
+
handleToggleColumnVisibility(col.name, !isVisible);
|
|
2467
|
+
}
|
|
2468
|
+
},
|
|
2469
|
+
title: isProtected ? protectedExplanation : void 0,
|
|
2470
|
+
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"}`,
|
|
2471
|
+
children: [
|
|
2472
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
2473
|
+
/* @__PURE__ */ jsx6(
|
|
2474
|
+
"input",
|
|
2475
|
+
{
|
|
2476
|
+
type: "checkbox",
|
|
2477
|
+
checked: isVisible,
|
|
2478
|
+
disabled: isProtected,
|
|
2479
|
+
onChange: () => {
|
|
2480
|
+
},
|
|
2481
|
+
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"
|
|
2482
|
+
}
|
|
2483
|
+
),
|
|
2484
|
+
/* @__PURE__ */ jsx6("span", { className: `font-medium truncate ${isProtected ? "text-slate-500" : "text-slate-700"}`, children: col.name })
|
|
2485
|
+
] }),
|
|
2486
|
+
isProtected && /* @__PURE__ */ jsxs6(
|
|
2487
|
+
"div",
|
|
2488
|
+
{
|
|
2489
|
+
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",
|
|
2490
|
+
title: protectedExplanation,
|
|
2491
|
+
children: [
|
|
2492
|
+
/* @__PURE__ */ jsx6("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__ */ jsx6("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" }) }),
|
|
2493
|
+
/* @__PURE__ */ jsx6("span", { children: badgeLabel })
|
|
2494
|
+
]
|
|
2495
|
+
}
|
|
2496
|
+
)
|
|
2497
|
+
]
|
|
2498
|
+
},
|
|
2499
|
+
col.name
|
|
2500
|
+
);
|
|
2501
|
+
}) })
|
|
2502
|
+
] })
|
|
2503
|
+
] }),
|
|
2504
|
+
/* @__PURE__ */ jsx6("div", { className: "h-5 w-px bg-slate-300 mx-1 hidden sm:block" }),
|
|
2505
|
+
/* @__PURE__ */ jsxs6("div", { className: "relative flex-1 sm:w-64 max-w-xs", children: [
|
|
2506
|
+
/* @__PURE__ */ jsx6(
|
|
1346
2507
|
"input",
|
|
1347
2508
|
{
|
|
1348
2509
|
placeholder: "\u05D7\u05D9\u05E4\u05D5\u05E9 \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA...",
|
|
@@ -1352,36 +2513,45 @@ function TableBlockClient({
|
|
|
1352
2513
|
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"
|
|
1353
2514
|
}
|
|
1354
2515
|
),
|
|
1355
|
-
|
|
2516
|
+
searchQuery ? /* @__PURE__ */ jsx6(
|
|
2517
|
+
"button",
|
|
2518
|
+
{
|
|
2519
|
+
type: "button",
|
|
2520
|
+
onClick: () => setSearchQuery(""),
|
|
2521
|
+
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",
|
|
2522
|
+
title: "Clear search",
|
|
2523
|
+
children: /* @__PURE__ */ jsx6(X4, { className: "w-3.5 h-3.5" })
|
|
2524
|
+
}
|
|
2525
|
+
) : /* @__PURE__ */ jsx6("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__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) })
|
|
1356
2526
|
] })
|
|
1357
2527
|
] }),
|
|
1358
|
-
/* @__PURE__ */
|
|
1359
|
-
isUpdatingActive ? /* @__PURE__ */
|
|
1360
|
-
/* @__PURE__ */
|
|
2528
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-3", children: [
|
|
2529
|
+
isUpdatingActive ? /* @__PURE__ */ jsxs6("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: [
|
|
2530
|
+
/* @__PURE__ */ jsx6("span", { className: "w-2 h-2 rounded-full bg-blue-500 inline-block" }),
|
|
1361
2531
|
"\u05DE\u05E2\u05D3\u05DB\u05DF..."
|
|
1362
|
-
] }) : isSaveSuccess ? /* @__PURE__ */
|
|
1363
|
-
/* @__PURE__ */
|
|
2532
|
+
] }) : isSaveSuccess ? /* @__PURE__ */ jsxs6("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: [
|
|
2533
|
+
/* @__PURE__ */ jsx6("svg", { className: "w-4 h-4 text-emerald-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M5 13l4 4L19 7" }) }),
|
|
1364
2534
|
"\u05E2\u05D5\u05D3\u05DB\u05DF \u05D1\u05D4\u05E6\u05DC\u05D7\u05D4"
|
|
1365
|
-
] }) : hasChanges ? /* @__PURE__ */
|
|
1366
|
-
/* @__PURE__ */
|
|
2535
|
+
] }) : hasChanges ? /* @__PURE__ */ jsx6("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,
|
|
2536
|
+
/* @__PURE__ */ jsx6(
|
|
1367
2537
|
"button",
|
|
1368
2538
|
{
|
|
1369
2539
|
onClick: handleSave,
|
|
1370
2540
|
disabled: isUpdatingActive || isLoading || !hasChanges,
|
|
1371
2541
|
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"}`,
|
|
1372
|
-
children: /* @__PURE__ */
|
|
2542
|
+
children: /* @__PURE__ */ jsx6("span", { children: isUpdatingActive ? "\u05E9\u05D5\u05DE\u05E8..." : "\u05E9\u05DE\u05D9\u05E8\u05EA \u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD" })
|
|
1373
2543
|
}
|
|
1374
2544
|
)
|
|
1375
2545
|
] })
|
|
1376
2546
|
] }),
|
|
1377
|
-
/* @__PURE__ */
|
|
1378
|
-
isLoading && /* @__PURE__ */
|
|
1379
|
-
/* @__PURE__ */
|
|
1380
|
-
/* @__PURE__ */
|
|
2547
|
+
/* @__PURE__ */ jsxs6("div", { className: `overflow-x-auto relative min-h-[260px] flex-1 transition-opacity duration-200 ${isMounted ? "opacity-100" : "opacity-0"}`, children: [
|
|
2548
|
+
isLoading && /* @__PURE__ */ jsxs6("div", { className: "absolute inset-0 bg-white/80 backdrop-blur-xs z-20 flex flex-col items-center justify-center gap-2", children: [
|
|
2549
|
+
/* @__PURE__ */ jsx6("div", { className: "w-6 h-6 border-2 border-brand border-t-transparent rounded-full animate-spin" }),
|
|
2550
|
+
/* @__PURE__ */ jsx6("span", { className: "text-sm font-medium text-slate-600", children: "\u05D8\u05D5\u05E2\u05DF \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD..." })
|
|
1381
2551
|
] }),
|
|
1382
|
-
/* @__PURE__ */
|
|
1383
|
-
/* @__PURE__ */
|
|
1384
|
-
/* @__PURE__ */
|
|
2552
|
+
/* @__PURE__ */ jsxs6("table", { className: "w-full text-sm text-right border-collapse table-auto", children: [
|
|
2553
|
+
/* @__PURE__ */ jsx6("thead", { className: "bg-slate-100/80 text-slate-700 sticky top-0 z-10", children: /* @__PURE__ */ jsxs6("tr", { children: [
|
|
2554
|
+
/* @__PURE__ */ jsx6("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__ */ jsx6(
|
|
1385
2555
|
"input",
|
|
1386
2556
|
{
|
|
1387
2557
|
type: "checkbox",
|
|
@@ -1391,67 +2561,313 @@ function TableBlockClient({
|
|
|
1391
2561
|
className: "w-4 h-4 rounded border-slate-300 text-brand"
|
|
1392
2562
|
}
|
|
1393
2563
|
) }),
|
|
1394
|
-
filteredColumns.map((col) => /* @__PURE__ */ jsx5("th", { className: "border-b border-l border-slate-200 px-4 py-2.5 font-semibold text-slate-700 whitespace-nowrap min-w-[140px]", children: col.name }, col.name))
|
|
1395
|
-
] }) }),
|
|
1396
|
-
/* @__PURE__ */ jsx5("tbody", { className: "bg-white", children: (isStateEmpty || filteredData.length === 0) && !isLoading ? /* @__PURE__ */ jsx5("tr", { children: /* @__PURE__ */ jsx5("td", { colSpan: filteredColumns.length + 1, className: "text-center py-12 text-slate-400", children: /* @__PURE__ */ jsxs5("div", { className: "flex flex-col items-center justify-center gap-2", children: [
|
|
1397
|
-
/* @__PURE__ */ jsx5("svg", { className: "w-8 h-8 text-slate-300", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx5("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" }) }),
|
|
1398
|
-
/* @__PURE__ */ jsx5("span", { children: "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05DC\u05D4\u05E6\u05D2\u05D4." })
|
|
1399
|
-
] }) }) }) : filteredData.map((row) => /* @__PURE__ */ jsxs5("tr", { className: "hover:bg-blue-50/30 transition-colors group", children: [
|
|
1400
|
-
/* @__PURE__ */ jsx5("td", { className: "border-b border-l border-slate-200 p-1.5 text-center bg-white group-hover:bg-transparent", children: /* @__PURE__ */ jsx5(
|
|
1401
|
-
"input",
|
|
1402
|
-
{
|
|
1403
|
-
type: "checkbox",
|
|
1404
|
-
checked: selectedIds.has(row.id),
|
|
1405
|
-
onChange: (e) => toggleSelectRow(row.id, e.target.checked),
|
|
1406
|
-
disabled: isLoading || isUpdatingActive,
|
|
1407
|
-
className: "w-4 h-4 rounded border-slate-300 text-brand"
|
|
1408
|
-
}
|
|
1409
|
-
) }),
|
|
1410
2564
|
filteredColumns.map((col) => {
|
|
2565
|
+
const isDragging = draggedColName === col.name;
|
|
2566
|
+
const isDragOver = dragOverColName === col.name;
|
|
2567
|
+
const currentWidth = columnWidths[col.name] || 200;
|
|
2568
|
+
return /* @__PURE__ */ jsxs6(
|
|
2569
|
+
"th",
|
|
2570
|
+
{
|
|
2571
|
+
style: { width: currentWidth, minWidth: currentWidth, maxWidth: currentWidth },
|
|
2572
|
+
draggable: !isLoading && !isUpdatingActive,
|
|
2573
|
+
onDragStart: (e) => {
|
|
2574
|
+
e.dataTransfer.setData("text/plain", col.name);
|
|
2575
|
+
e.dataTransfer.effectAllowed = "move";
|
|
2576
|
+
setDraggedColName(col.name);
|
|
2577
|
+
},
|
|
2578
|
+
onDragOver: (e) => {
|
|
2579
|
+
e.preventDefault();
|
|
2580
|
+
e.dataTransfer.dropEffect = "move";
|
|
2581
|
+
if (dragOverColName !== col.name) {
|
|
2582
|
+
setDragOverColName(col.name);
|
|
2583
|
+
}
|
|
2584
|
+
},
|
|
2585
|
+
onDragLeave: () => {
|
|
2586
|
+
if (dragOverColName === col.name) {
|
|
2587
|
+
setDragOverColName(null);
|
|
2588
|
+
}
|
|
2589
|
+
},
|
|
2590
|
+
onDrop: (e) => {
|
|
2591
|
+
e.preventDefault();
|
|
2592
|
+
if (draggedColName && draggedColName !== col.name) {
|
|
2593
|
+
handleColumnReorder(draggedColName, col.name);
|
|
2594
|
+
}
|
|
2595
|
+
setDraggedColName(null);
|
|
2596
|
+
setDragOverColName(null);
|
|
2597
|
+
},
|
|
2598
|
+
onDragEnd: () => {
|
|
2599
|
+
setDraggedColName(null);
|
|
2600
|
+
setDragOverColName(null);
|
|
2601
|
+
},
|
|
2602
|
+
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"}`,
|
|
2603
|
+
children: [
|
|
2604
|
+
/* @__PURE__ */ jsx6(
|
|
2605
|
+
"div",
|
|
2606
|
+
{
|
|
2607
|
+
onMouseDown: (e) => {
|
|
2608
|
+
e.preventDefault();
|
|
2609
|
+
e.stopPropagation();
|
|
2610
|
+
setResizingCol({ name: col.name, startWidth: currentWidth, startX: e.clientX });
|
|
2611
|
+
},
|
|
2612
|
+
className: "absolute left-0 top-0 bottom-0 w-1.5 cursor-col-resize hover:bg-brand active:bg-brand-hover z-20",
|
|
2613
|
+
title: "\u05E9\u05E0\u05D4 \u05D2\u05D5\u05D3\u05DC \u05E2\u05DE\u05D5\u05D3\u05D4"
|
|
2614
|
+
}
|
|
2615
|
+
),
|
|
2616
|
+
/* @__PURE__ */ jsxs6("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: [
|
|
2617
|
+
/* @__PURE__ */ jsx6("span", { className: "truncate", children: col.name }),
|
|
2618
|
+
/* @__PURE__ */ jsx6(
|
|
2619
|
+
"svg",
|
|
2620
|
+
{
|
|
2621
|
+
className: "w-3.5 h-3.5 text-slate-400 opacity-40 group-hover:opacity-100 transition-opacity shrink-0 cursor-grab",
|
|
2622
|
+
fill: "none",
|
|
2623
|
+
viewBox: "0 0 24 24",
|
|
2624
|
+
stroke: "currentColor",
|
|
2625
|
+
children: /* @__PURE__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M8 9h.01M8 15h.01M16 9h.01M16 15h.01" })
|
|
2626
|
+
}
|
|
2627
|
+
)
|
|
2628
|
+
] })
|
|
2629
|
+
]
|
|
2630
|
+
},
|
|
2631
|
+
col.name
|
|
2632
|
+
);
|
|
2633
|
+
}),
|
|
2634
|
+
/* @__PURE__ */ jsx6("th", { className: "w-full min-w-[50px] border-b border-slate-200 pointer-events-none" })
|
|
2635
|
+
] }) }),
|
|
2636
|
+
/* @__PURE__ */ jsx6("tbody", { className: "bg-white", children: (isStateEmpty || filteredData.length === 0) && !isLoading ? /* @__PURE__ */ jsx6("tr", { children: /* @__PURE__ */ jsx6("td", { colSpan: filteredColumns.length + 2, className: "text-center py-12 text-slate-400", children: /* @__PURE__ */ jsxs6("div", { className: "flex flex-col items-center justify-center gap-2", children: [
|
|
2637
|
+
/* @__PURE__ */ jsx6("svg", { className: "w-8 h-8 text-slate-300", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx6("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" }) }),
|
|
2638
|
+
/* @__PURE__ */ jsx6("span", { children: "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05DC\u05D4\u05E6\u05D2\u05D4." })
|
|
2639
|
+
] }) }) }) : filteredData.map((row) => {
|
|
2640
|
+
const hasSubTableCols = filteredColumns.some((c) => {
|
|
1411
2641
|
var _a;
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
2642
|
+
return ((_a = c.type) == null ? void 0 : _a.toUpperCase()) === "SUB_TABLE";
|
|
2643
|
+
});
|
|
2644
|
+
const isExpanded = expandedRowIds.has(row.id);
|
|
2645
|
+
const subTableColumns = filteredColumns.filter((c) => {
|
|
2646
|
+
var _a;
|
|
2647
|
+
return ((_a = c.type) == null ? void 0 : _a.toUpperCase()) === "SUB_TABLE";
|
|
2648
|
+
});
|
|
2649
|
+
return /* @__PURE__ */ jsxs6(React6.Fragment, { children: [
|
|
2650
|
+
/* @__PURE__ */ jsxs6("tr", { className: "hover:bg-blue-50/30 transition-colors group", children: [
|
|
2651
|
+
/* @__PURE__ */ jsx6("td", { className: "border-b border-l border-slate-200 p-1.5 text-center bg-white group-hover:bg-transparent", children: /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-center gap-1", children: [
|
|
2652
|
+
hasSubTableCols && /* @__PURE__ */ jsx6(
|
|
2653
|
+
"button",
|
|
2654
|
+
{
|
|
2655
|
+
type: "button",
|
|
2656
|
+
onClick: () => setExpandedRowIds((prev) => {
|
|
2657
|
+
const next = new Set(prev);
|
|
2658
|
+
if (next.has(row.id)) next.delete(row.id);
|
|
2659
|
+
else next.add(row.id);
|
|
2660
|
+
return next;
|
|
2661
|
+
}),
|
|
2662
|
+
className: "text-slate-400 hover:text-blue-600 p-0.5 rounded transition-colors cursor-pointer",
|
|
2663
|
+
title: isExpanded ? "\u05E1\u05D2\u05D5\u05E8 \u05EA\u05EA-\u05D8\u05D1\u05DC\u05D4" : "\u05E4\u05EA\u05D7 \u05EA\u05EA-\u05D8\u05D1\u05DC\u05D4",
|
|
2664
|
+
children: /* @__PURE__ */ jsx6("svg", { className: `w-3.5 h-3.5 transition-transform duration-150 ${isExpanded ? "rotate-90" : ""}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M9 5l7 7-7 7" }) })
|
|
2665
|
+
}
|
|
2666
|
+
),
|
|
2667
|
+
/* @__PURE__ */ jsx6(
|
|
2668
|
+
"input",
|
|
2669
|
+
{
|
|
2670
|
+
type: "checkbox",
|
|
2671
|
+
checked: selectedIds.has(row.id),
|
|
2672
|
+
onChange: (e) => toggleSelectRow(row.id, e.target.checked),
|
|
2673
|
+
disabled: isLoading || isUpdatingActive,
|
|
2674
|
+
className: "w-4 h-4 rounded border-slate-300 text-brand"
|
|
2675
|
+
}
|
|
2676
|
+
)
|
|
2677
|
+
] }) }),
|
|
2678
|
+
filteredColumns.map((col) => {
|
|
2679
|
+
var _a;
|
|
2680
|
+
const colType = ((_a = col.type) == null ? void 0 : _a.toUpperCase()) || "DEFAULT";
|
|
2681
|
+
const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
|
|
2682
|
+
let value = (row == null ? void 0 : row.data) ? row.data[col.name] : void 0;
|
|
2683
|
+
if (value === void 0 && col.defaultValue !== void 0) {
|
|
2684
|
+
value = colType === "CURRENCY" || colType === "NUMBER" ? parseFloat(col.defaultValue) : col.defaultValue;
|
|
2685
|
+
if (colType === "CURRENCY" || colType === "NUMBER") {
|
|
2686
|
+
if (isNaN(value)) value = null;
|
|
2687
|
+
}
|
|
2688
|
+
}
|
|
2689
|
+
if (value === void 0) value = null;
|
|
2690
|
+
return /* @__PURE__ */ jsx6("td", { className: "border-b border-l border-slate-200 p-0 relative", children: /* @__PURE__ */ jsx6(
|
|
2691
|
+
InputComponent,
|
|
2692
|
+
{
|
|
2693
|
+
value,
|
|
2694
|
+
column: col,
|
|
2695
|
+
rowId: row.id,
|
|
2696
|
+
onChange: (v) => handleCellChange(row.id, col.name, v),
|
|
2697
|
+
context: {
|
|
2698
|
+
tableName: (schema == null ? void 0 : schema.name) || (schema == null ? void 0 : schema.tableName) || (schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.id) || "Table",
|
|
2699
|
+
tableId: (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id),
|
|
2700
|
+
onMarkForDeletion: (fileId) => setPendingDeletions((prev) => [...prev, fileId]),
|
|
2701
|
+
relationOptions,
|
|
2702
|
+
refetchRelation,
|
|
2703
|
+
executeAction,
|
|
2704
|
+
emitEvent,
|
|
2705
|
+
pageState,
|
|
2706
|
+
componentId,
|
|
2707
|
+
orgId,
|
|
2708
|
+
updateQuietly: handleQuietCellChange,
|
|
2709
|
+
triggerSaveSuccess,
|
|
2710
|
+
rowData: row.data
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
) }, col.name);
|
|
2714
|
+
}),
|
|
2715
|
+
/* @__PURE__ */ jsx6("td", { className: "border-b border-slate-200 bg-white pointer-events-none" })
|
|
2716
|
+
] }),
|
|
2717
|
+
isExpanded && /* @__PURE__ */ jsx6(
|
|
2718
|
+
ExpandedSubTables,
|
|
1424
2719
|
{
|
|
1425
|
-
value,
|
|
1426
|
-
column: col,
|
|
1427
2720
|
rowId: row.id,
|
|
1428
|
-
|
|
2721
|
+
rowData: row.data,
|
|
2722
|
+
subTableColumns,
|
|
2723
|
+
filteredColumnsLength: filteredColumns.length,
|
|
2724
|
+
handleCellChange,
|
|
1429
2725
|
context: {
|
|
1430
|
-
tableName: (schema == null ? void 0 : schema.name) || (schema == null ? void 0 : schema.tableName) || (schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.id) || "Table",
|
|
1431
|
-
onMarkForDeletion: (fileId) => setPendingDeletions((prev) => [...prev, fileId]),
|
|
1432
|
-
relationOptions,
|
|
1433
|
-
refetchRelation,
|
|
1434
2726
|
executeAction,
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
2727
|
+
orgId,
|
|
2728
|
+
parentTableId: (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id),
|
|
2729
|
+
tableId: (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id),
|
|
2730
|
+
rowData: row.data,
|
|
2731
|
+
updateQuietly: handleQuietCellChange,
|
|
2732
|
+
triggerSaveSuccess
|
|
1439
2733
|
}
|
|
1440
2734
|
}
|
|
1441
|
-
)
|
|
1442
|
-
})
|
|
1443
|
-
|
|
2735
|
+
)
|
|
2736
|
+
] }, row.id);
|
|
2737
|
+
}) }),
|
|
2738
|
+
showSummary && filteredData.length > 0 && /* @__PURE__ */ jsx6("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__ */ jsxs6("tr", { children: [
|
|
2739
|
+
/* @__PURE__ */ jsx6("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' }),
|
|
2740
|
+
filteredColumns.map((col) => {
|
|
2741
|
+
var _a;
|
|
2742
|
+
const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
|
|
2743
|
+
const isNumeric = typeUpper === "CURRENCY" || typeUpper === "NUMBER";
|
|
2744
|
+
const total = columnTotals[col.name];
|
|
2745
|
+
let displayVal = "";
|
|
2746
|
+
if (isNumeric && total !== void 0) {
|
|
2747
|
+
displayVal = new Intl.NumberFormat("en-US").format(total);
|
|
2748
|
+
if (typeUpper === "CURRENCY") {
|
|
2749
|
+
const symbol = getCurrencySymbol(col.currencySymbol);
|
|
2750
|
+
displayVal = symbol ? `${symbol} ${displayVal}` : displayVal;
|
|
2751
|
+
}
|
|
2752
|
+
}
|
|
2753
|
+
return /* @__PURE__ */ jsx6("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__ */ jsx6("div", { className: "flex items-center text-right justify-start", children: /* @__PURE__ */ jsx6("span", { className: "truncate", children: displayVal }) }) }, col.name);
|
|
2754
|
+
}),
|
|
2755
|
+
/* @__PURE__ */ jsx6("td", { className: "border-b border-slate-200 bg-slate-50 pointer-events-none" })
|
|
2756
|
+
] }) })
|
|
2757
|
+
] })
|
|
2758
|
+
] }),
|
|
2759
|
+
/* @__PURE__ */ jsxs6("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: [
|
|
2760
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
2761
|
+
/* @__PURE__ */ jsx6("span", { className: "font-medium text-slate-700", children: "\u05E9\u05D5\u05E8\u05D5\u05EA \u05DC\u05E2\u05DE\u05D5\u05D3:" }),
|
|
2762
|
+
/* @__PURE__ */ jsxs6(
|
|
2763
|
+
"select",
|
|
2764
|
+
{
|
|
2765
|
+
value: limit,
|
|
2766
|
+
onChange: (e) => handleLimitChange(Number(e.target.value)),
|
|
2767
|
+
disabled: isLoading || isUpdatingActive,
|
|
2768
|
+
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",
|
|
2769
|
+
children: [
|
|
2770
|
+
/* @__PURE__ */ jsx6("option", { value: 20, children: "20" }),
|
|
2771
|
+
/* @__PURE__ */ jsx6("option", { value: 50, children: "50" }),
|
|
2772
|
+
/* @__PURE__ */ jsx6("option", { value: 100, children: "100" })
|
|
2773
|
+
]
|
|
2774
|
+
}
|
|
2775
|
+
)
|
|
2776
|
+
] }),
|
|
2777
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-4", children: [
|
|
2778
|
+
/* @__PURE__ */ jsxs6("span", { className: "font-medium text-slate-600", children: [
|
|
2779
|
+
"\u05E2\u05DE\u05D5\u05D3 ",
|
|
2780
|
+
/* @__PURE__ */ jsx6("strong", { className: "text-slate-900", children: page }),
|
|
2781
|
+
" \u05DE\u05EA\u05D5\u05DA ",
|
|
2782
|
+
/* @__PURE__ */ jsx6("strong", { className: "text-slate-900", children: totalPages || 1 }),
|
|
2783
|
+
totalRecords > 0 && /* @__PURE__ */ jsxs6("span", { className: "text-slate-500 font-normal", children: [
|
|
2784
|
+
" (",
|
|
2785
|
+
totalRecords,
|
|
2786
|
+
' \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D1\u05E1\u05D4"\u05DB)'
|
|
2787
|
+
] })
|
|
2788
|
+
] }),
|
|
2789
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1.5", children: [
|
|
2790
|
+
/* @__PURE__ */ jsx6(
|
|
2791
|
+
"button",
|
|
2792
|
+
{
|
|
2793
|
+
onClick: handlePrevPage,
|
|
2794
|
+
disabled: page <= 1 || isLoading || isUpdatingActive,
|
|
2795
|
+
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",
|
|
2796
|
+
title: "\u05E2\u05DE\u05D5\u05D3 \u05E7\u05D5\u05D3\u05DD",
|
|
2797
|
+
children: "\u05D4\u05E7\u05D5\u05D3\u05DD"
|
|
2798
|
+
}
|
|
2799
|
+
),
|
|
2800
|
+
/* @__PURE__ */ jsx6(
|
|
2801
|
+
"button",
|
|
2802
|
+
{
|
|
2803
|
+
onClick: handleNextPage,
|
|
2804
|
+
disabled: page >= totalPages || isLoading || isUpdatingActive,
|
|
2805
|
+
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",
|
|
2806
|
+
title: "\u05E2\u05DE\u05D5\u05D3 \u05D4\u05D1\u05D0",
|
|
2807
|
+
children: "\u05D4\u05D1\u05D0"
|
|
2808
|
+
}
|
|
2809
|
+
)
|
|
2810
|
+
] })
|
|
1444
2811
|
] })
|
|
1445
2812
|
] })
|
|
1446
2813
|
]
|
|
1447
2814
|
}
|
|
1448
2815
|
);
|
|
1449
2816
|
}
|
|
2817
|
+
function ExpandedSubTables({
|
|
2818
|
+
rowId,
|
|
2819
|
+
rowData,
|
|
2820
|
+
subTableColumns,
|
|
2821
|
+
filteredColumnsLength,
|
|
2822
|
+
handleCellChange,
|
|
2823
|
+
context
|
|
2824
|
+
}) {
|
|
2825
|
+
var _a;
|
|
2826
|
+
const [activeTab, setActiveTab] = useState5((_a = subTableColumns[0]) == null ? void 0 : _a.name);
|
|
2827
|
+
if (subTableColumns.length === 0) return null;
|
|
2828
|
+
if (subTableColumns.length === 1) {
|
|
2829
|
+
const stCol = subTableColumns[0];
|
|
2830
|
+
return /* @__PURE__ */ jsx6("tr", { children: /* @__PURE__ */ jsx6("td", { colSpan: filteredColumnsLength + 2, className: "p-0 border-b border-slate-200 bg-slate-50/50", children: /* @__PURE__ */ jsx6(
|
|
2831
|
+
SubTableViewer,
|
|
2832
|
+
{
|
|
2833
|
+
rowId,
|
|
2834
|
+
column: stCol,
|
|
2835
|
+
value: (rowData == null ? void 0 : rowData[stCol.name]) || [],
|
|
2836
|
+
onChange: (newVal) => handleCellChange(rowId, stCol.name, newVal),
|
|
2837
|
+
context
|
|
2838
|
+
}
|
|
2839
|
+
) }) });
|
|
2840
|
+
}
|
|
2841
|
+
const activeCol = subTableColumns.find((c) => c.name === activeTab) || subTableColumns[0];
|
|
2842
|
+
return /* @__PURE__ */ jsx6("tr", { children: /* @__PURE__ */ jsxs6("td", { colSpan: filteredColumnsLength + 2, className: "p-0 border-b border-slate-200 bg-slate-50/50 overflow-hidden", children: [
|
|
2843
|
+
/* @__PURE__ */ jsx6("div", { className: "flex border-b border-slate-200 bg-slate-100/50 px-2 pt-2 gap-1 overflow-hidden", children: subTableColumns.map((col) => /* @__PURE__ */ jsx6(
|
|
2844
|
+
"button",
|
|
2845
|
+
{
|
|
2846
|
+
type: "button",
|
|
2847
|
+
onClick: () => setActiveTab(col.name),
|
|
2848
|
+
className: `px-4 py-2 text-sm font-semibold rounded-t-lg transition-colors whitespace-nowrap cursor-pointer relative top-[1px] ${activeTab === col.name ? "bg-white border border-slate-200 border-b-transparent text-brand" : "bg-transparent border border-transparent text-slate-500 hover:text-slate-700 hover:bg-slate-200/50"}`,
|
|
2849
|
+
children: col.name
|
|
2850
|
+
},
|
|
2851
|
+
col.name
|
|
2852
|
+
)) }),
|
|
2853
|
+
/* @__PURE__ */ jsx6("div", { className: "bg-white", children: /* @__PURE__ */ jsx6(
|
|
2854
|
+
SubTableViewer,
|
|
2855
|
+
{
|
|
2856
|
+
rowId,
|
|
2857
|
+
column: activeCol,
|
|
2858
|
+
value: (rowData == null ? void 0 : rowData[activeCol.name]) || [],
|
|
2859
|
+
onChange: (newVal) => handleCellChange(rowId, activeCol.name, newVal),
|
|
2860
|
+
context
|
|
2861
|
+
},
|
|
2862
|
+
activeCol.name
|
|
2863
|
+
) })
|
|
2864
|
+
] }) });
|
|
2865
|
+
}
|
|
1450
2866
|
|
|
1451
2867
|
// src/components/TableBlock/TableBlock.tsx
|
|
1452
|
-
import { jsx as
|
|
2868
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
1453
2869
|
function TableBlock(props) {
|
|
1454
|
-
return /* @__PURE__ */
|
|
2870
|
+
return /* @__PURE__ */ jsx7(TableBlockClient, __spreadValues({}, props));
|
|
1455
2871
|
}
|
|
1456
2872
|
|
|
1457
2873
|
// src/registry.ts
|