@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/index.js CHANGED
@@ -77,7 +77,7 @@ function cn(...inputs) {
77
77
  }
78
78
 
79
79
  // src/components/TableBlock/TableBlockClient.tsx
80
- var import_react6 = require("react");
80
+ var import_react7 = __toESM(require("react"));
81
81
 
82
82
  // src/hooks/useToast.ts
83
83
  var import_react2 = require("react");
@@ -280,12 +280,36 @@ function useToast() {
280
280
  var import_react5 = __toESM(require("react"));
281
281
 
282
282
  // src/components/TableBlock/fields/DrivePickerCell.tsx
283
- var import_react3 = require("react");
283
+ var import_react3 = __toESM(require("react"));
284
284
  var import_lucide_react2 = require("lucide-react");
285
285
  var import_jsx_runtime2 = require("react/jsx-runtime");
286
- function DrivePickerCell({ value, onChange, tableName, onMarkForDeletion, context }) {
286
+ function DrivePickerCell({ value, onChange, tableName, column, rowId, onMarkForDeletion, context }) {
287
287
  const [isOpening, setIsOpening] = (0, import_react3.useState)(false);
288
288
  const { showError } = useToast();
289
+ const cellContextId = import_react3.default.useMemo(() => {
290
+ const colName = (column == null ? void 0 : column.name) || "col";
291
+ const rId = rowId || "row";
292
+ return `${rId}-${colName}`;
293
+ }, [rowId, column == null ? void 0 : column.name]);
294
+ const fileList = import_react3.default.useMemo(() => {
295
+ if (!value) return [];
296
+ if (Array.isArray(value)) return value;
297
+ if (typeof value === "object" && (value.fileId || value.fileUrl || value.url)) {
298
+ return [value];
299
+ }
300
+ return [];
301
+ }, [value]);
302
+ (0, import_react3.useEffect)(() => {
303
+ const handleMessage = (event) => {
304
+ var _a, _b, _c;
305
+ 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) {
306
+ const incoming = Array.isArray(event.data.payload) ? event.data.payload : [event.data.payload];
307
+ onChange([...fileList, ...incoming]);
308
+ }
309
+ };
310
+ window.addEventListener("message", handleMessage);
311
+ return () => window.removeEventListener("message", handleMessage);
312
+ }, [fileList, onChange, cellContextId]);
289
313
  const openUploadPopup = async () => {
290
314
  if (isOpening) return;
291
315
  setIsOpening(true);
@@ -314,34 +338,35 @@ function DrivePickerCell({ value, onChange, tableName, onMarkForDeletion, contex
314
338
  } catch (e) {
315
339
  }
316
340
  }
317
- const actionResult = await context.executeAction("UPLOAD_DRIVE_FILE", { tableName });
341
+ const actionResult = await context.executeAction("UPLOAD_DRIVE_FILE", { tableName, cellContextId });
318
342
  const folderId = actionResult == null ? void 0 : actionResult.folderId;
319
- const pickerUrl = (actionResult == null ? void 0 : actionResult.pickerUrl) || (folderId ? `/embed/picker?folderId=${encodeURIComponent(folderId)}` : `/embed/picker`);
343
+ let pickerUrl = (actionResult == null ? void 0 : actionResult.pickerUrl) || (folderId ? `/embed/picker?folderId=${encodeURIComponent(folderId)}` : `/embed/picker`);
344
+ if (!pickerUrl.includes("cellContextId=")) {
345
+ const separator = pickerUrl.includes("?") ? "&" : "?";
346
+ pickerUrl = `${pickerUrl}${separator}cellContextId=${encodeURIComponent(cellContextId)}`;
347
+ }
320
348
  if (popup) {
321
349
  popup.location.href = pickerUrl;
322
350
  }
323
- const newFile = await new Promise((resolve) => {
351
+ await new Promise((resolve) => {
324
352
  let timer = null;
325
- const handleMessage = (event) => {
353
+ const handlePopupMessage = (event) => {
326
354
  var _a, _b;
327
- if (((_a = event.data) == null ? void 0 : _a.type) === "DRIVE_UPLOAD_SUCCESS" && ((_b = event.data) == null ? void 0 : _b.payload)) {
328
- window.removeEventListener("message", handleMessage);
355
+ if (((_a = event.data) == null ? void 0 : _a.type) === "DRIVE_UPLOAD_SUCCESS" && ((_b = event.data) == null ? void 0 : _b.cellContextId) === cellContextId) {
356
+ window.removeEventListener("message", handlePopupMessage);
329
357
  if (timer) clearInterval(timer);
330
- resolve(event.data.payload);
358
+ resolve();
331
359
  }
332
360
  };
333
361
  timer = setInterval(() => {
334
362
  if (!popup || popup.closed) {
335
363
  if (timer) clearInterval(timer);
336
- window.removeEventListener("message", handleMessage);
337
- resolve(null);
364
+ window.removeEventListener("message", handlePopupMessage);
365
+ resolve();
338
366
  }
339
367
  }, 800);
340
- window.addEventListener("message", handleMessage);
368
+ window.addEventListener("message", handlePopupMessage);
341
369
  });
342
- if (newFile) {
343
- onChange(newFile);
344
- }
345
370
  }
346
371
  } catch (error) {
347
372
  console.error("[DrivePickerCell] Error uploading file:", error);
@@ -351,40 +376,15 @@ function DrivePickerCell({ value, onChange, tableName, onMarkForDeletion, contex
351
376
  setIsOpening(false);
352
377
  }
353
378
  };
354
- if (value == null ? void 0 : value.fileUrl) {
355
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center w-full h-8 px-2 gap-1", children: [
356
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
357
- "a",
358
- {
359
- href: value.fileUrl,
360
- target: "_blank",
361
- rel: "noopener noreferrer",
362
- 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",
363
- title: value.fileName || "Open file",
364
- children: [
365
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.FileText, { className: "w-3.5 h-3.5 shrink-0" }),
366
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "truncate", children: value.fileName || "Unnamed file" })
367
- ]
368
- }
369
- ),
370
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
371
- "button",
372
- {
373
- type: "button",
374
- onClick: () => {
375
- if ((value == null ? void 0 : value.fileId) && onMarkForDeletion) {
376
- onMarkForDeletion(value.fileId);
377
- }
378
- onChange(null);
379
- },
380
- className: "shrink-0 p-0.5 rounded hover:bg-rose-100 text-slate-400 hover:text-rose-500 transition-colors",
381
- title: "Remove file",
382
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.X, { className: "w-3.5 h-3.5" })
383
- }
384
- )
385
- ] });
386
- }
387
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex items-center w-full h-8 px-2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
379
+ const handleRemoveFile = (indexToRemove) => {
380
+ const fileToRemove = fileList[indexToRemove];
381
+ if ((fileToRemove == null ? void 0 : fileToRemove.fileId) && onMarkForDeletion) {
382
+ onMarkForDeletion(fileToRemove.fileId);
383
+ }
384
+ const updated = fileList.filter((_, idx) => idx !== indexToRemove);
385
+ onChange(updated);
386
+ };
387
+ const renderUploadButton = () => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex items-center w-full h-8 px-2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
388
388
  "button",
389
389
  {
390
390
  type: "button",
@@ -397,6 +397,38 @@ function DrivePickerCell({ value, onChange, tableName, onMarkForDeletion, contex
397
397
  ]
398
398
  }
399
399
  ) });
400
+ if (fileList.length > 0) {
401
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col w-full py-1 gap-1", children: [
402
+ fileList.map((file, idx) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center w-full h-8 px-2 gap-1", children: [
403
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
404
+ "a",
405
+ {
406
+ href: file.fileUrl || file.url,
407
+ target: "_blank",
408
+ rel: "noopener noreferrer",
409
+ 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",
410
+ title: file.fileName || "Open file",
411
+ children: [
412
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.FileText, { className: "w-3.5 h-3.5 shrink-0" }),
413
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "truncate", children: file.fileName || "Unnamed file" })
414
+ ]
415
+ }
416
+ ),
417
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
418
+ "button",
419
+ {
420
+ type: "button",
421
+ onClick: () => handleRemoveFile(idx),
422
+ className: "shrink-0 p-0.5 rounded hover:bg-rose-100 text-slate-400 hover:text-rose-500 transition-colors",
423
+ title: "Remove file",
424
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.X, { className: "w-3.5 h-3.5" })
425
+ }
426
+ )
427
+ ] }, file.fileId || idx)),
428
+ renderUploadButton()
429
+ ] });
430
+ }
431
+ return renderUploadButton();
400
432
  }
401
433
 
402
434
  // src/components/TableBlock/fields/DatePickerCell.tsx
