@universe-platform/ui 0.1.0-beta.5 → 0.1.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/globals.css +223 -2
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +599 -34
- package/dist/index.mjs +599 -34
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -742,15 +742,19 @@ var FORM_INPUTS = {
|
|
|
742
742
|
DATE: ({ value, onChange, column }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DatePickerCell, { value, onChange, column }),
|
|
743
743
|
CURRENCY: ({ value, column, onChange }) => {
|
|
744
744
|
const symbol = getCurrencySymbol(column.currencySymbol);
|
|
745
|
+
const [isFocused, setIsFocused] = import_react5.default.useState(false);
|
|
746
|
+
const displayValue = !isFocused && value !== void 0 && value !== null && value !== "" && !isNaN(Number(value)) ? new Intl.NumberFormat("en-US").format(Number(value)) : value !== void 0 && value !== null ? value : "";
|
|
745
747
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "relative w-full h-full", children: [
|
|
746
748
|
symbol && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "absolute left-2 top-1/2 -translate-y-1/2 text-slate-400 pointer-events-none text-sm", children: symbol }),
|
|
747
749
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
748
750
|
"input",
|
|
749
751
|
{
|
|
750
|
-
type: "number",
|
|
752
|
+
type: isFocused ? "number" : "text",
|
|
751
753
|
step: "any",
|
|
752
754
|
className: `w-full h-8 ${symbol ? "pl-6 pr-2" : "px-2"} bg-transparent focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 text-sm`,
|
|
753
|
-
value:
|
|
755
|
+
value: displayValue,
|
|
756
|
+
onFocus: () => setIsFocused(true),
|
|
757
|
+
onBlur: () => setIsFocused(false),
|
|
754
758
|
onChange: (e) => {
|
|
755
759
|
const val = e.target.value;
|
|
756
760
|
onChange(val === "" ? "" : Number(val));
|
|
@@ -901,6 +905,7 @@ var FORM_INPUTS = {
|
|
|
901
905
|
};
|
|
902
906
|
|
|
903
907
|
// src/components/TableBlock/TableBlockClient.tsx
|
|
908
|
+
var import_lucide_react4 = require("lucide-react");
|
|
904
909
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
905
910
|
function TableBlockClient({
|
|
906
911
|
data: initialRecords,
|
|
@@ -918,6 +923,68 @@ function TableBlockClient({
|
|
|
918
923
|
"data-testid": dataTestId
|
|
919
924
|
}) {
|
|
920
925
|
const { showError, addToast } = useToast();
|
|
926
|
+
const [columnWidths, setColumnWidths] = (0, import_react6.useState)({});
|
|
927
|
+
const [isMounted, setIsMounted] = (0, import_react6.useState)(false);
|
|
928
|
+
const tableKey = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id) || (schema == null ? void 0 : schema.name) || "default";
|
|
929
|
+
const [page, setPage] = (0, import_react6.useState)(1);
|
|
930
|
+
const [limit, setLimit] = (0, import_react6.useState)(50);
|
|
931
|
+
const [totalRecords, setTotalRecords] = (0, import_react6.useState)(0);
|
|
932
|
+
const [totalPages, setTotalPages] = (0, import_react6.useState)(1);
|
|
933
|
+
(0, import_react6.useEffect)(() => {
|
|
934
|
+
if (typeof window !== "undefined") {
|
|
935
|
+
const savedWidths = localStorage.getItem(`table_widths_${tableKey}`);
|
|
936
|
+
if (savedWidths) {
|
|
937
|
+
try {
|
|
938
|
+
setColumnWidths(JSON.parse(savedWidths));
|
|
939
|
+
} catch (e) {
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
const savedSummary = localStorage.getItem(`table_summary_${tableKey}`);
|
|
943
|
+
if (savedSummary !== null) {
|
|
944
|
+
setShowSummary(savedSummary === "true");
|
|
945
|
+
}
|
|
946
|
+
const savedLimit = localStorage.getItem(`table_limit_${tableKey}`);
|
|
947
|
+
if (savedLimit) {
|
|
948
|
+
const parsed = parseInt(savedLimit, 10);
|
|
949
|
+
if ([20, 50, 100].includes(parsed)) {
|
|
950
|
+
setLimit(parsed);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
setIsMounted(true);
|
|
955
|
+
}, [tableKey]);
|
|
956
|
+
const [showSummary, setShowSummary] = (0, import_react6.useState)(false);
|
|
957
|
+
const toggleSummary = () => {
|
|
958
|
+
setShowSummary((prev) => {
|
|
959
|
+
const next = !prev;
|
|
960
|
+
const tableKey2 = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id) || (schema == null ? void 0 : schema.name) || "default";
|
|
961
|
+
localStorage.setItem(`table_summary_${tableKey2}`, String(next));
|
|
962
|
+
return next;
|
|
963
|
+
});
|
|
964
|
+
};
|
|
965
|
+
const [resizingCol, setResizingCol] = (0, import_react6.useState)(null);
|
|
966
|
+
(0, import_react6.useEffect)(() => {
|
|
967
|
+
if (!resizingCol) return;
|
|
968
|
+
const handleMouseMove = (e) => {
|
|
969
|
+
const diffX = resizingCol.startX - e.clientX;
|
|
970
|
+
const newWidth = Math.max(100, Math.min(500, resizingCol.startWidth + diffX));
|
|
971
|
+
setColumnWidths((prev) => __spreadProps(__spreadValues({}, prev), { [resizingCol.name]: newWidth }));
|
|
972
|
+
};
|
|
973
|
+
const handleMouseUp = () => {
|
|
974
|
+
setResizingCol(null);
|
|
975
|
+
setColumnWidths((prev) => {
|
|
976
|
+
const tableKey2 = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id) || (schema == null ? void 0 : schema.name) || "default";
|
|
977
|
+
localStorage.setItem(`table_widths_${tableKey2}`, JSON.stringify(prev));
|
|
978
|
+
return prev;
|
|
979
|
+
});
|
|
980
|
+
};
|
|
981
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
982
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
983
|
+
return () => {
|
|
984
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
985
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
986
|
+
};
|
|
987
|
+
}, [resizingCol, schema]);
|
|
921
988
|
const normalizeRecords = (records) => {
|
|
922
989
|
return (records || []).map((row) => {
|
|
923
990
|
var _c;
|
|
@@ -943,12 +1010,32 @@ function TableBlockClient({
|
|
|
943
1010
|
return __spreadProps(__spreadValues({}, row), { id: String(row.id || ""), data: rowData });
|
|
944
1011
|
});
|
|
945
1012
|
};
|
|
1013
|
+
const mergeColumnDefs = (0, import_react6.useCallback)((existingCols, incomingCols) => {
|
|
1014
|
+
if (!incomingCols || incomingCols.length === 0) return existingCols || [];
|
|
1015
|
+
if (!existingCols || existingCols.length === 0) return incomingCols;
|
|
1016
|
+
const existingMap = new Map(existingCols.map((c) => [c.name, c]));
|
|
1017
|
+
const merged = incomingCols.map((inc) => {
|
|
1018
|
+
const ext = existingMap.get(inc.name);
|
|
1019
|
+
if (ext) {
|
|
1020
|
+
existingMap.delete(inc.name);
|
|
1021
|
+
return __spreadValues(__spreadValues({}, ext), inc);
|
|
1022
|
+
}
|
|
1023
|
+
return inc;
|
|
1024
|
+
});
|
|
1025
|
+
for (const [, extCol] of existingMap) {
|
|
1026
|
+
merged.push(extCol);
|
|
1027
|
+
}
|
|
1028
|
+
return merged.sort((a, b) => {
|
|
1029
|
+
var _a, _b;
|
|
1030
|
+
return ((_a = a.order) != null ? _a : 0) - ((_b = b.order) != null ? _b : 0);
|
|
1031
|
+
});
|
|
1032
|
+
}, []);
|
|
946
1033
|
const [localColumns, setLocalColumns] = (0, import_react6.useState)(() => (schema == null ? void 0 : schema.columns) || []);
|
|
947
1034
|
(0, import_react6.useEffect)(() => {
|
|
948
1035
|
if ((schema == null ? void 0 : schema.columns) && schema.columns.length > 0) {
|
|
949
|
-
setLocalColumns(schema.columns);
|
|
1036
|
+
setLocalColumns((prev) => mergeColumnDefs(prev, schema.columns));
|
|
950
1037
|
}
|
|
951
|
-
}, [schema == null ? void 0 : schema.columns]);
|
|
1038
|
+
}, [schema == null ? void 0 : schema.columns, mergeColumnDefs]);
|
|
952
1039
|
const [dirty, setDirty] = (0, import_react6.useState)({ added: [], modified: {}, deleted: [] });
|
|
953
1040
|
const dirtyRef = (0, import_react6.useRef)(dirty);
|
|
954
1041
|
(0, import_react6.useEffect)(() => {
|
|
@@ -995,29 +1082,57 @@ function TableBlockClient({
|
|
|
995
1082
|
setBaseRecordsMap(map);
|
|
996
1083
|
}
|
|
997
1084
|
}, [initialRecords]);
|
|
998
|
-
(0, import_react6.
|
|
1085
|
+
const refetchTableData = (0, import_react6.useCallback)((targetPage) => {
|
|
999
1086
|
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
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1087
|
+
if (!tableId || !executeAction) return Promise.resolve();
|
|
1088
|
+
const activePage = targetPage !== void 0 ? targetPage : page;
|
|
1089
|
+
const skip = (activePage - 1) * limit;
|
|
1090
|
+
return executeAction("FETCH_TABLE_DATA", { tableId, page: activePage, limit, skip }).then((res) => {
|
|
1091
|
+
var _a;
|
|
1092
|
+
if (res) {
|
|
1093
|
+
if (((_a = res.schema) == null ? void 0 : _a.columns) && res.schema.columns.length > 0) {
|
|
1094
|
+
setLocalColumns((prev) => mergeColumnDefs(prev, res.schema.columns));
|
|
1095
|
+
}
|
|
1096
|
+
if (res.records && Array.isArray(res.records)) {
|
|
1097
|
+
const norm = normalizeRecords(res.records);
|
|
1098
|
+
const map = /* @__PURE__ */ new Map();
|
|
1099
|
+
norm.forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
|
|
1100
|
+
setBaseRecordsMap(map);
|
|
1101
|
+
setData(norm);
|
|
1102
|
+
}
|
|
1103
|
+
if (res.meta) {
|
|
1104
|
+
const total = typeof res.meta.totalRecords === "number" ? res.meta.totalRecords : 0;
|
|
1105
|
+
const pages = typeof res.meta.totalPages === "number" ? res.meta.totalPages : Math.ceil(total / limit) || 1;
|
|
1106
|
+
setTotalRecords(total);
|
|
1107
|
+
setTotalPages(pages);
|
|
1108
|
+
if (activePage > pages && pages >= 1) {
|
|
1109
|
+
setPage(pages);
|
|
1014
1110
|
}
|
|
1111
|
+
} else if (res.records && Array.isArray(res.records)) {
|
|
1112
|
+
setTotalRecords(res.records.length);
|
|
1113
|
+
setTotalPages(Math.ceil(res.records.length / limit) || 1);
|
|
1015
1114
|
}
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
|
|
1115
|
+
}
|
|
1116
|
+
}).catch((err) => {
|
|
1117
|
+
console.error("[TableBlock] Failed to auto-fetch table data:", err);
|
|
1118
|
+
});
|
|
1119
|
+
}, [schema == null ? void 0 : schema.tableMetaId, schema == null ? void 0 : schema.tableId, schema == null ? void 0 : schema.id, page, limit, executeAction, mergeWithDirty, mergeColumnDefs]);
|
|
1120
|
+
(0, import_react6.useEffect)(() => {
|
|
1121
|
+
refetchTableData();
|
|
1122
|
+
}, [refetchTableData]);
|
|
1123
|
+
const handleLimitChange = (newLimit) => {
|
|
1124
|
+
setLimit(newLimit);
|
|
1125
|
+
setPage(1);
|
|
1126
|
+
if (typeof window !== "undefined") {
|
|
1127
|
+
localStorage.setItem(`table_limit_${tableKey}`, String(newLimit));
|
|
1019
1128
|
}
|
|
1020
|
-
}
|
|
1129
|
+
};
|
|
1130
|
+
const handlePrevPage = () => {
|
|
1131
|
+
setPage((prev) => Math.max(1, prev - 1));
|
|
1132
|
+
};
|
|
1133
|
+
const handleNextPage = () => {
|
|
1134
|
+
setPage((prev) => Math.min(totalPages, prev + 1));
|
|
1135
|
+
};
|
|
1021
1136
|
(0, import_react6.useEffect)(() => {
|
|
1022
1137
|
if (error) {
|
|
1023
1138
|
showError(error, "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E8\u05DB\u05D9\u05D1");
|
|
@@ -1064,10 +1179,144 @@ function TableBlockClient({
|
|
|
1064
1179
|
refetchRelation(col.name);
|
|
1065
1180
|
});
|
|
1066
1181
|
}, [schemaColsString, refetchRelation]);
|
|
1182
|
+
const normalizedColumns = (0, import_react6.useMemo)(() => {
|
|
1183
|
+
return (localColumns || []).map((col, idx) => {
|
|
1184
|
+
const isRequired = col.isRequired === true || String(col.isRequired) === "true";
|
|
1185
|
+
const isUnique = col.isUnique === true || String(col.isUnique) === "true";
|
|
1186
|
+
const isProtected = isRequired || isUnique;
|
|
1187
|
+
return __spreadProps(__spreadValues({}, col), {
|
|
1188
|
+
order: typeof col.order === "number" ? col.order : idx,
|
|
1189
|
+
isHidden: isProtected ? false : Boolean(col.isHidden)
|
|
1190
|
+
});
|
|
1191
|
+
}).sort((a, b) => {
|
|
1192
|
+
var _a, _b;
|
|
1193
|
+
return ((_a = a.order) != null ? _a : 0) - ((_b = b.order) != null ? _b : 0);
|
|
1194
|
+
});
|
|
1195
|
+
}, [localColumns]);
|
|
1067
1196
|
const filteredColumns = (0, import_react6.useMemo)(() => {
|
|
1068
1197
|
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
1069
|
-
return
|
|
1070
|
-
}, [
|
|
1198
|
+
return normalizedColumns.filter((col) => !systemFields.includes(col.name) && !col.isHidden);
|
|
1199
|
+
}, [normalizedColumns]);
|
|
1200
|
+
const customizableColumns = (0, import_react6.useMemo)(() => {
|
|
1201
|
+
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
1202
|
+
return normalizedColumns.filter((col) => !systemFields.includes(col.name));
|
|
1203
|
+
}, [normalizedColumns]);
|
|
1204
|
+
const [isColumnsDropdownOpen, setIsColumnsDropdownOpen] = (0, import_react6.useState)(false);
|
|
1205
|
+
const dropdownRef = (0, import_react6.useRef)(null);
|
|
1206
|
+
(0, import_react6.useEffect)(() => {
|
|
1207
|
+
const handleClickOutside = (e) => {
|
|
1208
|
+
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
1209
|
+
setIsColumnsDropdownOpen(false);
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
if (isColumnsDropdownOpen) {
|
|
1213
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
1214
|
+
}
|
|
1215
|
+
return () => {
|
|
1216
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
1217
|
+
};
|
|
1218
|
+
}, [isColumnsDropdownOpen]);
|
|
1219
|
+
const handleShowAllColumns = async () => {
|
|
1220
|
+
var _a;
|
|
1221
|
+
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
1222
|
+
const systemCols = (localColumns || []).filter((c) => systemFields.includes(c.name));
|
|
1223
|
+
const updatedCustomCols = customizableColumns.map((col) => __spreadProps(__spreadValues({}, col), {
|
|
1224
|
+
isHidden: false
|
|
1225
|
+
}));
|
|
1226
|
+
const fullUpdatedColumns = [...systemCols, ...updatedCustomCols];
|
|
1227
|
+
setLocalColumns(fullUpdatedColumns);
|
|
1228
|
+
const targetTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
|
|
1229
|
+
if (targetTableId && executeAction) {
|
|
1230
|
+
try {
|
|
1231
|
+
const res = await executeAction("UPDATE_TABLE_COLUMNS", {
|
|
1232
|
+
tableId: targetTableId,
|
|
1233
|
+
tableMetaId: targetTableId,
|
|
1234
|
+
columns: fullUpdatedColumns
|
|
1235
|
+
});
|
|
1236
|
+
const returnedCols = (res == null ? void 0 : res.columns) || ((_a = res == null ? void 0 : res.data) == null ? void 0 : _a.columns);
|
|
1237
|
+
if (returnedCols && Array.isArray(returnedCols)) {
|
|
1238
|
+
setLocalColumns((prev) => mergeColumnDefs(prev, returnedCols));
|
|
1239
|
+
}
|
|
1240
|
+
} catch (err) {
|
|
1241
|
+
console.error("[TableBlock] Failed to save show all columns:", err);
|
|
1242
|
+
showError((err == null ? void 0 : err.message) || String(err), "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05D4\u05E6\u05D2\u05EA \u05DB\u05DC \u05D4\u05E2\u05DE\u05D5\u05D3\u05D5\u05EA");
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
};
|
|
1246
|
+
const handleToggleColumnVisibility = async (colName, isVisible) => {
|
|
1247
|
+
var _a;
|
|
1248
|
+
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
1249
|
+
const systemCols = (localColumns || []).filter((c) => systemFields.includes(c.name));
|
|
1250
|
+
const updatedCustomCols = customizableColumns.map((col) => {
|
|
1251
|
+
const isRequired = col.isRequired === true || String(col.isRequired) === "true";
|
|
1252
|
+
const isUnique = col.isUnique === true || String(col.isUnique) === "true";
|
|
1253
|
+
const isProtected = isRequired || isUnique;
|
|
1254
|
+
if (col.name === colName) {
|
|
1255
|
+
if (isProtected) {
|
|
1256
|
+
return __spreadProps(__spreadValues({}, col), { isHidden: false });
|
|
1257
|
+
}
|
|
1258
|
+
return __spreadProps(__spreadValues({}, col), { isHidden: !isVisible });
|
|
1259
|
+
}
|
|
1260
|
+
return __spreadProps(__spreadValues({}, col), {
|
|
1261
|
+
isHidden: isProtected ? false : Boolean(col.isHidden)
|
|
1262
|
+
});
|
|
1263
|
+
});
|
|
1264
|
+
const fullUpdatedColumns = [...systemCols, ...updatedCustomCols];
|
|
1265
|
+
setLocalColumns(fullUpdatedColumns);
|
|
1266
|
+
const targetTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
|
|
1267
|
+
if (targetTableId && executeAction) {
|
|
1268
|
+
try {
|
|
1269
|
+
const res = await executeAction("UPDATE_TABLE_COLUMNS", {
|
|
1270
|
+
tableId: targetTableId,
|
|
1271
|
+
tableMetaId: targetTableId,
|
|
1272
|
+
columns: fullUpdatedColumns
|
|
1273
|
+
});
|
|
1274
|
+
const returnedCols = (res == null ? void 0 : res.columns) || ((_a = res == null ? void 0 : res.data) == null ? void 0 : _a.columns);
|
|
1275
|
+
if (returnedCols && Array.isArray(returnedCols)) {
|
|
1276
|
+
setLocalColumns((prev) => mergeColumnDefs(prev, returnedCols));
|
|
1277
|
+
}
|
|
1278
|
+
} catch (err) {
|
|
1279
|
+
console.error("[TableBlock] Failed to save column visibility:", err);
|
|
1280
|
+
showError((err == null ? void 0 : err.message) || String(err), "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E2\u05D3\u05DB\u05D5\u05DF \u05D4\u05E1\u05EA\u05E8\u05EA \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA");
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
};
|
|
1284
|
+
const [draggedColName, setDraggedColName] = (0, import_react6.useState)(null);
|
|
1285
|
+
const [dragOverColName, setDragOverColName] = (0, import_react6.useState)(null);
|
|
1286
|
+
const handleColumnReorder = async (draggedName, dropTargetName) => {
|
|
1287
|
+
var _a;
|
|
1288
|
+
if (draggedName === dropTargetName) return;
|
|
1289
|
+
const currentCustomCols = [...customizableColumns];
|
|
1290
|
+
const fromIndex = currentCustomCols.findIndex((c) => c.name === draggedName);
|
|
1291
|
+
const toIndex = currentCustomCols.findIndex((c) => c.name === dropTargetName);
|
|
1292
|
+
if (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) return;
|
|
1293
|
+
const [draggedItem] = currentCustomCols.splice(fromIndex, 1);
|
|
1294
|
+
currentCustomCols.splice(toIndex, 0, draggedItem);
|
|
1295
|
+
const updatedCustomCols = currentCustomCols.map((col, idx) => __spreadProps(__spreadValues({}, col), {
|
|
1296
|
+
order: idx
|
|
1297
|
+
}));
|
|
1298
|
+
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
1299
|
+
const systemCols = (localColumns || []).filter((c) => systemFields.includes(c.name));
|
|
1300
|
+
const fullUpdatedColumns = [...systemCols, ...updatedCustomCols];
|
|
1301
|
+
setLocalColumns(fullUpdatedColumns);
|
|
1302
|
+
const targetTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
|
|
1303
|
+
if (targetTableId && executeAction) {
|
|
1304
|
+
try {
|
|
1305
|
+
const res = await executeAction("UPDATE_TABLE_COLUMNS", {
|
|
1306
|
+
tableId: targetTableId,
|
|
1307
|
+
tableMetaId: targetTableId,
|
|
1308
|
+
columns: fullUpdatedColumns
|
|
1309
|
+
});
|
|
1310
|
+
const returnedCols = (res == null ? void 0 : res.columns) || ((_a = res == null ? void 0 : res.data) == null ? void 0 : _a.columns);
|
|
1311
|
+
if (returnedCols && Array.isArray(returnedCols)) {
|
|
1312
|
+
setLocalColumns((prev) => mergeColumnDefs(prev, returnedCols));
|
|
1313
|
+
}
|
|
1314
|
+
} catch (err) {
|
|
1315
|
+
console.error("[TableBlock] Failed to save column reorder:", err);
|
|
1316
|
+
showError((err == null ? void 0 : err.message) || String(err), "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E2\u05D3\u05DB\u05D5\u05DF \u05E1\u05D3\u05E8 \u05D4\u05E2\u05DE\u05D5\u05D3\u05D5\u05EA");
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
};
|
|
1071
1320
|
const generateTempId = () => `temp_${Math.random().toString(36).substr(2, 9)}`;
|
|
1072
1321
|
const handleAddRow = () => {
|
|
1073
1322
|
const defaultData = {};
|
|
@@ -1097,6 +1346,34 @@ function TableBlockClient({
|
|
|
1097
1346
|
setData((prev) => [newRow, ...prev]);
|
|
1098
1347
|
setDirty((prev) => __spreadProps(__spreadValues({}, prev), { added: [newRow, ...prev.added] }));
|
|
1099
1348
|
};
|
|
1349
|
+
const handleDuplicateRow = () => {
|
|
1350
|
+
if (selectedIds.size !== 1) return;
|
|
1351
|
+
const targetId = Array.from(selectedIds)[0];
|
|
1352
|
+
const sourceRow = data.find((r) => r.id === targetId);
|
|
1353
|
+
if (!sourceRow) return;
|
|
1354
|
+
const uniqueColNames = new Set(
|
|
1355
|
+
(localColumns || []).filter((c) => c.isUnique === true || String(c.isUnique) === "true").map((c) => c.name)
|
|
1356
|
+
);
|
|
1357
|
+
const fieldsToScrub = /* @__PURE__ */ new Set(["id", "_id", "createdAt", "updatedAt", "created_at", "updated_at"]);
|
|
1358
|
+
const clonedData = __spreadValues({}, sourceRow.data);
|
|
1359
|
+
Object.keys(clonedData).forEach((key) => {
|
|
1360
|
+
var _a;
|
|
1361
|
+
if (fieldsToScrub.has(key) || uniqueColNames.has(key)) {
|
|
1362
|
+
const col = (localColumns || []).find((c) => c.name === key);
|
|
1363
|
+
const typeUpper = (_a = col == null ? void 0 : col.type) == null ? void 0 : _a.toUpperCase();
|
|
1364
|
+
if (typeUpper === "NUMBER" || typeUpper === "CURRENCY") {
|
|
1365
|
+
clonedData[key] = 0;
|
|
1366
|
+
} else if (typeUpper === "BOOLEAN") {
|
|
1367
|
+
clonedData[key] = false;
|
|
1368
|
+
} else {
|
|
1369
|
+
clonedData[key] = "";
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
});
|
|
1373
|
+
const newRow = { id: generateTempId(), data: clonedData };
|
|
1374
|
+
setData((prev) => [newRow, ...prev]);
|
|
1375
|
+
setDirty((prev) => __spreadProps(__spreadValues({}, prev), { added: [newRow, ...prev.added] }));
|
|
1376
|
+
};
|
|
1100
1377
|
const handleCellChange = (rowId, colName, value) => {
|
|
1101
1378
|
setData((prev) => prev.map(
|
|
1102
1379
|
(row) => row.id === rowId ? __spreadProps(__spreadValues({}, row), { data: __spreadProps(__spreadValues({}, row.data), { [colName]: value }) }) : row
|
|
@@ -1317,6 +1594,7 @@ function TableBlockClient({
|
|
|
1317
1594
|
return next;
|
|
1318
1595
|
});
|
|
1319
1596
|
setDirty({ added: [], modified: {}, deleted: [] });
|
|
1597
|
+
await refetchTableData();
|
|
1320
1598
|
setIsSaveSuccess(true);
|
|
1321
1599
|
setTimeout(() => {
|
|
1322
1600
|
setIsSaveSuccess(false);
|
|
@@ -1340,12 +1618,30 @@ function TableBlockClient({
|
|
|
1340
1618
|
}, [data, searchQuery]);
|
|
1341
1619
|
const isUpdatingActive = Boolean(isUpdating || isSaving);
|
|
1342
1620
|
const errorMessage = error ? typeof error === "string" ? error : error.message || String(error) : null;
|
|
1621
|
+
const columnTotals = (0, import_react6.useMemo)(() => {
|
|
1622
|
+
const totals = {};
|
|
1623
|
+
if (!showSummary) return totals;
|
|
1624
|
+
filteredColumns.forEach((col) => {
|
|
1625
|
+
var _a;
|
|
1626
|
+
const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
|
|
1627
|
+
if (typeUpper === "CURRENCY" || typeUpper === "NUMBER") {
|
|
1628
|
+
const sum = filteredData.reduce((acc, row) => {
|
|
1629
|
+
var _a2;
|
|
1630
|
+
const val = (_a2 = row.data) == null ? void 0 : _a2[col.name];
|
|
1631
|
+
const num = Number(val);
|
|
1632
|
+
return acc + (isNaN(num) ? 0 : num);
|
|
1633
|
+
}, 0);
|
|
1634
|
+
totals[col.name] = sum;
|
|
1635
|
+
}
|
|
1636
|
+
});
|
|
1637
|
+
return totals;
|
|
1638
|
+
}, [filteredData, filteredColumns, showSummary]);
|
|
1343
1639
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1344
1640
|
"div",
|
|
1345
1641
|
{
|
|
1346
1642
|
id: componentId,
|
|
1347
1643
|
"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}`,
|
|
1644
|
+
className: `flex flex-col w-full bg-white border border-slate-200 rounded-xl shadow-xs min-h-[350px] overflow-hidden ${className}`,
|
|
1349
1645
|
dir: "rtl",
|
|
1350
1646
|
children: [
|
|
1351
1647
|
errorMessage && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "p-3 bg-rose-50 border-b border-rose-200 text-rose-700 text-sm flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
@@ -1365,6 +1661,16 @@ function TableBlockClient({
|
|
|
1365
1661
|
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4.5 h-4.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M12 4v16m8-8H4" }) })
|
|
1366
1662
|
}
|
|
1367
1663
|
),
|
|
1664
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1665
|
+
"button",
|
|
1666
|
+
{
|
|
1667
|
+
onClick: handleDuplicateRow,
|
|
1668
|
+
disabled: isLoading || isUpdatingActive || selectedIds.size !== 1,
|
|
1669
|
+
className: "w-9 h-9 bg-blue-50 hover:bg-blue-100 border border-blue-200 text-blue-700 rounded-lg shadow-2xs flex items-center justify-center transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer",
|
|
1670
|
+
title: "\u05E9\u05DB\u05E4\u05DC \u05E9\u05D5\u05E8\u05D4 \u05E0\u05D1\u05D7\u05E8\u05EA",
|
|
1671
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react4.Copy, { className: "w-4 h-4 text-blue-600 shrink-0" })
|
|
1672
|
+
}
|
|
1673
|
+
),
|
|
1368
1674
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1369
1675
|
"button",
|
|
1370
1676
|
{
|
|
@@ -1378,6 +1684,112 @@ function TableBlockClient({
|
|
|
1378
1684
|
]
|
|
1379
1685
|
}
|
|
1380
1686
|
),
|
|
1687
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1688
|
+
"button",
|
|
1689
|
+
{
|
|
1690
|
+
onClick: toggleSummary,
|
|
1691
|
+
disabled: isLoading || isUpdatingActive,
|
|
1692
|
+
className: `h-9 px-3 border font-semibold rounded-lg shadow-2xs flex items-center gap-1.5 text-xs transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer ${showSummary ? "bg-indigo-50 border-indigo-200 text-indigo-700 hover:bg-indigo-100" : "bg-white border-slate-300 text-slate-700 hover:bg-slate-100"}`,
|
|
1693
|
+
title: "\u05D4\u05E6\u05D2/\u05D4\u05E1\u05EA\u05E8 \u05E9\u05D5\u05E8\u05EA \u05E1\u05D9\u05DB\u05D5\u05DD",
|
|
1694
|
+
children: [
|
|
1695
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) }),
|
|
1696
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "hidden sm:inline", children: "\u05E1\u05DB\u05D9\u05DE\u05D4" })
|
|
1697
|
+
]
|
|
1698
|
+
}
|
|
1699
|
+
),
|
|
1700
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "relative", ref: dropdownRef, children: [
|
|
1701
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1702
|
+
"button",
|
|
1703
|
+
{
|
|
1704
|
+
onClick: () => setIsColumnsDropdownOpen((prev) => !prev),
|
|
1705
|
+
disabled: isLoading || isUpdatingActive,
|
|
1706
|
+
className: "h-9 px-3 bg-white hover:bg-slate-100 border border-slate-300 text-slate-700 font-semibold rounded-lg shadow-2xs flex items-center gap-1.5 text-xs transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer",
|
|
1707
|
+
title: "\u05D4\u05E6\u05D2/\u05D4\u05E1\u05EA\u05E8 \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA",
|
|
1708
|
+
children: [
|
|
1709
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4 h-4 text-slate-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2" }) }),
|
|
1710
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: `w-3.5 h-3.5 text-slate-500 transition-transform ${isColumnsDropdownOpen ? "rotate-180" : ""}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M19 9l-7 7-7-7" }) })
|
|
1711
|
+
]
|
|
1712
|
+
}
|
|
1713
|
+
),
|
|
1714
|
+
isColumnsDropdownOpen && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "absolute right-0 top-full mt-1.5 w-56 bg-white border border-slate-200 rounded-xl shadow-xl z-50 p-1.5 dir-rtl animate-in fade-in slide-in-from-top-2 duration-150", children: [
|
|
1715
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "px-2 py-1.5 text-xs font-bold text-slate-500 border-b border-slate-100 mb-1 flex items-center justify-between", children: [
|
|
1716
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
1717
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u05D4\u05E6\u05D2\u05EA \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA" }),
|
|
1718
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-[10px] font-normal text-slate-400", children: [
|
|
1719
|
+
"(",
|
|
1720
|
+
customizableColumns.filter((c) => !c.isHidden).length,
|
|
1721
|
+
"/",
|
|
1722
|
+
customizableColumns.length,
|
|
1723
|
+
")"
|
|
1724
|
+
] })
|
|
1725
|
+
] }),
|
|
1726
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1727
|
+
"button",
|
|
1728
|
+
{
|
|
1729
|
+
type: "button",
|
|
1730
|
+
onClick: handleShowAllColumns,
|
|
1731
|
+
className: "text-xs text-brand hover:text-brand-hover font-semibold hover:underline cursor-pointer",
|
|
1732
|
+
children: "\u05D4\u05E6\u05D2 \u05D4\u05DB\u05DC"
|
|
1733
|
+
}
|
|
1734
|
+
)
|
|
1735
|
+
] }),
|
|
1736
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "max-h-60 overflow-y-auto space-y-0.5", children: customizableColumns.map((col) => {
|
|
1737
|
+
const isRequired = col.isRequired === true || String(col.isRequired) === "true";
|
|
1738
|
+
const isUnique = col.isUnique === true || String(col.isUnique) === "true";
|
|
1739
|
+
const isProtected = isRequired || isUnique;
|
|
1740
|
+
const isVisible = !col.isHidden;
|
|
1741
|
+
let protectedExplanation = "";
|
|
1742
|
+
if (isRequired && isUnique) {
|
|
1743
|
+
protectedExplanation = "\u05E9\u05D3\u05D4 \u05D7\u05D5\u05D1\u05D4 \u05D5\u05D9\u05D9\u05D7\u05D5\u05D3\u05D9 - \u05DC\u05D0 \u05E0\u05D9\u05EA\u05DF \u05DC\u05D4\u05D5\u05E8\u05D9\u05D3 \u05E2\u05DE\u05D5\u05D3\u05D4 \u05D6\u05D5 \u05DE\u05D4\u05EA\u05E6\u05D5\u05D2\u05D4";
|
|
1744
|
+
} else if (isRequired) {
|
|
1745
|
+
protectedExplanation = "\u05E9\u05D3\u05D4 \u05D7\u05D5\u05D1\u05D4 - \u05DC\u05D0 \u05E0\u05D9\u05EA\u05DF \u05DC\u05D4\u05D5\u05E8\u05D9\u05D3 \u05E2\u05DE\u05D5\u05D3\u05D4 \u05D6\u05D5 \u05DE\u05D4\u05EA\u05E6\u05D5\u05D2\u05D4";
|
|
1746
|
+
} else if (isUnique) {
|
|
1747
|
+
protectedExplanation = "\u05E9\u05D3\u05D4 \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9 - \u05DC\u05D0 \u05E0\u05D9\u05EA\u05DF \u05DC\u05D4\u05D5\u05E8\u05D9\u05D3 \u05E2\u05DE\u05D5\u05D3\u05D4 \u05D6\u05D5 \u05DE\u05D4\u05EA\u05E6\u05D5\u05D2\u05D4";
|
|
1748
|
+
}
|
|
1749
|
+
const badgeLabel = isRequired && isUnique ? "\u05D7\u05D5\u05D1\u05D4 + \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9" : isRequired ? "\u05E9\u05D3\u05D4 \u05D7\u05D5\u05D1\u05D4" : "\u05E9\u05D3\u05D4 \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9";
|
|
1750
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1751
|
+
"div",
|
|
1752
|
+
{
|
|
1753
|
+
onClick: () => {
|
|
1754
|
+
if (!isProtected) {
|
|
1755
|
+
handleToggleColumnVisibility(col.name, !isVisible);
|
|
1756
|
+
}
|
|
1757
|
+
},
|
|
1758
|
+
title: isProtected ? protectedExplanation : void 0,
|
|
1759
|
+
className: `group flex items-center justify-between px-2.5 py-1.5 rounded-lg text-xs transition-colors select-none ${isProtected ? "opacity-75 bg-slate-50 border border-slate-100/70 cursor-not-allowed" : "hover:bg-slate-100 active:bg-slate-200 cursor-pointer"}`,
|
|
1760
|
+
children: [
|
|
1761
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
1762
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1763
|
+
"input",
|
|
1764
|
+
{
|
|
1765
|
+
type: "checkbox",
|
|
1766
|
+
checked: isVisible,
|
|
1767
|
+
disabled: isProtected,
|
|
1768
|
+
onChange: () => {
|
|
1769
|
+
},
|
|
1770
|
+
className: "w-3.5 h-3.5 rounded border-slate-300 text-brand focus:ring-brand/20 cursor-pointer disabled:cursor-not-allowed disabled:opacity-60"
|
|
1771
|
+
}
|
|
1772
|
+
),
|
|
1773
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: `font-medium truncate ${isProtected ? "text-slate-500" : "text-slate-700"}`, children: col.name })
|
|
1774
|
+
] }),
|
|
1775
|
+
isProtected && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1776
|
+
"div",
|
|
1777
|
+
{
|
|
1778
|
+
className: "flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] font-semibold bg-amber-50 text-amber-800 border border-amber-200/80 cursor-help",
|
|
1779
|
+
title: protectedExplanation,
|
|
1780
|
+
children: [
|
|
1781
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3 h-3 text-amber-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: "2.2", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" }) }),
|
|
1782
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: badgeLabel })
|
|
1783
|
+
]
|
|
1784
|
+
}
|
|
1785
|
+
)
|
|
1786
|
+
]
|
|
1787
|
+
},
|
|
1788
|
+
col.name
|
|
1789
|
+
);
|
|
1790
|
+
}) })
|
|
1791
|
+
] })
|
|
1792
|
+
] }),
|
|
1381
1793
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-5 w-px bg-slate-300 mx-1 hidden sm:block" }),
|
|
1382
1794
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "relative flex-1 sm:w-64 max-w-xs", children: [
|
|
1383
1795
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
@@ -1390,7 +1802,16 @@ function TableBlockClient({
|
|
|
1390
1802
|
className: "w-full h-9 px-3 pr-9 text-xs border border-slate-300 rounded-lg bg-white shadow-2xs focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 text-slate-800 disabled:opacity-50"
|
|
1391
1803
|
}
|
|
1392
1804
|
),
|
|
1393
|
-
|
|
1805
|
+
searchQuery ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1806
|
+
"button",
|
|
1807
|
+
{
|
|
1808
|
+
type: "button",
|
|
1809
|
+
onClick: () => setSearchQuery(""),
|
|
1810
|
+
className: "absolute right-2.5 top-2.5 text-slate-400 hover:text-slate-600 transition-colors p-0.5 rounded-full hover:bg-slate-100 cursor-pointer",
|
|
1811
|
+
title: "Clear search",
|
|
1812
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react4.X, { className: "w-3.5 h-3.5" })
|
|
1813
|
+
}
|
|
1814
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4 h-4 text-slate-400 absolute right-2.5 top-2.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) })
|
|
1394
1815
|
] })
|
|
1395
1816
|
] }),
|
|
1396
1817
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
@@ -1412,14 +1833,14 @@ function TableBlockClient({
|
|
|
1412
1833
|
)
|
|
1413
1834
|
] })
|
|
1414
1835
|
] }),
|
|
1415
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className:
|
|
1836
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `overflow-x-auto relative min-h-[260px] flex-1 transition-opacity duration-200 ${isMounted ? "opacity-100" : "opacity-0"}`, children: [
|
|
1416
1837
|
isLoading && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "absolute inset-0 bg-white/80 backdrop-blur-xs z-20 flex flex-col items-center justify-center gap-2", children: [
|
|
1417
1838
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-6 h-6 border-2 border-brand border-t-transparent rounded-full animate-spin" }),
|
|
1418
1839
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-sm font-medium text-slate-600", children: "\u05D8\u05D5\u05E2\u05DF \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD..." })
|
|
1419
1840
|
] }),
|
|
1420
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("table", { className: "w-full text-sm text-right border-collapse", children: [
|
|
1841
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("table", { className: "w-full text-sm text-right border-collapse table-auto", children: [
|
|
1421
1842
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("thead", { className: "bg-slate-100/80 text-slate-700 sticky top-0 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { children: [
|
|
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)(
|
|
1843
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "border-b border-l border-slate-200 p-2.5 w-10 text-center shrink-0", style: { width: 50, minWidth: 50, maxWidth: 50 }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1423
1844
|
"input",
|
|
1424
1845
|
{
|
|
1425
1846
|
type: "checkbox",
|
|
@@ -1429,9 +1850,79 @@ function TableBlockClient({
|
|
|
1429
1850
|
className: "w-4 h-4 rounded border-slate-300 text-brand"
|
|
1430
1851
|
}
|
|
1431
1852
|
) }),
|
|
1432
|
-
filteredColumns.map((col) =>
|
|
1853
|
+
filteredColumns.map((col) => {
|
|
1854
|
+
const isDragging = draggedColName === col.name;
|
|
1855
|
+
const isDragOver = dragOverColName === col.name;
|
|
1856
|
+
const currentWidth = columnWidths[col.name] || 200;
|
|
1857
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1858
|
+
"th",
|
|
1859
|
+
{
|
|
1860
|
+
style: { width: currentWidth, minWidth: currentWidth, maxWidth: currentWidth },
|
|
1861
|
+
draggable: !isLoading && !isUpdatingActive,
|
|
1862
|
+
onDragStart: (e) => {
|
|
1863
|
+
e.dataTransfer.setData("text/plain", col.name);
|
|
1864
|
+
e.dataTransfer.effectAllowed = "move";
|
|
1865
|
+
setDraggedColName(col.name);
|
|
1866
|
+
},
|
|
1867
|
+
onDragOver: (e) => {
|
|
1868
|
+
e.preventDefault();
|
|
1869
|
+
e.dataTransfer.dropEffect = "move";
|
|
1870
|
+
if (dragOverColName !== col.name) {
|
|
1871
|
+
setDragOverColName(col.name);
|
|
1872
|
+
}
|
|
1873
|
+
},
|
|
1874
|
+
onDragLeave: () => {
|
|
1875
|
+
if (dragOverColName === col.name) {
|
|
1876
|
+
setDragOverColName(null);
|
|
1877
|
+
}
|
|
1878
|
+
},
|
|
1879
|
+
onDrop: (e) => {
|
|
1880
|
+
e.preventDefault();
|
|
1881
|
+
if (draggedColName && draggedColName !== col.name) {
|
|
1882
|
+
handleColumnReorder(draggedColName, col.name);
|
|
1883
|
+
}
|
|
1884
|
+
setDraggedColName(null);
|
|
1885
|
+
setDragOverColName(null);
|
|
1886
|
+
},
|
|
1887
|
+
onDragEnd: () => {
|
|
1888
|
+
setDraggedColName(null);
|
|
1889
|
+
setDragOverColName(null);
|
|
1890
|
+
},
|
|
1891
|
+
className: `relative border-b border-l border-slate-200 px-4 py-2.5 font-semibold text-slate-700 whitespace-nowrap select-none cursor-grab active:cursor-grabbing transition-colors ${isDragging ? "opacity-40 bg-slate-200 border-dashed border-2 border-brand" : ""} ${isDragOver ? "bg-blue-50 border-r-4 border-r-brand text-brand font-bold" : "hover:bg-slate-200/60"}`,
|
|
1892
|
+
children: [
|
|
1893
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1894
|
+
"div",
|
|
1895
|
+
{
|
|
1896
|
+
onMouseDown: (e) => {
|
|
1897
|
+
e.preventDefault();
|
|
1898
|
+
e.stopPropagation();
|
|
1899
|
+
setResizingCol({ name: col.name, startWidth: currentWidth, startX: e.clientX });
|
|
1900
|
+
},
|
|
1901
|
+
className: "absolute left-0 top-0 bottom-0 w-1.5 cursor-col-resize hover:bg-brand active:bg-brand-hover z-20",
|
|
1902
|
+
title: "\u05E9\u05E0\u05D4 \u05D2\u05D5\u05D3\u05DC \u05E2\u05DE\u05D5\u05D3\u05D4"
|
|
1903
|
+
}
|
|
1904
|
+
),
|
|
1905
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between gap-2 group overflow-hidden", title: "\u05D2\u05E8\u05D5\u05E8 \u05DC\u05E9\u05D9\u05E0\u05D5\u05D9 \u05E1\u05D3\u05E8 \u05D4\u05E2\u05DE\u05D5\u05D3\u05D4", children: [
|
|
1906
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "truncate", children: col.name }),
|
|
1907
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1908
|
+
"svg",
|
|
1909
|
+
{
|
|
1910
|
+
className: "w-3.5 h-3.5 text-slate-400 opacity-40 group-hover:opacity-100 transition-opacity shrink-0 cursor-grab",
|
|
1911
|
+
fill: "none",
|
|
1912
|
+
viewBox: "0 0 24 24",
|
|
1913
|
+
stroke: "currentColor",
|
|
1914
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M8 9h.01M8 15h.01M16 9h.01M16 15h.01" })
|
|
1915
|
+
}
|
|
1916
|
+
)
|
|
1917
|
+
] })
|
|
1918
|
+
]
|
|
1919
|
+
},
|
|
1920
|
+
col.name
|
|
1921
|
+
);
|
|
1922
|
+
}),
|
|
1923
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "w-full min-w-[50px] border-b border-slate-200 pointer-events-none" })
|
|
1433
1924
|
] }) }),
|
|
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 +
|
|
1925
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tbody", { className: "bg-white", children: (isStateEmpty || filteredData.length === 0) && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { colSpan: filteredColumns.length + 2, className: "text-center py-12 text-slate-400", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col items-center justify-center gap-2", children: [
|
|
1435
1926
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-8 h-8 text-slate-300", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", d: "M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4" }) }),
|
|
1436
1927
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05DC\u05D4\u05E6\u05D2\u05D4." })
|
|
1437
1928
|
] }) }) }) : filteredData.map((row) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { className: "hover:bg-blue-50/30 transition-colors group", children: [
|
|
@@ -1477,8 +1968,82 @@ function TableBlockClient({
|
|
|
1477
1968
|
}
|
|
1478
1969
|
}
|
|
1479
1970
|
) }, col.name);
|
|
1480
|
-
})
|
|
1481
|
-
|
|
1971
|
+
}),
|
|
1972
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-slate-200 bg-white pointer-events-none" })
|
|
1973
|
+
] }, row.id)) }),
|
|
1974
|
+
showSummary && filteredData.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tfoot", { className: "bg-slate-50 border-t-2 border-slate-300 sticky bottom-0 z-10 shadow-[0_-2px_4px_rgba(0,0,0,0.02)]", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { children: [
|
|
1975
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-l border-slate-200 p-1.5 text-center font-bold text-slate-600 text-xs", children: '\u05E1\u05D4"\u05DB' }),
|
|
1976
|
+
filteredColumns.map((col) => {
|
|
1977
|
+
var _a;
|
|
1978
|
+
const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
|
|
1979
|
+
const isNumeric = typeUpper === "CURRENCY" || typeUpper === "NUMBER";
|
|
1980
|
+
const total = columnTotals[col.name];
|
|
1981
|
+
let displayVal = "";
|
|
1982
|
+
if (isNumeric && total !== void 0) {
|
|
1983
|
+
displayVal = new Intl.NumberFormat("en-US").format(total);
|
|
1984
|
+
if (typeUpper === "CURRENCY") {
|
|
1985
|
+
const symbol = getCurrencySymbol(col.currencySymbol);
|
|
1986
|
+
displayVal = symbol ? `${symbol} ${displayVal}` : displayVal;
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-l border-slate-200 p-2 text-sm font-semibold text-slate-700 bg-slate-50 relative", children: isNumeric && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex items-center text-right justify-start", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "truncate", children: displayVal }) }) }, col.name);
|
|
1990
|
+
}),
|
|
1991
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-slate-200 bg-slate-50 pointer-events-none" })
|
|
1992
|
+
] }) })
|
|
1993
|
+
] })
|
|
1994
|
+
] }),
|
|
1995
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col sm:flex-row items-center justify-between gap-3 px-4 py-3 bg-slate-50 border-t border-slate-200 text-xs text-slate-600 rounded-b-xl", children: [
|
|
1996
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1997
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-medium text-slate-700", children: "\u05E9\u05D5\u05E8\u05D5\u05EA \u05DC\u05E2\u05DE\u05D5\u05D3:" }),
|
|
1998
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1999
|
+
"select",
|
|
2000
|
+
{
|
|
2001
|
+
value: limit,
|
|
2002
|
+
onChange: (e) => handleLimitChange(Number(e.target.value)),
|
|
2003
|
+
disabled: isLoading || isUpdatingActive,
|
|
2004
|
+
className: "bg-white border border-slate-300 rounded-lg px-2.5 py-1 text-slate-700 font-semibold shadow-2xs cursor-pointer focus:outline-none focus:ring-2 focus:ring-brand disabled:opacity-50",
|
|
2005
|
+
children: [
|
|
2006
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: 20, children: "20" }),
|
|
2007
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: 50, children: "50" }),
|
|
2008
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: 100, children: "100" })
|
|
2009
|
+
]
|
|
2010
|
+
}
|
|
2011
|
+
)
|
|
2012
|
+
] }),
|
|
2013
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-4", children: [
|
|
2014
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-medium text-slate-600", children: [
|
|
2015
|
+
"\u05E2\u05DE\u05D5\u05D3 ",
|
|
2016
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { className: "text-slate-900", children: page }),
|
|
2017
|
+
" \u05DE\u05EA\u05D5\u05DA ",
|
|
2018
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { className: "text-slate-900", children: totalPages || 1 }),
|
|
2019
|
+
totalRecords > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-slate-500 font-normal", children: [
|
|
2020
|
+
" (",
|
|
2021
|
+
totalRecords,
|
|
2022
|
+
' \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D1\u05E1\u05D4"\u05DB)'
|
|
2023
|
+
] })
|
|
2024
|
+
] }),
|
|
2025
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
2026
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2027
|
+
"button",
|
|
2028
|
+
{
|
|
2029
|
+
onClick: handlePrevPage,
|
|
2030
|
+
disabled: page <= 1 || isLoading || isUpdatingActive,
|
|
2031
|
+
className: "px-3 py-1.5 bg-white border border-slate-300 hover:bg-slate-100 font-semibold text-slate-700 rounded-lg shadow-2xs disabled:opacity-40 disabled:pointer-events-none transition-colors cursor-pointer",
|
|
2032
|
+
title: "\u05E2\u05DE\u05D5\u05D3 \u05E7\u05D5\u05D3\u05DD",
|
|
2033
|
+
children: "\u05D4\u05E7\u05D5\u05D3\u05DD"
|
|
2034
|
+
}
|
|
2035
|
+
),
|
|
2036
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2037
|
+
"button",
|
|
2038
|
+
{
|
|
2039
|
+
onClick: handleNextPage,
|
|
2040
|
+
disabled: page >= totalPages || isLoading || isUpdatingActive,
|
|
2041
|
+
className: "px-3 py-1.5 bg-white border border-slate-300 hover:bg-slate-100 font-semibold text-slate-700 rounded-lg shadow-2xs disabled:opacity-40 disabled:pointer-events-none transition-colors cursor-pointer",
|
|
2042
|
+
title: "\u05E2\u05DE\u05D5\u05D3 \u05D4\u05D1\u05D0",
|
|
2043
|
+
children: "\u05D4\u05D1\u05D0"
|
|
2044
|
+
}
|
|
2045
|
+
)
|
|
2046
|
+
] })
|
|
1482
2047
|
] })
|
|
1483
2048
|
] })
|
|
1484
2049
|
]
|