@@ -742,15 +774,19 @@ var FORM_INPUTS = {
742
774
  DATE: ({ value, onChange, column }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DatePickerCell, { value, onChange, column }),
743
775
  CURRENCY: ({ value, column, onChange }) => {
744
776
  const symbol = getCurrencySymbol(column.currencySymbol);
777
+ const [isFocused, setIsFocused] = import_react5.default.useState(false);
778
+ 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 : "";
745
779
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "relative w-full h-full", children: [
746
780
  symbol && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "absolute left-2 top-1/2 -translate-y-1/2 text-slate-400 pointer-events-none text-sm", children: symbol }),
747
781
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
748
782
  "input",
749
783
  {
750
- type: "number",
784
+ type: isFocused ? "number" : "text",
751
785
  step: "any",
752
786
  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`,
753
- value: value !== void 0 && value !== null ? value : "",
787
+ value: displayValue,
788
+ onFocus: () => setIsFocused(true),
789
+ onBlur: () => setIsFocused(false),
754
790
  onChange: (e) => {
755
791
  const val = e.target.value;
756
792
  onChange(val === "" ? "" : Number(val));
@@ -827,11 +863,13 @@ var FORM_INPUTS = {
827
863
  className: "w-4 h-4 rounded border-slate-300 text-brand"
828
864
  }
829
865
  ) }),
830
- GOOGLE_DRIVE_FILE: ({ value, onChange, context }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
866
+ GOOGLE_DRIVE_FILE: ({ value, onChange, column, rowId, context }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
831
867
  DrivePickerCell,
832
868
  {
833
- value: value || null,
869
+ value: value || [],
834
870
  onChange,
871
+ column,
872
+ rowId,
835
873
  tableName: context == null ? void 0 : context.tableName,
836
874
  onMarkForDeletion: context == null ? void 0 : context.onMarkForDeletion,
837
875
  context
@@ -889,6 +927,228 @@ var FORM_INPUTS = {
889
927
  }
890
928
  }
891
929
  ),
930
+ PHONE: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
931
+ "input",
932
+ {
933
+ type: "tel",
934
+ className: "w-full h-8 px-2 bg-transparent focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 text-sm",
935
+ value: value !== void 0 && value !== null ? String(value) : "",
936
+ onChange: (e) => onChange(e.target.value),
937
+ dir: "ltr"
938
+ }
939
+ ),
940
+ GOOGLE_CONTACT: ({ value, column, rowId, onChange, context }) => {
941
+ const [isSyncing, setIsSyncing] = import_react5.default.useState(false);
942
+ const { addToast } = useToast();
943
+ const googleClientIdRef = import_react5.default.useRef(null);
944
+ const ensureGisScript = import_react5.default.useCallback(() => {
945
+ return new Promise((resolve, reject) => {
946
+ var _a, _b, _c;
947
+ if ((_c = (_b = (_a = window.google) == null ? void 0 : _a.accounts) == null ? void 0 : _b.oauth2) == null ? void 0 : _c.initTokenClient) {
948
+ resolve();
949
+ return;
950
+ }
951
+ if (document.querySelector('script[src*="accounts.google.com/gsi/client"]')) {
952
+ const waitForLoad = setInterval(() => {
953
+ var _a2, _b2, _c2;
954
+ if ((_c2 = (_b2 = (_a2 = window.google) == null ? void 0 : _a2.accounts) == null ? void 0 : _b2.oauth2) == null ? void 0 : _c2.initTokenClient) {
955
+ clearInterval(waitForLoad);
956
+ resolve();
957
+ }
958
+ }, 100);
959
+ setTimeout(() => {
960
+ clearInterval(waitForLoad);
961
+ reject(new Error("GIS script load timeout"));
962
+ }, 1e4);
963
+ return;
964
+ }
965
+ const script = document.createElement("script");
966
+ script.src = "https://accounts.google.com/gsi/client";
967
+ script.async = true;
968
+ script.onload = () => resolve();
969
+ script.onerror = () => reject(new Error("Failed to load Google Identity Services"));
970
+ document.head.appendChild(script);
971
+ });
972
+ }, []);
973
+ const requestGisToken = import_react5.default.useCallback(async (hint) => {
974
+ await ensureGisScript();
975
+ if (!googleClientIdRef.current && (context == null ? void 0 : context.executeAction)) {
976
+ try {
977
+ const config = await context.executeAction("GET_GOOGLE_CONFIG", {});
978
+ googleClientIdRef.current = (config == null ? void 0 : config.clientId) || "";
979
+ } catch (e) {
980
+ throw new Error("Failed to fetch Google configuration");
981
+ }
982
+ }
983
+ const clientId = googleClientIdRef.current;
984
+ if (!clientId) {
985
+ throw new Error("Google Client ID is not configured");
986
+ }
987
+ const accessToken = await new Promise((resolve, reject) => {
988
+ const tokenClient = window.google.accounts.oauth2.initTokenClient({
989
+ client_id: clientId,
990
+ scope: "https://www.googleapis.com/auth/contacts https://www.googleapis.com/auth/userinfo.email",
991
+ prompt: hint ? "" : "select_account",
992
+ hint: hint || void 0,
993
+ callback: (tokenResponse) => {
994
+ if (tokenResponse == null ? void 0 : tokenResponse.access_token) {
995
+ resolve(tokenResponse.access_token);
996
+ } else {
997
+ reject(new Error("Google authorization was cancelled or failed"));
998
+ }
999
+ },
1000
+ error_callback: (err) => {
1001
+ reject(new Error((err == null ? void 0 : err.message) || "Google authorization error"));
1002
+ }
1003
+ });
1004
+ tokenClient.requestAccessToken({ hint: hint || void 0 });
1005
+ });
1006
+ let email = "";
1007
+ try {
1008
+ const res = await fetch("https://www.googleapis.com/oauth2/v3/userinfo", {
1009
+ headers: { Authorization: `Bearer ${accessToken}` }
1010
+ });
1011
+ if (res.ok) {
1012
+ const info = await res.json();
1013
+ email = info.email || "";
1014
+ }
1015
+ } catch (e) {
1016
+ }
1017
+ return { accessToken, email };
1018
+ }, [ensureGisScript, context]);
1019
+ const handleSync = async () => {
1020
+ var _a, _b, _c;
1021
+ if (!(context == null ? void 0 : context.executeAction)) return;
1022
+ setIsSyncing(true);
1023
+ try {
1024
+ const mapping = column.contactMapping || {};
1025
+ const rowData = context.rowData || {};
1026
+ let hasPhone = false;
1027
+ if (mapping.phoneCol && rowData[mapping.phoneCol]) hasPhone = true;
1028
+ let hasName = false;
1029
+ if (mapping.nameParts && Array.isArray(mapping.nameParts)) {
1030
+ for (const part of mapping.nameParts) {
1031
+ if (part.type === "LOCAL" && rowData[part.columnId]) hasName = true;
1032
+ 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;
1033
+ }
1034
+ }
1035
+ if (!hasPhone) {
1036
+ 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" });
1037
+ setIsSyncing(false);
1038
+ return;
1039
+ }
1040
+ if (!hasName) {
1041
+ 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" });
1042
+ setIsSyncing(false);
1043
+ return;
1044
+ }
1045
+ let accessToken;
1046
+ let userEmail = "";
1047
+ try {
1048
+ const gisResult = await requestGisToken();
1049
+ accessToken = gisResult.accessToken;
1050
+ userEmail = gisResult.email;
1051
+ } catch (gisError) {
1052
+ addToast({ type: "warning", message: gisError.message || "\u05D4\u05D4\u05E8\u05E9\u05D0\u05D4 \u05DC\u05D2\u05D5\u05D2\u05DC \u05E0\u05DB\u05E9\u05DC\u05D4" });
1053
+ setIsSyncing(false);
1054
+ return;
1055
+ }
1056
+ const payload = {
1057
+ nameParts: mapping.nameParts || [],
1058
+ phoneCol: mapping.phoneCol,
1059
+ emailCol: mapping.emailCol,
1060
+ localRowData: rowData,
1061
+ parentRecord: context.parentRecord,
1062
+ accessToken,
1063
+ userEmail
1064
+ };
1065
+ const res = await context.executeAction("SYNC_GOOGLE_CONTACT", payload);
1066
+ if (res && res.synced) {
1067
+ if (context.updateQuietly) {
1068
+ context.updateQuietly(rowId, column.name, res);
1069
+ } else {
1070
+ onChange(res);
1071
+ }
1072
+ if (context.tableId && !rowId.startsWith("temp_")) {
1073
+ await context.executeAction("UPDATE_RECORD", {
1074
+ tableId: context.tableId,
1075
+ recordId: rowId,
1076
+ data: { [column.name]: res }
1077
+ });
1078
+ }
1079
+ }
1080
+ } catch (error) {
1081
+ console.error("Failed to sync contact:", error);
1082
+ addToast({ type: "warning", message: "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E1\u05E0\u05DB\u05E8\u05D5\u05DF \u05D0\u05D9\u05E9 \u05E7\u05E9\u05E8: " + error.message });
1083
+ } finally {
1084
+ setIsSyncing(false);
1085
+ }
1086
+ };
1087
+ const handleUnlink = async () => {
1088
+ let accessToken;
1089
+ try {
1090
+ let emailHint = value == null ? void 0 : value.userEmail;
1091
+ if (!emailHint && (value == null ? void 0 : value.url)) {
1092
+ try {
1093
+ const parsed = new URL(value.url);
1094
+ emailHint = parsed.searchParams.get("authuser") || void 0;
1095
+ } catch (e) {
1096
+ }
1097
+ }
1098
+ const auth = await requestGisToken(emailHint);
1099
+ accessToken = auth.accessToken;
1100
+ } catch (err) {
1101
+ console.warn("[handleUnlink] Could not obtain token via GIS, falling back to server default token:", err);
1102
+ }
1103
+ if ((value == null ? void 0 : value.resourceName) && (context == null ? void 0 : context.executeAction)) {
1104
+ await context.executeAction("DELETE_GOOGLE_CONTACT", {
1105
+ resourceName: value.resourceName,
1106
+ accessToken
1107
+ });
1108
+ }
1109
+ if (context == null ? void 0 : context.updateQuietly) {
1110
+ context.updateQuietly(rowId, column.name, null);
1111
+ } else {
1112
+ onChange(null);
1113
+ }
1114
+ if ((context == null ? void 0 : context.tableId) && (context == null ? void 0 : context.executeAction) && !rowId.startsWith("temp_")) {
1115
+ await context.executeAction("UPDATE_RECORD", {
1116
+ tableId: context.tableId,
1117
+ recordId: rowId,
1118
+ data: { [column.name]: null }
1119
+ });
1120
+ }
1121
+ };
1122
+ if (value && value.synced && value.url) {
1123
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-2 h-8 px-2 group", children: [
1124
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("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" }),
1125
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1126
+ "button",
1127
+ {
1128
+ onClick: handleUnlink,
1129
+ className: "text-slate-400 hover:text-rose-500 opacity-0 group-hover:opacity-100 transition-opacity p-1",
1130
+ title: "\u05D1\u05D8\u05DC \u05E1\u05E0\u05DB\u05E8\u05D5\u05DF",
1131
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M6 18L18 6M6 6l12 12" }) })
1132
+ }
1133
+ )
1134
+ ] });
1135
+ }
1136
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex items-center h-8 px-2", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1137
+ "button",
1138
+ {
1139
+ onClick: handleSync,
1140
+ disabled: isSyncing,
1141
+ 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",
1142
+ children: [
1143
+ isSyncing ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { className: "w-3.5 h-3.5 animate-spin", viewBox: "0 0 24 24", fill: "none", children: [
1144
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
1145
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("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" })
1146
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 4v16m8-8H4" }) }),
1147
+ "\u05E1\u05E0\u05DB\u05E8\u05DF \u05DC\u05D2\u05D5\u05D2\u05DC"
1148
+ ]
1149
+ }
1150
+ ) });
1151
+ },
892
1152
  DEFAULT: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
893
1153
  "input",
894
1154
  {
@@ -897,11 +1157,459 @@ var FORM_INPUTS = {
897
1157
  value: value !== void 0 && value !== null ? String(value) : "",
898
1158
  onChange: (e) => onChange(e.target.value)
899
1159
  }
900
- )
1160
+ ),
1161
+ SUB_TABLE: ({ value, column }) => {
1162
+ if (!Array.isArray(value)) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "px-2 py-1 flex items-center h-full text-slate-300 text-xs italic", children: "\u05E8\u05D9\u05E7" });
1163
+ const selected = value.filter((e) => e == null ? void 0 : e.isSelected);
1164
+ if (selected.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "px-2 py-1 flex items-center h-full text-slate-300 text-xs italic", children: "\u05E8\u05D9\u05E7" });
1165
+ const displayFields = column.subTableDisplayFields || [];
1166
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "px-1.5 py-1 flex flex-wrap items-center gap-1 h-full", children: selected.map((entry, idx) => {
1167
+ var _a;
1168
+ let label = "";
1169
+ if (entry._resolvedData && displayFields.length > 0) {
1170
+ label = displayFields.map((f) => String(entry._resolvedData[f] || "")).filter(Boolean).join(" ");
1171
+ }
1172
+ if (!label) label = ((_a = entry.recordId) == null ? void 0 : _a.slice(-6)) || "...";
1173
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1174
+ "span",
1175
+ {
1176
+ 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",
1177
+ title: label,
1178
+ children: label
1179
+ },
1180
+ entry.recordId || idx
1181
+ );
1182
+ }) });
1183
+ }
901
1184
  };
902
1185
 
903
- // src/components/TableBlock/TableBlockClient.tsx
1186
+ // src/components/TableBlock/fields/SubTableViewer.tsx
1187
+ var import_react6 = require("react");
904
1188
  var import_jsx_runtime5 = require("react/jsx-runtime");
1189
+ function SubTableViewer({ rowId, column, value, onChange, context }) {
1190
+ var _a;
1191
+ const { addToast } = useToast();
1192
+ const entries = Array.isArray(value) ? value : [];
1193
+ const [linkedRecords, setLinkedRecords] = (0, import_react6.useState)([]);
1194
+ const [targetSchema, setTargetSchema] = (0, import_react6.useState)(null);
1195
+ const [isLoading, setIsLoading] = (0, import_react6.useState)(true);
1196
+ const [isSearchOpen, setIsSearchOpen] = (0, import_react6.useState)(false);
1197
+ const [searchQuery, setSearchQuery] = (0, import_react6.useState)("");
1198
+ const [searchResults, setSearchResults] = (0, import_react6.useState)([]);
1199
+ const [isSearching, setIsSearching] = (0, import_react6.useState)(false);
1200
+ const [isCreating, setIsCreating] = (0, import_react6.useState)(false);
1201
+ const [newRecordData, setNewRecordData] = (0, import_react6.useState)({});
1202
+ const searchRef = (0, import_react6.useRef)(null);
1203
+ const searchTimerRef = (0, import_react6.useRef)(null);
1204
+ const executeAction = context == null ? void 0 : context.executeAction;
1205
+ const referencedTableId = column.referencedTableId;
1206
+ const fetchedIdsRef = (0, import_react6.useRef)(/* @__PURE__ */ new Set());
1207
+ (0, import_react6.useEffect)(() => {
1208
+ if (!referencedTableId || !executeAction) {
1209
+ setIsLoading(false);
1210
+ return;
1211
+ }
1212
+ const recordIdsToFetch = entries.map((e) => e.recordId).filter((id) => !fetchedIdsRef.current.has(id));
1213
+ if (recordIdsToFetch.length === 0 && targetSchema) return;
1214
+ if (recordIdsToFetch.length > 0) {
1215
+ recordIdsToFetch.forEach((id) => fetchedIdsRef.current.add(id));
1216
+ }
1217
+ setIsLoading(true);
1218
+ executeAction("FETCH_SUB_TABLE_RECORDS", { referencedTableId, recordIds: recordIdsToFetch }).then((res) => {
1219
+ const payload = (res == null ? void 0 : res.data) || res;
1220
+ if (payload == null ? void 0 : payload.records) {
1221
+ setLinkedRecords((prev) => {
1222
+ const map = new Map(prev.map((r) => [r.id, r]));
1223
+ payload.records.forEach((r) => map.set(r.id, r));
1224
+ return Array.from(map.values());
1225
+ });
1226
+ }
1227
+ if (payload == null ? void 0 : payload.schema) {
1228
+ setTargetSchema(payload.schema);
1229
+ }
1230
+ }).catch(() => {
1231
+ recordIdsToFetch.forEach((id) => fetchedIdsRef.current.delete(id));
1232
+ }).finally(() => setIsLoading(false));
1233
+ }, [referencedTableId, executeAction, entries, targetSchema]);
1234
+ (0, import_react6.useEffect)(() => {
1235
+ const handleClick = (e) => {
1236
+ if (searchRef.current && !searchRef.current.contains(e.target)) {
1237
+ setIsSearchOpen(false);
1238
+ }
1239
+ };
1240
+ if (isSearchOpen) document.addEventListener("mousedown", handleClick);
1241
+ return () => document.removeEventListener("mousedown", handleClick);
1242
+ }, [isSearchOpen]);
1243
+ const handleSearch = (0, import_react6.useCallback)((query) => {
1244
+ setSearchQuery(query);
1245
+ if (searchTimerRef.current) clearTimeout(searchTimerRef.current);
1246
+ if (!query.trim()) {
1247
+ setSearchResults([]);
1248
+ return;
1249
+ }
1250
+ searchTimerRef.current = setTimeout(async () => {
1251
+ if (!executeAction || !referencedTableId) return;
1252
+ setIsSearching(true);
1253
+ try {
1254
+ const excludeIds = entries.map((e) => e.recordId);
1255
+ const res = await executeAction("SEARCH_SUB_TABLE_RECORDS", {
1256
+ referencedTableId,
1257
+ query: query.trim(),
1258
+ excludeIds,
1259
+ limit: 15
1260
+ });
1261
+ setSearchResults(Array.isArray(res) ? res : []);
1262
+ } catch (e) {
1263
+ setSearchResults([]);
1264
+ } finally {
1265
+ setIsSearching(false);
1266
+ }
1267
+ }, 300);
1268
+ }, [executeAction, referencedTableId, entries]);
1269
+ const targetColumns = ((targetSchema == null ? void 0 : targetSchema.columns) || []).filter(
1270
+ (c) => {
1271
+ if (c.name === "_id" || c.type === "SUB_TABLE") return false;
1272
+ return true;
1273
+ }
1274
+ );
1275
+ const [relationOptions, setRelationOptions] = (0, import_react6.useState)({});
1276
+ (0, import_react6.useEffect)(() => {
1277
+ if (!executeAction || targetColumns.length === 0) return;
1278
+ const relationCols = targetColumns.filter((c) => {
1279
+ var _a2;
1280
+ return ((_a2 = c.type) == null ? void 0 : _a2.toUpperCase()) === "RELATION" && c.referencedTableId;
1281
+ });
1282
+ relationCols.forEach(async (col) => {
1283
+ try {
1284
+ const options = await executeAction("FETCH_RELATION", {
1285
+ referencedTableId: col.referencedTableId,
1286
+ displayField: col.displayField
1287
+ });
1288
+ if (options && Array.isArray(options)) {
1289
+ setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [col.name]: options }));
1290
+ }
1291
+ } catch (err) {
1292
+ console.warn(`[SubTableViewer] Could not fetch relation options for column ${col.name}:`, err);
1293
+ }
1294
+ });
1295
+ }, [executeAction, targetColumns]);
1296
+ const refetchRelation = (0, import_react6.useCallback)(async (colName) => {
1297
+ var _a2;
1298
+ const col = targetColumns.find((c) => c.name === colName);
1299
+ if (!col || ((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) !== "RELATION" || !col.referencedTableId || !executeAction) return;
1300
+ try {
1301
+ const options = await executeAction("FETCH_RELATION", { referencedTableId: col.referencedTableId, displayField: col.displayField });
1302
+ if (options && Array.isArray(options)) {
1303
+ setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [col.name]: options }));
1304
+ }
1305
+ } catch (err) {
1306
+ console.warn(`[SubTableViewer] Could not refetch relation options for column ${col.name}:`, err);
1307
+ }
1308
+ }, [targetColumns, executeAction]);
1309
+ const updateParentLinkage = async (updated) => {
1310
+ const isNewRow = rowId.startsWith("temp_");
1311
+ if (context == null ? void 0 : context.updateQuietly) {
1312
+ context.updateQuietly(rowId, column.name, updated);
1313
+ } else {
1314
+ onChange(updated);
1315
+ }
1316
+ if (executeAction && (context == null ? void 0 : context.parentTableId) && !isNewRow) {
1317
+ try {
1318
+ const payloadToSave = updated.map(({ recordId, isSelected }) => ({ recordId, isSelected }));
1319
+ await executeAction("UPDATE_RECORD", {
1320
+ tableId: context.parentTableId,
1321
+ recordId: rowId,
1322
+ data: { [column.name]: payloadToSave }
1323
+ });
1324
+ if (context == null ? void 0 : context.triggerSaveSuccess) {
1325
+ context.triggerSaveSuccess();
1326
+ }
1327
+ } catch (err) {
1328
+ console.error("Failed to auto-save parent linkage", err);
1329
+ }
1330
+ }
1331
+ };
1332
+ const handleLinkRecord = (record) => {
1333
+ fetchedIdsRef.current.add(record.id);
1334
+ const newEntry = { recordId: record.id, isSelected: true, _resolvedData: record.data };
1335
+ const updated = [...entries, newEntry];
1336
+ updateParentLinkage(updated);
1337
+ setLinkedRecords((prev) => {
1338
+ const exists = prev.find((r) => r.id === record.id);
1339
+ if (exists) return prev;
1340
+ return [...prev, record];
1341
+ });
1342
+ setSearchQuery("");
1343
+ setSearchResults([]);
1344
+ setIsSearchOpen(false);
1345
+ };
1346
+ const handleUnlinkRecord = (recordId) => {
1347
+ const updated = entries.filter((e) => e.recordId !== recordId);
1348
+ updateParentLinkage(updated);
1349
+ setLinkedRecords((prev) => prev.filter((r) => r.id !== recordId));
1350
+ };
1351
+ const handleToggleSelected = (recordId) => {
1352
+ const record = linkedRecords.find((r) => r.id === recordId);
1353
+ const updated = entries.map(
1354
+ (e) => e.recordId === recordId ? __spreadProps(__spreadValues({}, e), { isSelected: !e.isSelected, _resolvedData: (record == null ? void 0 : record.data) || e._resolvedData }) : e
1355
+ );
1356
+ updateParentLinkage(updated);
1357
+ };
1358
+ const handleRecordCellChange = async (recordId, colName, value2) => {
1359
+ const updatedRecords = linkedRecords.map(
1360
+ (r) => r.id === recordId ? __spreadProps(__spreadValues({}, r), { data: __spreadProps(__spreadValues({}, r.data), { [colName]: value2 }) }) : r
1361
+ );
1362
+ setLinkedRecords(updatedRecords);
1363
+ const targetRecord = updatedRecords.find((r) => r.id === recordId);
1364
+ const updatedEntries = entries.map(
1365
+ (e) => e.recordId === recordId ? __spreadProps(__spreadValues({}, e), { _resolvedData: targetRecord == null ? void 0 : targetRecord.data }) : e
1366
+ );
1367
+ if (context == null ? void 0 : context.updateQuietly) {
1368
+ context.updateQuietly(rowId, column.name, updatedEntries);
1369
+ } else {
1370
+ onChange(updatedEntries);
1371
+ }
1372
+ if (executeAction && referencedTableId && !recordId.startsWith("temp_")) {
1373
+ try {
1374
+ await executeAction("UPDATE_RECORD", {
1375
+ tableId: referencedTableId,
1376
+ recordId,
1377
+ data: { [colName]: value2 }
1378
+ });
1379
+ if (context == null ? void 0 : context.triggerSaveSuccess) {
1380
+ context.triggerSaveSuccess();
1381
+ }
1382
+ } catch (err) {
1383
+ console.error("[SubTableViewer] Failed to auto-save linked record field", err);
1384
+ }
1385
+ }
1386
+ };
1387
+ const handleCreateRecord = async () => {
1388
+ var _a2;
1389
+ if (!executeAction || !referencedTableId) return;
1390
+ for (const col of targetColumns) {
1391
+ if (col.isRequired) {
1392
+ const val = newRecordData[col.name];
1393
+ if (val === void 0 || val === null || typeof val === "string" && val.trim() === "") {
1394
+ addToast({
1395
+ type: "error",
1396
+ message: `Validation Error: Field '${col.name}' is required but was not provided.`
1397
+ });
1398
+ return;
1399
+ }
1400
+ }
1401
+ }
1402
+ try {
1403
+ const res = await executeAction("CREATE_RECORD", {
1404
+ tableId: referencedTableId,
1405
+ records: [newRecordData]
1406
+ });
1407
+ if (res && res.success === false) {
1408
+ throw new Error(res.error || "Action execution failed");
1409
+ }
1410
+ const created = Array.isArray(res) ? res[0] : ((_a2 = res == null ? void 0 : res.data) == null ? void 0 : _a2[0]) || res;
1411
+ if (created) {
1412
+ const newRecord = {
1413
+ id: String(created.id || created._id),
1414
+ data: created.data || newRecordData
1415
+ };
1416
+ handleLinkRecord(newRecord);
1417
+ setIsCreating(false);
1418
+ setNewRecordData({});
1419
+ }
1420
+ } catch (err) {
1421
+ const msg = (err == null ? void 0 : err.message) || String(err);
1422
+ addToast({
1423
+ type: "error",
1424
+ message: msg
1425
+ });
1426
+ }
1427
+ };
1428
+ const getDisplayLabel = (record) => {
1429
+ const fields = column.subTableDisplayFields || [];
1430
+ if (fields.length === 0) {
1431
+ const firstField = Object.keys(record.data).find((k) => k !== "_id");
1432
+ return firstField ? String(record.data[firstField] || "") : record.id;
1433
+ }
1434
+ return fields.map((f) => String(record.data[f] || "")).filter(Boolean).join(" ");
1435
+ };
1436
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "p-3 animate-in fade-in slide-in-from-top-2 duration-200", dir: "rtl", children: [
1437
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-4 mb-2.5", children: [
1438
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-xs font-bold text-slate-600", children: (_a = targetSchema == null ? void 0 : targetSchema.name) != null ? _a : column.referencedTableName }) }),
1439
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-1.5", children: [
1440
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "relative", ref: searchRef, children: [
1441
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1442
+ "button",
1443
+ {
1444
+ type: "button",
1445
+ onClick: () => setIsSearchOpen((prev) => !prev),
1446
+ 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",
1447
+ children: [
1448
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3 h-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }),
1449
+ "\u05E7\u05D9\u05E9\u05D5\u05E8 \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA"
1450
+ ]
1451
+ }
1452
+ ),
1453
+ isSearchOpen && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("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: [
1454
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1455
+ "input",
1456
+ {
1457
+ type: "text",
1458
+ value: searchQuery,
1459
+ onChange: (e) => handleSearch(e.target.value),
1460
+ placeholder: "\u05D7\u05E4\u05E9 \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA...",
1461
+ 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",
1462
+ autoFocus: true
1463
+ }
1464
+ ),
1465
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "max-h-48 overflow-y-auto", children: isSearching ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex items-center justify-center py-4", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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__ */ (0, import_jsx_runtime5.jsx)(
1466
+ "button",
1467
+ {
1468
+ type: "button",
1469
+ onClick: () => handleLinkRecord(r),
1470
+ className: "w-full text-right px-2 py-1.5 text-xs hover:bg-blue-50 rounded cursor-pointer transition-colors",
1471
+ children: getDisplayLabel(r)
1472
+ },
1473
+ r.id
1474
+ )) : searchQuery.trim() ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-xs text-slate-400 text-center py-3", children: "\u05D4\u05E7\u05DC\u05D3 \u05DC\u05D7\u05D9\u05E4\u05D5\u05E9..." }) })
1475
+ ] })
1476
+ ] }),
1477
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1478
+ "button",
1479
+ {
1480
+ type: "button",
1481
+ onClick: () => {
1482
+ setIsCreating(true);
1483
+ const initialData = {};
1484
+ targetColumns.forEach((c) => {
1485
+ if (c.defaultValue !== void 0 && c.defaultValue !== null) {
1486
+ initialData[c.name] = c.type === "NUMBER" || c.type === "CURRENCY" ? parseFloat(c.defaultValue) : c.type === "BOOLEAN" ? c.defaultValue === "true" || c.defaultValue === true : c.defaultValue;
1487
+ } else {
1488
+ if (c.type === "NUMBER" || c.type === "CURRENCY") initialData[c.name] = 0;
1489
+ else if (c.type === "BOOLEAN") initialData[c.name] = false;
1490
+ else initialData[c.name] = "";
1491
+ }
1492
+ });
1493
+ setNewRecordData(initialData);
1494
+ },
1495
+ 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",
1496
+ children: [
1497
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3 h-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M12 4v16m8-8H4" }) }),
1498
+ "\u05E8\u05E9\u05D5\u05DE\u05D4 \u05D7\u05D3\u05E9\u05D4"
1499
+ ]
1500
+ }
1501
+ )
1502
+ ] })
1503
+ ] }),
1504
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex items-center justify-center py-6", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-5 h-5 border-2 border-blue-400 border-t-transparent rounded-full animate-spin" }) }) : entries.length === 0 && !isCreating ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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__ */ (0, import_jsx_runtime5.jsx)("div", { className: "overflow-x-auto pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("table", { className: "w-full text-xs border-collapse", children: [
1505
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { className: "bg-slate-100/80", children: [
1506
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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" }),
1507
+ targetColumns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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)),
1508
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "border border-slate-200 px-2 py-1.5 w-14" })
1509
+ ] }) }),
1510
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tbody", { children: [
1511
+ entries.map((entry) => {
1512
+ const record = linkedRecords.find((r) => r.id === entry.recordId);
1513
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { className: "hover:bg-blue-50/30 transition-colors", children: [
1514
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border border-slate-200 px-2 py-1 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1515
+ "input",
1516
+ {
1517
+ type: "checkbox",
1518
+ checked: entry.isSelected,
1519
+ onChange: () => handleToggleSelected(entry.recordId),
1520
+ className: "w-3.5 h-3.5 rounded border-slate-300 text-blue-600 cursor-pointer"
1521
+ }
1522
+ ) }),
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__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border border-slate-200 p-0 relative h-8", children: record ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1528
+ InputComponent,
1529
+ {
1530
+ value: (_b = record.data[col.name]) != null ? _b : colType === "BOOLEAN" ? false : "",
1531
+ column: col,
1532
+ rowId: record.id,
1533
+ onChange: (v) => handleRecordCellChange(record.id, 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
+ updateRelationOptions: (name, opts) => setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [name]: opts })),
1538
+ refetchRelation,
1539
+ parentRecord: { tableId: (context == null ? void 0 : context.parentTableId) || (context == null ? void 0 : context.tableId), data: context == null ? void 0 : context.rowData },
1540
+ rowData: record.data,
1541
+ tableId: targetSchema == null ? void 0 : targetSchema.id,
1542
+ updateQuietly: (rid, colName, val) => handleRecordCellChange(rid, colName, val)
1543
+ })
1544
+ }
1545
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-slate-300 italic px-2", children: "\u05D8\u05D5\u05E2\u05DF..." }) }, col.name);
1546
+ }),
1547
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border border-slate-200 px-1 py-1 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1548
+ "button",
1549
+ {
1550
+ type: "button",
1551
+ onClick: () => handleUnlinkRecord(entry.recordId),
1552
+ className: "text-slate-400 hover:text-rose-500 p-0.5 rounded transition-colors cursor-pointer inline-flex items-center justify-center w-full",
1553
+ title: "\u05D4\u05E1\u05E8 \u05E7\u05D9\u05E9\u05D5\u05E8",
1554
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M6 18L18 6M6 6l12 12" }) })
1555
+ }
1556
+ ) })
1557
+ ] }, entry.recordId);
1558
+ }),
1559
+ isCreating && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { className: "bg-emerald-50/40", children: [
1560
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border border-emerald-200 px-2 py-1 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-emerald-500 font-bold text-[10px]", children: "\u05D7\u05D3\u05E9" }) }),
1561
+ targetColumns.map((col) => {
1562
+ var _a2, _b;
1563
+ const colType = ((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) || "DEFAULT";
1564
+ const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
1565
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border border-emerald-200 p-0 relative h-8", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1566
+ InputComponent,
1567
+ {
1568
+ value: (_b = newRecordData[col.name]) != null ? _b : colType === "BOOLEAN" ? false : "",
1569
+ column: col,
1570
+ rowId: "new_record",
1571
+ onChange: (v) => setNewRecordData((prev) => __spreadProps(__spreadValues({}, prev), { [col.name]: v })),
1572
+ context: __spreadProps(__spreadValues({}, context), {
1573
+ 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",
1574
+ relationOptions,
1575
+ refetchRelation
1576
+ })
1577
+ }
1578
+ ) }, `new_${col.name}`);
1579
+ }),
1580
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border border-emerald-200 px-1 py-1 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-center gap-1", children: [
1581
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1582
+ "button",
1583
+ {
1584
+ type: "button",
1585
+ onClick: handleCreateRecord,
1586
+ className: "p-1 text-emerald-600 hover:bg-emerald-100 rounded transition-colors",
1587
+ title: "\u05E9\u05DE\u05D5\u05E8",
1588
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M5 13l4 4L19 7" }) })
1589
+ }
1590
+ ),
1591
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1592
+ "button",
1593
+ {
1594
+ type: "button",
1595
+ onClick: () => {
1596
+ setIsCreating(false);
1597
+ },
1598
+ className: "p-1 text-rose-500 hover:bg-rose-100 rounded transition-colors",
1599
+ title: "\u05D1\u05D9\u05D8\u05D5\u05DC",
1600
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M6 18L18 6M6 6l12 12" }) })
1601
+ }
1602
+ )
1603
+ ] }) })
1604
+ ] })
1605
+ ] })
1606
+ ] }) })
1607
+ ] });
1608
+ }
1609
+
1610
+ // src/components/TableBlock/TableBlockClient.tsx
1611
+ var import_lucide_react4 = require("lucide-react");
1612
+ var import_jsx_runtime6 = require("react/jsx-runtime");
905
1613
  function TableBlockClient({
906
1614
  data: initialRecords,
907
1615
  settings: schema,
@@ -918,6 +1626,68 @@ function TableBlockClient({
918
1626
  "data-testid": dataTestId
919
1627
  }) {
920
1628
  const { showError, addToast } = useToast();
1629
+ const [columnWidths, setColumnWidths] = (0, import_react7.useState)({});
1630
+ const [isMounted, setIsMounted] = (0, import_react7.useState)(false);
1631
+ 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";
1632
+ const [page, setPage] = (0, import_react7.useState)(1);
1633
+ const [limit, setLimit] = (0, import_react7.useState)(50);
1634
+ const [totalRecords, setTotalRecords] = (0, import_react7.useState)(0);
1635
+ const [totalPages, setTotalPages] = (0, import_react7.useState)(1);
1636
+ (0, import_react7.useEffect)(() => {
1637
+ if (typeof window !== "undefined") {
1638
+ const savedWidths = localStorage.getItem(`table_widths_${tableKey}`);
1639
+ if (savedWidths) {
1640
+ try {
1641
+ setColumnWidths(JSON.parse(savedWidths));
1642
+ } catch (e) {
1643
+ }
1644
+ }
1645
+ const savedSummary = localStorage.getItem(`table_summary_${tableKey}`);
1646
+ if (savedSummary !== null) {
1647
+ setShowSummary(savedSummary === "true");
1648
+ }
1649
+ const savedLimit = localStorage.getItem(`table_limit_${tableKey}`);
1650
+ if (savedLimit) {
1651
+ const parsed = parseInt(savedLimit, 10);
1652
+ if ([20, 50, 100].includes(parsed)) {
1653
+ setLimit(parsed);
1654
+ }
1655
+ }
1656
+ }
1657
+ setIsMounted(true);
1658
+ }, [tableKey]);
1659
+ const [showSummary, setShowSummary] = (0, import_react7.useState)(false);
1660
+ const toggleSummary = () => {
1661
+ setShowSummary((prev) => {
1662
+ const next = !prev;
1663
+ 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";
1664
+ localStorage.setItem(`table_summary_${tableKey2}`, String(next));
1665
+ return next;
1666
+ });
1667
+ };
1668
+ const [resizingCol, setResizingCol] = (0, import_react7.useState)(null);
1669
+ (0, import_react7.useEffect)(() => {
1670
+ if (!resizingCol) return;
1671
+ const handleMouseMove = (e) => {
1672
+ const diffX = resizingCol.startX - e.clientX;
1673
+ const newWidth = Math.max(100, Math.min(500, resizingCol.startWidth + diffX));
1674
+ setColumnWidths((prev) => __spreadProps(__spreadValues({}, prev), { [resizingCol.name]: newWidth }));
1675
+ };
1676
+ const handleMouseUp = () => {
1677
+ setResizingCol(null);
1678
+ setColumnWidths((prev) => {
1679
+ 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";
1680
+ localStorage.setItem(`table_widths_${tableKey2}`, JSON.stringify(prev));
1681
+ return prev;
1682
+ });
1683
+ };
1684
+ document.addEventListener("mousemove", handleMouseMove);
1685
+ document.addEventListener("mouseup", handleMouseUp);
1686
+ return () => {
1687
+ document.removeEventListener("mousemove", handleMouseMove);
1688
+ document.removeEventListener("mouseup", handleMouseUp);
1689
+ };
1690
+ }, [resizingCol, schema]);
921
1691
  const normalizeRecords = (records) => {
922
1692
  return (records || []).map((row) => {
923
1693
  var _c;
@@ -943,18 +1713,38 @@ function TableBlockClient({
943
1713
  return __spreadProps(__spreadValues({}, row), { id: String(row.id || ""), data: rowData });
944
1714
  });
945
1715
  };
946
- const [localColumns, setLocalColumns] = (0, import_react6.useState)(() => (schema == null ? void 0 : schema.columns) || []);
947
- (0, import_react6.useEffect)(() => {
1716
+ const mergeColumnDefs = (0, import_react7.useCallback)((existingCols, incomingCols) => {
1717
+ if (!incomingCols || incomingCols.length === 0) return existingCols || [];
1718
+ if (!existingCols || existingCols.length === 0) return incomingCols;
1719
+ const existingMap = new Map(existingCols.map((c) => [c.name, c]));
1720
+ const merged = incomingCols.map((inc) => {
1721
+ const ext = existingMap.get(inc.name);
1722
+ if (ext) {
1723
+ existingMap.delete(inc.name);
1724
+ return __spreadValues(__spreadValues({}, ext), inc);
1725
+ }
1726
+ return inc;
1727
+ });
1728
+ for (const [, extCol] of existingMap) {
1729
+ merged.push(extCol);
1730
+ }
1731
+ return merged.sort((a, b) => {
1732
+ var _a, _b;
1733
+ return ((_a = a.order) != null ? _a : 0) - ((_b = b.order) != null ? _b : 0);
1734
+ });
1735
+ }, []);
1736
+ const [localColumns, setLocalColumns] = (0, import_react7.useState)(() => (schema == null ? void 0 : schema.columns) || []);
1737
+ (0, import_react7.useEffect)(() => {
948
1738
  if ((schema == null ? void 0 : schema.columns) && schema.columns.length > 0) {
949
- setLocalColumns(schema.columns);
1739
+ setLocalColumns((prev) => mergeColumnDefs(prev, schema.columns));
950
1740
  }
951
- }, [schema == null ? void 0 : schema.columns]);
952
- const [dirty, setDirty] = (0, import_react6.useState)({ added: [], modified: {}, deleted: [] });
953
- const dirtyRef = (0, import_react6.useRef)(dirty);
954
- (0, import_react6.useEffect)(() => {
1741
+ }, [schema == null ? void 0 : schema.columns, mergeColumnDefs]);
1742
+ const [dirty, setDirty] = (0, import_react7.useState)({ added: [], modified: {}, deleted: [] });
1743
+ const dirtyRef = (0, import_react7.useRef)(dirty);
1744
+ (0, import_react7.useEffect)(() => {
955
1745
  dirtyRef.current = dirty;
956
1746
  }, [dirty]);
957
- const mergeWithDirty = (0, import_react6.useCallback)((baseRecords) => {
1747
+ const mergeWithDirty = (0, import_react7.useCallback)((baseRecords) => {
958
1748
  const { added, modified, deleted } = dirtyRef.current;
959
1749
  const nonDeleted = (baseRecords || []).filter((r) => !deleted.includes(r.id));
960
1750
  const modifiedRecords = nonDeleted.map((r) => {
@@ -967,8 +1757,8 @@ function TableBlockClient({
967
1757
  const uniqueAdded = added.filter((r) => !baseIds.has(r.id));
968
1758
  return [...uniqueAdded, ...modifiedRecords];
969
1759
  }, []);
970
- const [data, setData] = (0, import_react6.useState)(() => normalizeRecords(initialRecords));
971
- (0, import_react6.useEffect)(() => {
1760
+ const [data, setData] = (0, import_react7.useState)(() => normalizeRecords(initialRecords));
1761
+ (0, import_react7.useEffect)(() => {
972
1762
  if (initialRecords) {
973
1763
  setData(mergeWithDirty(normalizeRecords(initialRecords)));
974
1764
  }
@@ -983,54 +1773,83 @@ function TableBlockClient({
983
1773
  }
984
1774
  return false;
985
1775
  };
986
- const [baseRecordsMap, setBaseRecordsMap] = (0, import_react6.useState)(() => {
1776
+ const [baseRecordsMap, setBaseRecordsMap] = (0, import_react7.useState)(() => {
987
1777
  const map = /* @__PURE__ */ new Map();
988
1778
  (normalizeRecords(initialRecords) || []).forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
989
1779
  return map;
990
1780
  });
991
- (0, import_react6.useEffect)(() => {
1781
+ (0, import_react7.useEffect)(() => {
992
1782
  if (initialRecords && initialRecords.length > 0) {
993
1783
  const map = /* @__PURE__ */ new Map();
994
1784
  (normalizeRecords(initialRecords) || []).forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
995
1785
  setBaseRecordsMap(map);
996
1786
  }
997
1787
  }, [initialRecords]);
998
- (0, import_react6.useEffect)(() => {
1788
+ const refetchTableData = (0, import_react7.useCallback)((targetPage) => {
999
1789
  const tableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
1000
- if (!tableId || !executeAction) return;
1001
- if (!(schema == null ? void 0 : schema.columns) || schema.columns.length === 0 || (!initialRecords || initialRecords.length === 0)) {
1002
- executeAction("FETCH_TABLE_DATA", { tableId }).then((res) => {
1003
- var _a;
1004
- if (res) {
1005
- if (((_a = res.schema) == null ? void 0 : _a.columns) && res.schema.columns.length > 0) {
1006
- setLocalColumns(res.schema.columns);
1007
- }
1008
- if (res.records && Array.isArray(res.records)) {
1009
- const norm = normalizeRecords(res.records);
1010
- const map = /* @__PURE__ */ new Map();
1011
- norm.forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
1012
- setBaseRecordsMap(map);
1013
- setData(mergeWithDirty(norm));
1790
+ if (!tableId || !executeAction) return Promise.resolve();
1791
+ const activePage = targetPage !== void 0 ? targetPage : page;
1792
+ const skip = (activePage - 1) * limit;
1793
+ return executeAction("FETCH_TABLE_DATA", { tableId, page: activePage, limit, skip }).then((res) => {
1794
+ var _a;
1795
+ if (res) {
1796
+ if (((_a = res.schema) == null ? void 0 : _a.columns) && res.schema.columns.length > 0) {
1797
+ setLocalColumns((prev) => mergeColumnDefs(prev, res.schema.columns));
1798
+ }
1799
+ if (res.records && Array.isArray(res.records)) {
1800
+ const norm = normalizeRecords(res.records);
1801
+ const map = /* @__PURE__ */ new Map();
1802
+ norm.forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
1803
+ setBaseRecordsMap(map);
1804
+ setData(norm);
1805
+ }
1806
+ if (res.meta) {
1807
+ const total = typeof res.meta.totalRecords === "number" ? res.meta.totalRecords : 0;
1808
+ const pages = typeof res.meta.totalPages === "number" ? res.meta.totalPages : Math.ceil(total / limit) || 1;
1809
+ setTotalRecords(total);
1810
+ setTotalPages(pages);
1811
+ if (activePage > pages && pages >= 1) {
1812
+ setPage(pages);
1014
1813
  }
1814
+ } else if (res.records && Array.isArray(res.records)) {
1815
+ setTotalRecords(res.records.length);
1816
+ setTotalPages(Math.ceil(res.records.length / limit) || 1);
1015
1817
  }
1016
- }).catch((err) => {
1017
- console.error("[TableBlock] Failed to auto-fetch table data:", err);
1018
- });
1818
+ }
1819
+ }).catch((err) => {
1820
+ console.error("[TableBlock] Failed to auto-fetch table data:", err);
1821
+ });
1822
+ }, [schema == null ? void 0 : schema.tableMetaId, schema == null ? void 0 : schema.tableId, schema == null ? void 0 : schema.id, page, limit, executeAction, mergeColumnDefs]);
1823
+ (0, import_react7.useEffect)(() => {
1824
+ refetchTableData();
1825
+ }, [refetchTableData]);
1826
+ const handleLimitChange = (newLimit) => {
1827
+ setLimit(newLimit);
1828
+ setPage(1);
1829
+ if (typeof window !== "undefined") {
1830
+ localStorage.setItem(`table_limit_${tableKey}`, String(newLimit));
1019
1831
  }
1020
- }, [schema == null ? void 0 : schema.tableMetaId, schema == null ? void 0 : schema.tableId, schema == null ? void 0 : schema.id, schema == null ? void 0 : schema.columns, initialRecords, executeAction, mergeWithDirty]);
1021
- (0, import_react6.useEffect)(() => {
1832
+ };
1833
+ const handlePrevPage = () => {
1834
+ setPage((prev) => Math.max(1, prev - 1));
1835
+ };
1836
+ const handleNextPage = () => {
1837
+ setPage((prev) => Math.min(totalPages, prev + 1));
1838
+ };
1839
+ (0, import_react7.useEffect)(() => {
1022
1840
  if (error) {
1023
1841
  showError(error, "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E8\u05DB\u05D9\u05D1");
1024
1842
  }
1025
1843
  }, [error, showError]);
1026
- const [searchQuery, setSearchQuery] = (0, import_react6.useState)("");
1027
- const [selectedIds, setSelectedIds] = (0, import_react6.useState)(/* @__PURE__ */ new Set());
1028
- const [pendingDeletions, setPendingDeletions] = (0, import_react6.useState)([]);
1029
- const [isSaving, setIsSaving] = (0, import_react6.useState)(false);
1030
- const [isSaveSuccess, setIsSaveSuccess] = (0, import_react6.useState)(false);
1031
- const [relationOptions, setRelationOptions] = (0, import_react6.useState)({});
1032
- const schemaColsString = (0, import_react6.useMemo)(() => JSON.stringify(localColumns || []), [localColumns]);
1033
- const refetchRelation = (0, import_react6.useCallback)(async (colName) => {
1844
+ const [searchQuery, setSearchQuery] = (0, import_react7.useState)("");
1845
+ const [selectedIds, setSelectedIds] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
1846
+ const [pendingDeletions, setPendingDeletions] = (0, import_react7.useState)([]);
1847
+ const [isSaving, setIsSaving] = (0, import_react7.useState)(false);
1848
+ const [isSaveSuccess, setIsSaveSuccess] = (0, import_react7.useState)(false);
1849
+ const [relationOptions, setRelationOptions] = (0, import_react7.useState)({});
1850
+ const [expandedRowIds, setExpandedRowIds] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
1851
+ const schemaColsString = (0, import_react7.useMemo)(() => JSON.stringify(localColumns || []), [localColumns]);
1852
+ const refetchRelation = (0, import_react7.useCallback)(async (colName) => {
1034
1853
  var _a;
1035
1854
  let parsedCols = [];
1036
1855
  try {
@@ -1050,7 +1869,7 @@ function TableBlockClient({
1050
1869
  console.warn(`[TableBlock] Could not fetch relation options for column ${colName}:`, err);
1051
1870
  }
1052
1871
  }, [schemaColsString, executeAction]);
1053
- (0, import_react6.useEffect)(() => {
1872
+ (0, import_react7.useEffect)(() => {
1054
1873
  let parsedCols = [];
1055
1874
  try {
1056
1875
  parsedCols = JSON.parse(schemaColsString);
@@ -1064,10 +1883,144 @@ function TableBlockClient({
1064
1883
  refetchRelation(col.name);
1065
1884
  });
1066
1885
  }, [schemaColsString, refetchRelation]);
1067
- const filteredColumns = (0, import_react6.useMemo)(() => {
1068
- const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
1069
- return (localColumns || []).filter((col) => !systemFields.includes(col.name));
1886
+ const normalizedColumns = (0, import_react7.useMemo)(() => {
1887
+ return (localColumns || []).map((col, idx) => {
1888
+ const isRequired = col.isRequired === true || String(col.isRequired) === "true";
1889
+ const isUnique = col.isUnique === true || String(col.isUnique) === "true";
1890
+ const isProtected = isRequired || isUnique;
1891
+ return __spreadProps(__spreadValues({}, col), {
1892
+ order: typeof col.order === "number" ? col.order : idx,
1893
+ isHidden: isProtected ? false : Boolean(col.isHidden)
1894
+ });
1895
+ }).sort((a, b) => {
1896
+ var _a, _b;
1897
+ return ((_a = a.order) != null ? _a : 0) - ((_b = b.order) != null ? _b : 0);
1898
+ });
1070
1899
  }, [localColumns]);
1900
+ const filteredColumns = (0, import_react7.useMemo)(() => {
1901
+ const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
1902
+ return normalizedColumns.filter((col) => !systemFields.includes(col.name) && !col.isHidden);
1903
+ }, [normalizedColumns]);
1904
+ const customizableColumns = (0, import_react7.useMemo)(() => {
1905
+ const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
1906
+ return normalizedColumns.filter((col) => !systemFields.includes(col.name));
1907
+ }, [normalizedColumns]);
1908
+ const [isColumnsDropdownOpen, setIsColumnsDropdownOpen] = (0, import_react7.useState)(false);
1909
+ const dropdownRef = (0, import_react7.useRef)(null);
1910
+ (0, import_react7.useEffect)(() => {
1911
+ const handleClickOutside = (e) => {
1912
+ if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
1913
+ setIsColumnsDropdownOpen(false);
1914
+ }
1915
+ };
1916
+ if (isColumnsDropdownOpen) {
1917
+ document.addEventListener("mousedown", handleClickOutside);
1918
+ }
1919
+ return () => {
1920
+ document.removeEventListener("mousedown", handleClickOutside);
1921
+ };
1922
+ }, [isColumnsDropdownOpen]);
1923
+ const handleShowAllColumns = async () => {
1924
+ var _a;
1925
+ const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
1926
+ const systemCols = (localColumns || []).filter((c) => systemFields.includes(c.name));
1927
+ const updatedCustomCols = customizableColumns.map((col) => __spreadProps(__spreadValues({}, col), {
1928
+ isHidden: false
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 show all columns:", err);
1946
+ 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");
1947
+ }
1948
+ }
1949
+ };
1950
+ const handleToggleColumnVisibility = async (colName, isVisible) => {
1951
+ var _a;
1952
+ const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
1953
+ const systemCols = (localColumns || []).filter((c) => systemFields.includes(c.name));
1954
+ const updatedCustomCols = customizableColumns.map((col) => {
1955
+ const isRequired = col.isRequired === true || String(col.isRequired) === "true";
1956
+ const isUnique = col.isUnique === true || String(col.isUnique) === "true";
1957
+ const isProtected = isRequired || isUnique;
1958
+ if (col.name === colName) {
1959
+ if (isProtected) {
1960
+ return __spreadProps(__spreadValues({}, col), { isHidden: false });
1961
+ }
1962
+ return __spreadProps(__spreadValues({}, col), { isHidden: !isVisible });
1963
+ }
1964
+ return __spreadProps(__spreadValues({}, col), {
1965
+ isHidden: isProtected ? false : Boolean(col.isHidden)
1966
+ });
1967
+ });
1968
+ const fullUpdatedColumns = [...systemCols, ...updatedCustomCols];
1969
+ setLocalColumns(fullUpdatedColumns);
1970
+ const targetTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
1971
+ if (targetTableId && executeAction) {
1972
+ try {
1973
+ const res = await executeAction("UPDATE_TABLE_COLUMNS", {
1974
+ tableId: targetTableId,
1975
+ tableMetaId: targetTableId,
1976
+ columns: fullUpdatedColumns
1977
+ });
1978
+ const returnedCols = (res == null ? void 0 : res.columns) || ((_a = res == null ? void 0 : res.data) == null ? void 0 : _a.columns);
1979
+ if (returnedCols && Array.isArray(returnedCols)) {
1980
+ setLocalColumns((prev) => mergeColumnDefs(prev, returnedCols));
1981
+ }
1982
+ } catch (err) {
1983
+ console.error("[TableBlock] Failed to save column visibility:", err);
1984
+ 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");
1985
+ }
1986
+ }
1987
+ };
1988
+ const [draggedColName, setDraggedColName] = (0, import_react7.useState)(null);
1989
+ const [dragOverColName, setDragOverColName] = (0, import_react7.useState)(null);
1990
+ const handleColumnReorder = async (draggedName, dropTargetName) => {
1991
+ var _a;
1992
+ if (draggedName === dropTargetName) return;
1993
+ const currentCustomCols = [...customizableColumns];
1994
+ const fromIndex = currentCustomCols.findIndex((c) => c.name === draggedName);
1995
+ const toIndex = currentCustomCols.findIndex((c) => c.name === dropTargetName);
1996
+ if (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) return;
1997
+ const [draggedItem] = currentCustomCols.splice(fromIndex, 1);
1998
+ currentCustomCols.splice(toIndex, 0, draggedItem);
1999
+ const updatedCustomCols = currentCustomCols.map((col, idx) => __spreadProps(__spreadValues({}, col), {
2000
+ order: idx
2001
+ }));
2002
+ const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
2003
+ const systemCols = (localColumns || []).filter((c) => systemFields.includes(c.name));
2004
+ const fullUpdatedColumns = [...systemCols, ...updatedCustomCols];
2005
+ setLocalColumns(fullUpdatedColumns);
2006
+ const targetTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
2007
+ if (targetTableId && executeAction) {
2008
+ try {
2009
+ const res = await executeAction("UPDATE_TABLE_COLUMNS", {
2010
+ tableId: targetTableId,
2011
+ tableMetaId: targetTableId,
2012
+ columns: fullUpdatedColumns
2013
+ });
2014
+ const returnedCols = (res == null ? void 0 : res.columns) || ((_a = res == null ? void 0 : res.data) == null ? void 0 : _a.columns);
2015
+ if (returnedCols && Array.isArray(returnedCols)) {
2016
+ setLocalColumns((prev) => mergeColumnDefs(prev, returnedCols));
2017
+ }
2018
+ } catch (err) {
2019
+ console.error("[TableBlock] Failed to save column reorder:", err);
2020
+ 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");
2021
+ }
2022
+ }
2023
+ };
1071
2024
  const generateTempId = () => `temp_${Math.random().toString(36).substr(2, 9)}`;
1072
2025
  const handleAddRow = () => {
1073
2026
  const defaultData = {};
@@ -1075,6 +2028,10 @@ function TableBlockClient({
1075
2028
  var _a;
1076
2029
  const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
1077
2030
  let initialValue = col.defaultValue;
2031
+ if (typeUpper === "SUB_TABLE") {
2032
+ defaultData[col.name] = [];
2033
+ return;
2034
+ }
1078
2035
  if (initialValue !== void 0 && initialValue !== null && initialValue !== "") {
1079
2036
  if (typeUpper === "CURRENCY" || typeUpper === "NUMBER") {
1080
2037
  initialValue = parseFloat(initialValue);
@@ -1097,6 +2054,34 @@ function TableBlockClient({
1097
2054
  setData((prev) => [newRow, ...prev]);
1098
2055
  setDirty((prev) => __spreadProps(__spreadValues({}, prev), { added: [newRow, ...prev.added] }));
1099
2056
  };
2057
+ const handleDuplicateRow = () => {
2058
+ if (selectedIds.size !== 1) return;
2059
+ const targetId = Array.from(selectedIds)[0];
2060
+ const sourceRow = data.find((r) => r.id === targetId);
2061
+ if (!sourceRow) return;
2062
+ const uniqueColNames = new Set(
2063
+ (localColumns || []).filter((c) => c.isUnique === true || String(c.isUnique) === "true").map((c) => c.name)
2064
+ );
2065
+ const fieldsToScrub = /* @__PURE__ */ new Set(["id", "_id", "createdAt", "updatedAt", "created_at", "updated_at"]);
2066
+ const clonedData = __spreadValues({}, sourceRow.data);
2067
+ Object.keys(clonedData).forEach((key) => {
2068
+ var _a;
2069
+ if (fieldsToScrub.has(key) || uniqueColNames.has(key)) {
2070
+ const col = (localColumns || []).find((c) => c.name === key);
2071
+ const typeUpper = (_a = col == null ? void 0 : col.type) == null ? void 0 : _a.toUpperCase();
2072
+ if (typeUpper === "NUMBER" || typeUpper === "CURRENCY") {
2073
+ clonedData[key] = 0;
2074
+ } else if (typeUpper === "BOOLEAN") {
2075
+ clonedData[key] = false;
2076
+ } else {
2077
+ clonedData[key] = "";
2078
+ }
2079
+ }
2080
+ });
2081
+ const newRow = { id: generateTempId(), data: clonedData };
2082
+ setData((prev) => [newRow, ...prev]);
2083
+ setDirty((prev) => __spreadProps(__spreadValues({}, prev), { added: [newRow, ...prev.added] }));
2084
+ };
1100
2085
  const handleCellChange = (rowId, colName, value) => {
1101
2086
  setData((prev) => prev.map(
1102
2087
  (row) => row.id === rowId ? __spreadProps(__spreadValues({}, row), { data: __spreadProps(__spreadValues({}, row.data), { [colName]: value }) }) : row
@@ -1130,6 +2115,36 @@ function TableBlockClient({
1130
2115
  });
1131
2116
  }
1132
2117
  };
2118
+ const triggerSaveSuccess = (0, import_react7.useCallback)(() => {
2119
+ setIsSaveSuccess(true);
2120
+ setTimeout(() => {
2121
+ setIsSaveSuccess(false);
2122
+ }, 2500);
2123
+ }, []);
2124
+ const handleQuietCellChange = (0, import_react7.useCallback)((rowId, colName, value) => {
2125
+ setData((prev) => prev.map(
2126
+ (row) => row.id === rowId ? __spreadProps(__spreadValues({}, row), { data: __spreadProps(__spreadValues({}, row.data), { [colName]: value }) }) : row
2127
+ ));
2128
+ if (rowId.startsWith("temp_")) {
2129
+ setDirty((prev) => {
2130
+ if (!prev.added.some((r) => r.id === rowId)) return prev;
2131
+ return __spreadProps(__spreadValues({}, prev), {
2132
+ added: prev.added.map(
2133
+ (r) => r.id === rowId ? __spreadProps(__spreadValues({}, r), { data: __spreadProps(__spreadValues({}, r.data), { [colName]: value }) }) : r
2134
+ )
2135
+ });
2136
+ });
2137
+ } else {
2138
+ setBaseRecordsMap((prev) => {
2139
+ const next = new Map(prev);
2140
+ const rowData = next.get(rowId);
2141
+ if (rowData) {
2142
+ next.set(rowId, __spreadProps(__spreadValues({}, rowData), { [colName]: value }));
2143
+ }
2144
+ return next;
2145
+ });
2146
+ }
2147
+ }, []);
1133
2148
  const toggleSelectAll = (checked) => {
1134
2149
  const nextSelected = checked ? new Set(filteredData.map((r) => r.id)) : /* @__PURE__ */ new Set();
1135
2150
  setSelectedIds(nextSelected);
@@ -1159,9 +2174,15 @@ function TableBlockClient({
1159
2174
  const row = data.find((r) => r.id === id);
1160
2175
  if (row) {
1161
2176
  driveCols.forEach((col) => {
1162
- const fileObj = row.data[col.name];
1163
- if (fileObj && fileObj.fileId) {
1164
- filesToDelete.push(fileObj.fileId);
2177
+ const fileVal = row.data[col.name];
2178
+ if (Array.isArray(fileVal)) {
2179
+ fileVal.forEach((fileObj) => {
2180
+ if (fileObj && fileObj.fileId) {
2181
+ filesToDelete.push(fileObj.fileId);
2182
+ }
2183
+ });
2184
+ } else if (fileVal && fileVal.fileId) {
2185
+ filesToDelete.push(fileVal.fileId);
1165
2186
  }
1166
2187
  });
1167
2188
  }
@@ -1188,7 +2209,7 @@ function TableBlockClient({
1188
2209
  const formatPayload = (payload) => {
1189
2210
  const formatted = {};
1190
2211
  (localColumns || []).forEach((col) => {
1191
- var _a;
2212
+ var _a, _b;
1192
2213
  if (["_id", "id", "createdAt", "updatedAt", "orgId", "tableId", "isSelected"].includes(col.name)) return;
1193
2214
  let val = payload[col.name];
1194
2215
  if (val !== void 0) {
@@ -1198,6 +2219,11 @@ function TableBlockClient({
1198
2219
  if (((_a = col.type) == null ? void 0 : _a.toUpperCase()) === "NUMBER") {
1199
2220
  val = val === "" ? 0 : Number(val);
1200
2221
  if (isNaN(val)) val = 0;
2222
+ } else if (((_b = col.type) == null ? void 0 : _b.toUpperCase()) === "SUB_TABLE" && Array.isArray(val)) {
2223
+ val = val.map((item) => {
2224
+ const _a2 = item, { _resolvedData } = _a2, rest = __objRest(_a2, ["_resolvedData"]);
2225
+ return rest;
2226
+ });
1201
2227
  }
1202
2228
  formatted[col.name] = val;
1203
2229
  }
@@ -1317,6 +2343,7 @@ function TableBlockClient({
1317
2343
  return next;
1318
2344
  });
1319
2345
  setDirty({ added: [], modified: {}, deleted: [] });
2346
+ await refetchTableData();
1320
2347
  setIsSaveSuccess(true);
1321
2348
  setTimeout(() => {
1322
2349
  setIsSaveSuccess(false);
@@ -1329,7 +2356,7 @@ function TableBlockClient({
1329
2356
  setIsSaving(false);
1330
2357
  }
1331
2358
  };
1332
- const filteredData = (0, import_react6.useMemo)(() => {
2359
+ const filteredData = (0, import_react7.useMemo)(() => {
1333
2360
  if (!searchQuery) return data;
1334
2361
  const lowerQuery = searchQuery.toLowerCase();
1335
2362
  return data.filter(
@@ -1340,32 +2367,60 @@ function TableBlockClient({
1340
2367
  }, [data, searchQuery]);
1341
2368
  const isUpdatingActive = Boolean(isUpdating || isSaving);
1342
2369
  const errorMessage = error ? typeof error === "string" ? error : error.message || String(error) : null;
1343
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2370
+ const columnTotals = (0, import_react7.useMemo)(() => {
2371
+ const totals = {};
2372
+ if (!showSummary) return totals;
2373
+ filteredColumns.forEach((col) => {
2374
+ var _a;
2375
+ const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
2376
+ if (typeUpper === "CURRENCY" || typeUpper === "NUMBER") {
2377
+ const sum = filteredData.reduce((acc, row) => {
2378
+ var _a2;
2379
+ const val = (_a2 = row.data) == null ? void 0 : _a2[col.name];
2380
+ const num = Number(val);
2381
+ return acc + (isNaN(num) ? 0 : num);
2382
+ }, 0);
2383
+ totals[col.name] = sum;
2384
+ }
2385
+ });
2386
+ return totals;
2387
+ }, [filteredData, filteredColumns, showSummary]);
2388
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1344
2389
  "div",
1345
2390
  {
1346
2391
  id: componentId,
1347
2392
  "data-testid": dataTestId || (componentId ? `table-block-${componentId}` : void 0),
1348
- className: `flex flex-col w-full bg-white border border-slate-200 rounded-xl shadow-xs overflow-hidden ${className}`,
2393
+ className: `flex flex-col w-full bg-white border border-slate-200 rounded-xl shadow-xs min-h-[350px] overflow-hidden ${className}`,
1349
2394
  dir: "rtl",
1350
2395
  children: [
1351
- errorMessage && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "p-3 bg-rose-50 border-b border-rose-200 text-rose-700 text-sm flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2", children: [
1352
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4 h-4 text-rose-500 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
1353
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: errorMessage })
2396
+ errorMessage && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "p-3 bg-rose-50 border-b border-rose-200 text-rose-700 text-sm flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-2", children: [
2397
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-4 h-4 text-rose-500 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
2398
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: errorMessage })
1354
2399
  ] }) }),
1355
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-3 p-3.5 sm:p-4 bg-slate-50 border-b border-slate-200", children: [
1356
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-wrap items-center gap-2.5", children: [
1357
- ((schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.name)) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "font-bold text-slate-800 text-sm sm:text-base border-l border-slate-300 pl-3 ml-1", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: schema.title || schema.name }) }),
1358
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2400
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-3 p-3.5 sm:p-4 bg-slate-50 border-b border-slate-200", children: [
2401
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap items-center gap-2.5", children: [
2402
+ ((schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.name)) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "font-bold text-slate-800 text-sm sm:text-base border-l border-slate-300 pl-3 ml-1", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: schema.title || schema.name }) }),
2403
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1359
2404
  "button",
1360
2405
  {
1361
2406
  onClick: handleAddRow,
1362
2407
  disabled: isLoading || isUpdatingActive,
1363
2408
  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",
1364
2409
  title: "\u05D4\u05D5\u05E1\u05E3 \u05E9\u05D5\u05E8\u05D4 \u05D7\u05D3\u05E9\u05D4",
1365
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4.5 h-4.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M12 4v16m8-8H4" }) })
2410
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-4.5 h-4.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M12 4v16m8-8H4" }) })
1366
2411
  }
1367
2412
  ),
1368
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2413
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2414
+ "button",
2415
+ {
2416
+ onClick: handleDuplicateRow,
2417
+ disabled: isLoading || isUpdatingActive || selectedIds.size !== 1,
2418
+ 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",
2419
+ title: "\u05E9\u05DB\u05E4\u05DC \u05E9\u05D5\u05E8\u05D4 \u05E0\u05D1\u05D7\u05E8\u05EA",
2420
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react4.Copy, { className: "w-4 h-4 text-blue-600 shrink-0" })
2421
+ }
2422
+ ),
2423
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1369
2424
  "button",
1370
2425
  {
1371
2426
  onClick: handleDeleteSelected,
@@ -1373,14 +2428,120 @@ function TableBlockClient({
1373
2428
  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",
1374
2429
  title: "\u05DE\u05D7\u05E7 \u05E9\u05D5\u05E8\u05D5\u05EA \u05E0\u05D1\u05D7\u05E8\u05D5\u05EA",
1375
2430
  children: [
1376
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4.5 h-4.5 text-rose-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }),
1377
- selectedIds.size > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "absolute -top-1.5 -right-1.5 bg-rose-600 text-white min-w-[18px] h-[18px] px-1 rounded-full text-[10px] font-bold flex items-center justify-center shadow-xs", children: selectedIds.size })
2431
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-4.5 h-4.5 text-rose-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }),
2432
+ selectedIds.size > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "absolute -top-1.5 -right-1.5 bg-rose-600 text-white min-w-[18px] h-[18px] px-1 rounded-full text-[10px] font-bold flex items-center justify-center shadow-xs", children: selectedIds.size })
1378
2433
  ]
1379
2434
  }
1380
2435
  ),
1381
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-5 w-px bg-slate-300 mx-1 hidden sm:block" }),
1382
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "relative flex-1 sm:w-64 max-w-xs", children: [
1383
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2436
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2437
+ "button",
2438
+ {
2439
+ onClick: toggleSummary,
2440
+ disabled: isLoading || isUpdatingActive,
2441
+ 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"}`,
2442
+ title: "\u05D4\u05E6\u05D2/\u05D4\u05E1\u05EA\u05E8 \u05E9\u05D5\u05E8\u05EA \u05E1\u05D9\u05DB\u05D5\u05DD",
2443
+ children: [
2444
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) }),
2445
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hidden sm:inline", children: "\u05E1\u05DB\u05D9\u05DE\u05D4" })
2446
+ ]
2447
+ }
2448
+ ),
2449
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "relative", ref: dropdownRef, children: [
2450
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2451
+ "button",
2452
+ {
2453
+ onClick: () => setIsColumnsDropdownOpen((prev) => !prev),
2454
+ disabled: isLoading || isUpdatingActive,
2455
+ 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",
2456
+ title: "\u05D4\u05E6\u05D2/\u05D4\u05E1\u05EA\u05E8 \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA",
2457
+ children: [
2458
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-4 h-4 text-slate-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2" }) }),
2459
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: `w-3.5 h-3.5 text-slate-500 transition-transform ${isColumnsDropdownOpen ? "rotate-180" : ""}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M19 9l-7 7-7-7" }) })
2460
+ ]
2461
+ }
2462
+ ),
2463
+ isColumnsDropdownOpen && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "absolute right-0 top-full mt-1.5 w-56 bg-white border border-slate-200 rounded-xl shadow-xl z-50 p-1.5 dir-rtl animate-in fade-in slide-in-from-top-2 duration-150", children: [
2464
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "px-2 py-1.5 text-xs font-bold text-slate-500 border-b border-slate-100 mb-1 flex items-center justify-between", children: [
2465
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-1.5", children: [
2466
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u05D4\u05E6\u05D2\u05EA \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA" }),
2467
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "text-[10px] font-normal text-slate-400", children: [
2468
+ "(",
2469
+ customizableColumns.filter((c) => !c.isHidden).length,
2470
+ "/",
2471
+ customizableColumns.length,
2472
+ ")"
2473
+ ] })
2474
+ ] }),
2475
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2476
+ "button",
2477
+ {
2478
+ type: "button",
2479
+ onClick: handleShowAllColumns,
2480
+ className: "text-xs text-brand hover:text-brand-hover font-semibold hover:underline cursor-pointer",
2481
+ children: "\u05D4\u05E6\u05D2 \u05D4\u05DB\u05DC"
2482
+ }
2483
+ )
2484
+ ] }),
2485
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "max-h-60 overflow-y-auto space-y-0.5", children: customizableColumns.map((col) => {
2486
+ const isRequired = col.isRequired === true || String(col.isRequired) === "true";
2487
+ const isUnique = col.isUnique === true || String(col.isUnique) === "true";
2488
+ const isProtected = isRequired || isUnique;
2489
+ const isVisible = !col.isHidden;
2490
+ let protectedExplanation = "";
2491
+ if (isRequired && isUnique) {
2492
+ 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";
2493
+ } else if (isRequired) {
2494
+ 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";
2495
+ } else if (isUnique) {
2496
+ 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";
2497
+ }
2498
+ 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";
2499
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2500
+ "div",
2501
+ {
2502
+ onClick: () => {
2503
+ if (!isProtected) {
2504
+ handleToggleColumnVisibility(col.name, !isVisible);
2505
+ }
2506
+ },
2507
+ title: isProtected ? protectedExplanation : void 0,
2508
+ 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"}`,
2509
+ children: [
2510
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-2 min-w-0", children: [
2511
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2512
+ "input",
2513
+ {
2514
+ type: "checkbox",
2515
+ checked: isVisible,
2516
+ disabled: isProtected,
2517
+ onChange: () => {
2518
+ },
2519
+ 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"
2520
+ }
2521
+ ),
2522
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: `font-medium truncate ${isProtected ? "text-slate-500" : "text-slate-700"}`, children: col.name })
2523
+ ] }),
2524
+ isProtected && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2525
+ "div",
2526
+ {
2527
+ 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",
2528
+ title: protectedExplanation,
2529
+ children: [
2530
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-3 h-3 text-amber-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: "2.2", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" }) }),
2531
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: badgeLabel })
2532
+ ]
2533
+ }
2534
+ )
2535
+ ]
2536
+ },
2537
+ col.name
2538
+ );
2539
+ }) })
2540
+ ] })
2541
+ ] }),
2542
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "h-5 w-px bg-slate-300 mx-1 hidden sm:block" }),
2543
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "relative flex-1 sm:w-64 max-w-xs", children: [
2544
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1384
2545
  "input",
1385
2546
  {
1386
2547
  placeholder: "\u05D7\u05D9\u05E4\u05D5\u05E9 \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA...",
@@ -1390,36 +2551,45 @@ function TableBlockClient({
1390
2551
  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"
1391
2552
  }
1392
2553
  ),
1393
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4 h-4 text-slate-400 absolute right-2.5 top-2.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) })
2554
+ searchQuery ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2555
+ "button",
2556
+ {
2557
+ type: "button",
2558
+ onClick: () => setSearchQuery(""),
2559
+ 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",
2560
+ title: "Clear search",
2561
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react4.X, { className: "w-3.5 h-3.5" })
2562
+ }
2563
+ ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-4 h-4 text-slate-400 absolute right-2.5 top-2.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) })
1394
2564
  ] })
1395
2565
  ] }),
1396
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-3", children: [
1397
- isUpdatingActive ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-xs text-blue-600 font-semibold flex items-center gap-1.5 bg-blue-50 border border-blue-200 px-3 py-1.5 rounded-lg animate-pulse", children: [
1398
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w-2 h-2 rounded-full bg-blue-500 inline-block" }),
2566
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-3", children: [
2567
+ isUpdatingActive ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "text-xs text-blue-600 font-semibold flex items-center gap-1.5 bg-blue-50 border border-blue-200 px-3 py-1.5 rounded-lg animate-pulse", children: [
2568
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "w-2 h-2 rounded-full bg-blue-500 inline-block" }),
1399
2569
  "\u05DE\u05E2\u05D3\u05DB\u05DF..."
1400
- ] }) : isSaveSuccess ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-xs text-emerald-700 font-semibold flex items-center gap-1.5 bg-emerald-50 border border-emerald-200 px-3 py-1.5 rounded-lg animate-in fade-in duration-200", children: [
1401
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4 h-4 text-emerald-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M5 13l4 4L19 7" }) }),
2570
+ ] }) : isSaveSuccess ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "text-xs text-emerald-700 font-semibold flex items-center gap-1.5 bg-emerald-50 border border-emerald-200 px-3 py-1.5 rounded-lg animate-in fade-in duration-200", children: [
2571
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-4 h-4 text-emerald-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M5 13l4 4L19 7" }) }),
1402
2572
  "\u05E2\u05D5\u05D3\u05DB\u05DF \u05D1\u05D4\u05E6\u05DC\u05D7\u05D4"
1403
- ] }) : hasChanges ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-xs font-semibold text-amber-700 animate-in fade-in", children: "\u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD \u05E9\u05DC\u05D0 \u05E0\u05E9\u05DE\u05E8\u05D5" }) : null,
1404
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2573
+ ] }) : hasChanges ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-xs font-semibold text-amber-700 animate-in fade-in", children: "\u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD \u05E9\u05DC\u05D0 \u05E0\u05E9\u05DE\u05E8\u05D5" }) : null,
2574
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1405
2575
  "button",
1406
2576
  {
1407
2577
  onClick: handleSave,
1408
2578
  disabled: isUpdatingActive || isLoading || !hasChanges,
1409
2579
  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"}`,
1410
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: isUpdatingActive ? "\u05E9\u05D5\u05DE\u05E8..." : "\u05E9\u05DE\u05D9\u05E8\u05EA \u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD" })
2580
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: isUpdatingActive ? "\u05E9\u05D5\u05DE\u05E8..." : "\u05E9\u05DE\u05D9\u05E8\u05EA \u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD" })
1411
2581
  }
1412
2582
  )
1413
2583
  ] })
1414
2584
  ] }),
1415
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "overflow-x-auto relative", children: [
1416
- isLoading && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "absolute inset-0 bg-white/80 backdrop-blur-xs z-20 flex flex-col items-center justify-center gap-2", children: [
1417
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-6 h-6 border-2 border-brand border-t-transparent rounded-full animate-spin" }),
1418
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-sm font-medium text-slate-600", children: "\u05D8\u05D5\u05E2\u05DF \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD..." })
2585
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `overflow-x-auto relative min-h-[260px] flex-1 transition-opacity duration-200 ${isMounted ? "opacity-100" : "opacity-0"}`, children: [
2586
+ isLoading && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "absolute inset-0 bg-white/80 backdrop-blur-xs z-20 flex flex-col items-center justify-center gap-2", children: [
2587
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "w-6 h-6 border-2 border-brand border-t-transparent rounded-full animate-spin" }),
2588
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm font-medium text-slate-600", children: "\u05D8\u05D5\u05E2\u05DF \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD..." })
1419
2589
  ] }),
1420
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("table", { className: "w-full text-sm text-right border-collapse", children: [
1421
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("thead", { className: "bg-slate-100/80 text-slate-700 sticky top-0 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { children: [
1422
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "border-b border-l border-slate-200 p-2.5 w-10 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2590
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("table", { className: "w-full text-sm text-right border-collapse table-auto", children: [
2591
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("thead", { className: "bg-slate-100/80 text-slate-700 sticky top-0 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("tr", { children: [
2592
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("th", { className: "border-b border-l border-slate-200 p-2.5 w-10 text-center shrink-0", style: { width: 50, minWidth: 50, maxWidth: 50 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1423
2593
  "input",
1424
2594
  {
1425
2595
  type: "checkbox",
@@ -1429,67 +2599,313 @@ function TableBlockClient({
1429
2599
  className: "w-4 h-4 rounded border-slate-300 text-brand"
1430
2600
  }
1431
2601
  ) }),
1432
- filteredColumns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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))
1433
- ] }) }),
1434
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tbody", { className: "bg-white", children: (isStateEmpty || filteredData.length === 0) && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { colSpan: filteredColumns.length + 1, className: "text-center py-12 text-slate-400", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col items-center justify-center gap-2", children: [
1435
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-8 h-8 text-slate-300", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", d: "M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4" }) }),
1436
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05DC\u05D4\u05E6\u05D2\u05D4." })
1437
- ] }) }) }) : filteredData.map((row) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { className: "hover:bg-blue-50/30 transition-colors group", children: [
1438
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-l border-slate-200 p-1.5 text-center bg-white group-hover:bg-transparent", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1439
- "input",
1440
- {
1441
- type: "checkbox",
1442
- checked: selectedIds.has(row.id),
1443
- onChange: (e) => toggleSelectRow(row.id, e.target.checked),
1444
- disabled: isLoading || isUpdatingActive,
1445
- className: "w-4 h-4 rounded border-slate-300 text-brand"
1446
- }
1447
- ) }),
1448
2602
  filteredColumns.map((col) => {
2603
+ const isDragging = draggedColName === col.name;
2604
+ const isDragOver = dragOverColName === col.name;
2605
+ const currentWidth = columnWidths[col.name] || 200;
2606
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2607
+ "th",
2608
+ {
2609
+ style: { width: currentWidth, minWidth: currentWidth, maxWidth: currentWidth },
2610
+ draggable: !isLoading && !isUpdatingActive,
2611
+ onDragStart: (e) => {
2612
+ e.dataTransfer.setData("text/plain", col.name);
2613
+ e.dataTransfer.effectAllowed = "move";
2614
+ setDraggedColName(col.name);
2615
+ },
2616
+ onDragOver: (e) => {
2617
+ e.preventDefault();
2618
+ e.dataTransfer.dropEffect = "move";
2619
+ if (dragOverColName !== col.name) {
2620
+ setDragOverColName(col.name);
2621
+ }
2622
+ },
2623
+ onDragLeave: () => {
2624
+ if (dragOverColName === col.name) {
2625
+ setDragOverColName(null);
2626
+ }
2627
+ },
2628
+ onDrop: (e) => {
2629
+ e.preventDefault();
2630
+ if (draggedColName && draggedColName !== col.name) {
2631
+ handleColumnReorder(draggedColName, col.name);
2632
+ }
2633
+ setDraggedColName(null);
2634
+ setDragOverColName(null);
2635
+ },
2636
+ onDragEnd: () => {
2637
+ setDraggedColName(null);
2638
+ setDragOverColName(null);
2639
+ },
2640
+ 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"}`,
2641
+ children: [
2642
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2643
+ "div",
2644
+ {
2645
+ onMouseDown: (e) => {
2646
+ e.preventDefault();
2647
+ e.stopPropagation();
2648
+ setResizingCol({ name: col.name, startWidth: currentWidth, startX: e.clientX });
2649
+ },
2650
+ className: "absolute left-0 top-0 bottom-0 w-1.5 cursor-col-resize hover:bg-brand active:bg-brand-hover z-20",
2651
+ title: "\u05E9\u05E0\u05D4 \u05D2\u05D5\u05D3\u05DC \u05E2\u05DE\u05D5\u05D3\u05D4"
2652
+ }
2653
+ ),
2654
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center justify-between gap-2 group overflow-hidden", title: "\u05D2\u05E8\u05D5\u05E8 \u05DC\u05E9\u05D9\u05E0\u05D5\u05D9 \u05E1\u05D3\u05E8 \u05D4\u05E2\u05DE\u05D5\u05D3\u05D4", children: [
2655
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "truncate", children: col.name }),
2656
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2657
+ "svg",
2658
+ {
2659
+ className: "w-3.5 h-3.5 text-slate-400 opacity-40 group-hover:opacity-100 transition-opacity shrink-0 cursor-grab",
2660
+ fill: "none",
2661
+ viewBox: "0 0 24 24",
2662
+ stroke: "currentColor",
2663
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M8 9h.01M8 15h.01M16 9h.01M16 15h.01" })
2664
+ }
2665
+ )
2666
+ ] })
2667
+ ]
2668
+ },
2669
+ col.name
2670
+ );
2671
+ }),
2672
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("th", { className: "w-full min-w-[50px] border-b border-slate-200 pointer-events-none" })
2673
+ ] }) }),
2674
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tbody", { className: "bg-white", children: (isStateEmpty || filteredData.length === 0) && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { colSpan: filteredColumns.length + 2, className: "text-center py-12 text-slate-400", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-col items-center justify-center gap-2", children: [
2675
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-8 h-8 text-slate-300", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", d: "M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4" }) }),
2676
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05DC\u05D4\u05E6\u05D2\u05D4." })
2677
+ ] }) }) }) : filteredData.map((row) => {
2678
+ const hasSubTableCols = filteredColumns.some((c) => {
1449
2679
  var _a;
1450
- const colType = ((_a = col.type) == null ? void 0 : _a.toUpperCase()) || "DEFAULT";
1451
- const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
1452
- let value = (row == null ? void 0 : row.data) ? row.data[col.name] : void 0;
1453
- if (value === void 0 && col.defaultValue !== void 0) {
1454
- value = colType === "CURRENCY" || colType === "NUMBER" ? parseFloat(col.defaultValue) : col.defaultValue;
1455
- if (colType === "CURRENCY" || colType === "NUMBER") {
1456
- if (isNaN(value)) value = null;
1457
- }
1458
- }
1459
- if (value === void 0) value = null;
1460
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-l border-slate-200 p-0 relative", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1461
- InputComponent,
2680
+ return ((_a = c.type) == null ? void 0 : _a.toUpperCase()) === "SUB_TABLE";
2681
+ });
2682
+ const isExpanded = expandedRowIds.has(row.id);
2683
+ const subTableColumns = filteredColumns.filter((c) => {
2684
+ var _a;
2685
+ return ((_a = c.type) == null ? void 0 : _a.toUpperCase()) === "SUB_TABLE";
2686
+ });
2687
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react7.default.Fragment, { children: [
2688
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("tr", { className: "hover:bg-blue-50/30 transition-colors group", children: [
2689
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "border-b border-l border-slate-200 p-1.5 text-center bg-white group-hover:bg-transparent", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center justify-center gap-1", children: [
2690
+ hasSubTableCols && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2691
+ "button",
2692
+ {
2693
+ type: "button",
2694
+ onClick: () => setExpandedRowIds((prev) => {
2695
+ const next = new Set(prev);
2696
+ if (next.has(row.id)) next.delete(row.id);
2697
+ else next.add(row.id);
2698
+ return next;
2699
+ }),
2700
+ className: "text-slate-400 hover:text-blue-600 p-0.5 rounded transition-colors cursor-pointer",
2701
+ title: isExpanded ? "\u05E1\u05D2\u05D5\u05E8 \u05EA\u05EA-\u05D8\u05D1\u05DC\u05D4" : "\u05E4\u05EA\u05D7 \u05EA\u05EA-\u05D8\u05D1\u05DC\u05D4",
2702
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("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__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M9 5l7 7-7 7" }) })
2703
+ }
2704
+ ),
2705
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2706
+ "input",
2707
+ {
2708
+ type: "checkbox",
2709
+ checked: selectedIds.has(row.id),
2710
+ onChange: (e) => toggleSelectRow(row.id, e.target.checked),
2711
+ disabled: isLoading || isUpdatingActive,
2712
+ className: "w-4 h-4 rounded border-slate-300 text-brand"
2713
+ }
2714
+ )
2715
+ ] }) }),
2716
+ filteredColumns.map((col) => {
2717
+ var _a;
2718
+ const colType = ((_a = col.type) == null ? void 0 : _a.toUpperCase()) || "DEFAULT";
2719
+ const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
2720
+ let value = (row == null ? void 0 : row.data) ? row.data[col.name] : void 0;
2721
+ if (value === void 0 && col.defaultValue !== void 0) {
2722
+ value = colType === "CURRENCY" || colType === "NUMBER" ? parseFloat(col.defaultValue) : col.defaultValue;
2723
+ if (colType === "CURRENCY" || colType === "NUMBER") {
2724
+ if (isNaN(value)) value = null;
2725
+ }
2726
+ }
2727
+ if (value === void 0) value = null;
2728
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "border-b border-l border-slate-200 p-0 relative", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2729
+ InputComponent,
2730
+ {
2731
+ value,
2732
+ column: col,
2733
+ rowId: row.id,
2734
+ onChange: (v) => handleCellChange(row.id, col.name, v),
2735
+ context: {
2736
+ 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",
2737
+ tableId: (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id),
2738
+ onMarkForDeletion: (fileId) => setPendingDeletions((prev) => [...prev, fileId]),
2739
+ relationOptions,
2740
+ refetchRelation,
2741
+ executeAction,
2742
+ emitEvent,
2743
+ pageState,
2744
+ componentId,
2745
+ orgId,
2746
+ updateQuietly: handleQuietCellChange,
2747
+ triggerSaveSuccess,
2748
+ rowData: row.data
2749
+ }
2750
+ }
2751
+ ) }, col.name);
2752
+ }),
2753
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "border-b border-slate-200 bg-white pointer-events-none" })
2754
+ ] }),
2755
+ isExpanded && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2756
+ ExpandedSubTables,
1462
2757
  {
1463
- value,
1464
- column: col,
1465
2758
  rowId: row.id,
1466
- onChange: (v) => handleCellChange(row.id, col.name, v),
2759
+ rowData: row.data,
2760
+ subTableColumns,
2761
+ filteredColumnsLength: filteredColumns.length,
2762
+ handleCellChange,
1467
2763
  context: {
1468
- 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",
1469
- onMarkForDeletion: (fileId) => setPendingDeletions((prev) => [...prev, fileId]),
1470
- relationOptions,
1471
- refetchRelation,
1472
2764
  executeAction,
1473
- emitEvent,
1474
- pageState,
1475
- componentId,
1476
- orgId
2765
+ orgId,
2766
+ parentTableId: (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id),
2767
+ tableId: (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id),
2768
+ rowData: row.data,
2769
+ updateQuietly: handleQuietCellChange,
2770
+ triggerSaveSuccess
1477
2771
  }
1478
2772
  }
1479
- ) }, col.name);
1480
- })
1481
- ] }, row.id)) })
2773
+ )
2774
+ ] }, row.id);
2775
+ }) }),
2776
+ showSummary && filteredData.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tfoot", { className: "bg-slate-50 border-t-2 border-slate-300 sticky bottom-0 z-10 shadow-[0_-2px_4px_rgba(0,0,0,0.02)]", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("tr", { children: [
2777
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "border-b border-l border-slate-200 p-1.5 text-center font-bold text-slate-600 text-xs", children: '\u05E1\u05D4"\u05DB' }),
2778
+ filteredColumns.map((col) => {
2779
+ var _a;
2780
+ const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
2781
+ const isNumeric = typeUpper === "CURRENCY" || typeUpper === "NUMBER";
2782
+ const total = columnTotals[col.name];
2783
+ let displayVal = "";
2784
+ if (isNumeric && total !== void 0) {
2785
+ displayVal = new Intl.NumberFormat("en-US").format(total);
2786
+ if (typeUpper === "CURRENCY") {
2787
+ const symbol = getCurrencySymbol(col.currencySymbol);
2788
+ displayVal = symbol ? `${symbol} ${displayVal}` : displayVal;
2789
+ }
2790
+ }
2791
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "border-b border-l border-slate-200 p-2 text-sm font-semibold text-slate-700 bg-slate-50 relative", children: isNumeric && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex items-center text-right justify-start", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "truncate", children: displayVal }) }) }, col.name);
2792
+ }),
2793
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "border-b border-slate-200 bg-slate-50 pointer-events-none" })
2794
+ ] }) })
2795
+ ] })
2796
+ ] }),
2797
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-col sm:flex-row items-center justify-between gap-3 px-4 py-3 bg-slate-50 border-t border-slate-200 text-xs text-slate-600 rounded-b-xl", children: [
2798
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-2", children: [
2799
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "font-medium text-slate-700", children: "\u05E9\u05D5\u05E8\u05D5\u05EA \u05DC\u05E2\u05DE\u05D5\u05D3:" }),
2800
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2801
+ "select",
2802
+ {
2803
+ value: limit,
2804
+ onChange: (e) => handleLimitChange(Number(e.target.value)),
2805
+ disabled: isLoading || isUpdatingActive,
2806
+ 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",
2807
+ children: [
2808
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: 20, children: "20" }),
2809
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: 50, children: "50" }),
2810
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: 100, children: "100" })
2811
+ ]
2812
+ }
2813
+ )
2814
+ ] }),
2815
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-4", children: [
2816
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "font-medium text-slate-600", children: [
2817
+ "\u05E2\u05DE\u05D5\u05D3 ",
2818
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { className: "text-slate-900", children: page }),
2819
+ " \u05DE\u05EA\u05D5\u05DA ",
2820
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { className: "text-slate-900", children: totalPages || 1 }),
2821
+ totalRecords > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "text-slate-500 font-normal", children: [
2822
+ " (",
2823
+ totalRecords,
2824
+ ' \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D1\u05E1\u05D4"\u05DB)'
2825
+ ] })
2826
+ ] }),
2827
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-1.5", children: [
2828
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2829
+ "button",
2830
+ {
2831
+ onClick: handlePrevPage,
2832
+ disabled: page <= 1 || isLoading || isUpdatingActive,
2833
+ 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",
2834
+ title: "\u05E2\u05DE\u05D5\u05D3 \u05E7\u05D5\u05D3\u05DD",
2835
+ children: "\u05D4\u05E7\u05D5\u05D3\u05DD"
2836
+ }
2837
+ ),
2838
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2839
+ "button",
2840
+ {
2841
+ onClick: handleNextPage,
2842
+ disabled: page >= totalPages || isLoading || isUpdatingActive,
2843
+ 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",
2844
+ title: "\u05E2\u05DE\u05D5\u05D3 \u05D4\u05D1\u05D0",
2845
+ children: "\u05D4\u05D1\u05D0"
2846
+ }
2847
+ )
2848
+ ] })
1482
2849
  ] })
1483
2850
  ] })
1484
2851
  ]
1485
2852
  }
1486
2853
  );
1487
2854
  }
2855
+ function ExpandedSubTables({
2856
+ rowId,
2857
+ rowData,
2858
+ subTableColumns,
2859
+ filteredColumnsLength,
2860
+ handleCellChange,
2861
+ context
2862
+ }) {
2863
+ var _a;
2864
+ const [activeTab, setActiveTab] = (0, import_react7.useState)((_a = subTableColumns[0]) == null ? void 0 : _a.name);
2865
+ if (subTableColumns.length === 0) return null;
2866
+ if (subTableColumns.length === 1) {
2867
+ const stCol = subTableColumns[0];
2868
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { colSpan: filteredColumnsLength + 2, className: "p-0 border-b border-slate-200 bg-slate-50/50", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2869
+ SubTableViewer,
2870
+ {
2871
+ rowId,
2872
+ column: stCol,
2873
+ value: (rowData == null ? void 0 : rowData[stCol.name]) || [],
2874
+ onChange: (newVal) => handleCellChange(rowId, stCol.name, newVal),
2875
+ context
2876
+ }
2877
+ ) }) });
2878
+ }
2879
+ const activeCol = subTableColumns.find((c) => c.name === activeTab) || subTableColumns[0];
2880
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("td", { colSpan: filteredColumnsLength + 2, className: "p-0 border-b border-slate-200 bg-slate-50/50 overflow-hidden", children: [
2881
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("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__ */ (0, import_jsx_runtime6.jsx)(
2882
+ "button",
2883
+ {
2884
+ type: "button",
2885
+ onClick: () => setActiveTab(col.name),
2886
+ 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"}`,
2887
+ children: col.name
2888
+ },
2889
+ col.name
2890
+ )) }),
2891
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "bg-white", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2892
+ SubTableViewer,
2893
+ {
2894
+ rowId,
2895
+ column: activeCol,
2896
+ value: (rowData == null ? void 0 : rowData[activeCol.name]) || [],
2897
+ onChange: (newVal) => handleCellChange(rowId, activeCol.name, newVal),
2898
+ context
2899
+ },
2900
+ activeCol.name
2901
+ ) })
2902
+ ] }) });
2903
+ }
1488
2904
 
1489
2905
  // src/components/TableBlock/TableBlock.tsx
1490
- var import_jsx_runtime6 = require("react/jsx-runtime");
2906
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1491
2907
  function TableBlock(props) {
1492
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TableBlockClient, __spreadValues({}, props));
2908
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TableBlockClient, __spreadValues({}, props));
1493
2909
  }
1494
2910
 
1495
2911
  // src/registry.ts