@universe-platform/ui 0.1.0-beta.1 → 0.1.0-beta.3
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 +1117 -11
- package/dist/index.d.mts +76 -2
- package/dist/index.d.ts +76 -2
- package/dist/index.js +1116 -4
- package/dist/index.mjs +1104 -3
- package/package.json +46 -44
package/dist/index.js
CHANGED
|
@@ -1,8 +1,40 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
2
4
|
var __defProp = Object.defineProperty;
|
|
5
|
+
var __defProps = Object.defineProperties;
|
|
3
6
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
8
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
9
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
10
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
11
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
12
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
13
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
14
|
+
var __spreadValues = (a, b) => {
|
|
15
|
+
for (var prop in b || (b = {}))
|
|
16
|
+
if (__hasOwnProp.call(b, prop))
|
|
17
|
+
__defNormalProp(a, prop, b[prop]);
|
|
18
|
+
if (__getOwnPropSymbols)
|
|
19
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
20
|
+
if (__propIsEnum.call(b, prop))
|
|
21
|
+
__defNormalProp(a, prop, b[prop]);
|
|
22
|
+
}
|
|
23
|
+
return a;
|
|
24
|
+
};
|
|
25
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
26
|
+
var __objRest = (source, exclude) => {
|
|
27
|
+
var target = {};
|
|
28
|
+
for (var prop in source)
|
|
29
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
30
|
+
target[prop] = source[prop];
|
|
31
|
+
if (source != null && __getOwnPropSymbols)
|
|
32
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
33
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
34
|
+
target[prop] = source[prop];
|
|
35
|
+
}
|
|
36
|
+
return target;
|
|
37
|
+
};
|
|
6
38
|
var __export = (target, all) => {
|
|
7
39
|
for (var name in all)
|
|
8
40
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -15,13 +47,25 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
47
|
}
|
|
16
48
|
return to;
|
|
17
49
|
};
|
|
50
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
51
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
52
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
53
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
54
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
55
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
56
|
+
mod
|
|
57
|
+
));
|
|
18
58
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
59
|
|
|
20
60
|
// src/index.ts
|
|
21
61
|
var index_exports = {};
|
|
22
62
|
__export(index_exports, {
|
|
63
|
+
TableBlock: () => TableBlock,
|
|
64
|
+
ToastContext: () => ToastContext,
|
|
65
|
+
ToastProvider: () => ToastProvider,
|
|
66
|
+
UNIVERSE_COMPONENTS: () => UNIVERSE_COMPONENTS,
|
|
23
67
|
cn: () => cn,
|
|
24
|
-
|
|
68
|
+
useToast: () => useToast
|
|
25
69
|
});
|
|
26
70
|
module.exports = __toCommonJS(index_exports);
|
|
27
71
|
|
|
@@ -32,10 +76,1078 @@ function cn(...inputs) {
|
|
|
32
76
|
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
33
77
|
}
|
|
34
78
|
|
|
35
|
-
// src/
|
|
36
|
-
var
|
|
79
|
+
// src/components/TableBlock/TableBlockClient.tsx
|
|
80
|
+
var import_react5 = require("react");
|
|
81
|
+
|
|
82
|
+
// src/hooks/useToast.ts
|
|
83
|
+
var import_react2 = require("react");
|
|
84
|
+
|
|
85
|
+
// src/providers/ToastProvider.tsx
|
|
86
|
+
var import_react = require("react");
|
|
87
|
+
var import_lucide_react = require("lucide-react");
|
|
88
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
89
|
+
var ToastContext = (0, import_react.createContext)(void 0);
|
|
90
|
+
function ToastCard({
|
|
91
|
+
toast,
|
|
92
|
+
onClose,
|
|
93
|
+
onMouseEnter,
|
|
94
|
+
onMouseLeave
|
|
95
|
+
}) {
|
|
96
|
+
const [copied, setCopied] = (0, import_react.useState)(false);
|
|
97
|
+
const handleCopy = (e) => {
|
|
98
|
+
e.stopPropagation();
|
|
99
|
+
const textToCopy = toast.title ? `${toast.title}
|
|
100
|
+
${toast.message}` : toast.message;
|
|
101
|
+
navigator.clipboard.writeText(textToCopy).then(() => {
|
|
102
|
+
setCopied(true);
|
|
103
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
104
|
+
}).catch(() => {
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
const isSuccess = toast.type === "success";
|
|
108
|
+
const isInfo = toast.type === "info";
|
|
109
|
+
const isWarning = toast.type === "warning";
|
|
110
|
+
let borderClass = "border-rose-200";
|
|
111
|
+
let iconBgClass = "bg-rose-100 text-rose-600";
|
|
112
|
+
let titleClass = "text-rose-900";
|
|
113
|
+
let defaultTitle = "\u05E9\u05D2\u05D9\u05D0\u05D4";
|
|
114
|
+
let IconComponent = import_lucide_react.AlertCircle;
|
|
115
|
+
if (isSuccess) {
|
|
116
|
+
borderClass = "border-emerald-200";
|
|
117
|
+
iconBgClass = "bg-emerald-100 text-emerald-600";
|
|
118
|
+
titleClass = "text-emerald-900";
|
|
119
|
+
defaultTitle = "\u05D4\u05E6\u05DC\u05D7\u05D4";
|
|
120
|
+
IconComponent = import_lucide_react.CheckCircle2;
|
|
121
|
+
} else if (isInfo) {
|
|
122
|
+
borderClass = "border-sky-200";
|
|
123
|
+
iconBgClass = "bg-sky-100 text-sky-600";
|
|
124
|
+
titleClass = "text-sky-900";
|
|
125
|
+
defaultTitle = "\u05E2\u05D3\u05DB\u05D5\u05DF";
|
|
126
|
+
IconComponent = import_lucide_react.Info;
|
|
127
|
+
} else if (isWarning) {
|
|
128
|
+
borderClass = "border-amber-200";
|
|
129
|
+
iconBgClass = "bg-amber-100 text-amber-600";
|
|
130
|
+
titleClass = "text-amber-900";
|
|
131
|
+
defaultTitle = "\u05D0\u05D6\u05D4\u05E8\u05D4";
|
|
132
|
+
IconComponent = import_lucide_react.AlertTriangle;
|
|
133
|
+
}
|
|
134
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
135
|
+
"div",
|
|
136
|
+
{
|
|
137
|
+
onMouseEnter,
|
|
138
|
+
onMouseLeave,
|
|
139
|
+
className: `pointer-events-auto flex items-start gap-3 p-4 rounded-xl shadow-xl border bg-white/95 text-slate-900 backdrop-blur-md transition-all animate-in fade-in slide-in-from-bottom-5 duration-200 select-text ${borderClass}`,
|
|
140
|
+
children: [
|
|
141
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `p-1.5 rounded-full shrink-0 mt-0.5 ${iconBgClass}`, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconComponent, { className: "w-5 h-5" }) }),
|
|
142
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex-1 text-right min-w-0", children: [
|
|
143
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h4", { className: `font-semibold text-sm ${titleClass}`, children: toast.title || defaultTitle }),
|
|
144
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
145
|
+
"p",
|
|
146
|
+
{
|
|
147
|
+
className: "text-xs text-slate-700 mt-1 leading-relaxed break-words font-sans select-text selection:bg-blue-100 selection:text-blue-900",
|
|
148
|
+
dir: "auto",
|
|
149
|
+
children: toast.message
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
] }),
|
|
153
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-1 shrink-0", children: [
|
|
154
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
155
|
+
"button",
|
|
156
|
+
{
|
|
157
|
+
onClick: handleCopy,
|
|
158
|
+
className: "text-slate-400 hover:text-slate-700 hover:bg-slate-100 transition-colors p-1.5 rounded-md relative flex items-center gap-1 text-xs",
|
|
159
|
+
title: "\u05D4\u05E2\u05EA\u05E7 \u05D8\u05E7\u05E1\u05D8",
|
|
160
|
+
"aria-label": "\u05D4\u05E2\u05EA\u05E7 \u05D8\u05E7\u05E1\u05D8",
|
|
161
|
+
children: copied ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
162
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Check, { className: "w-4 h-4 text-emerald-600" }),
|
|
163
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-[10px] text-emerald-600 font-medium", children: "\u05D4\u05D5\u05E2\u05EA\u05E7!" })
|
|
164
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Copy, { className: "w-4 h-4" })
|
|
165
|
+
}
|
|
166
|
+
),
|
|
167
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
168
|
+
"button",
|
|
169
|
+
{
|
|
170
|
+
onClick: () => onClose(toast.id),
|
|
171
|
+
className: "text-slate-400 hover:text-slate-700 hover:bg-slate-100 transition-colors p-1.5 rounded-md",
|
|
172
|
+
"aria-label": "\u05E1\u05D2\u05D5\u05E8",
|
|
173
|
+
title: "\u05E1\u05D2\u05D5\u05E8",
|
|
174
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { className: "w-4 h-4" })
|
|
175
|
+
}
|
|
176
|
+
)
|
|
177
|
+
] })
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
function ToastProvider({ children }) {
|
|
183
|
+
const [toasts, setToasts] = (0, import_react.useState)([]);
|
|
184
|
+
const timersRef = (0, import_react.useRef)({});
|
|
185
|
+
const removeToast = (0, import_react.useCallback)((id) => {
|
|
186
|
+
if (timersRef.current[id]) {
|
|
187
|
+
clearTimeout(timersRef.current[id]);
|
|
188
|
+
delete timersRef.current[id];
|
|
189
|
+
}
|
|
190
|
+
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
191
|
+
}, []);
|
|
192
|
+
const scheduleDismiss = (0, import_react.useCallback)(
|
|
193
|
+
(id, duration) => {
|
|
194
|
+
if (duration <= 0) return;
|
|
195
|
+
if (timersRef.current[id]) {
|
|
196
|
+
clearTimeout(timersRef.current[id]);
|
|
197
|
+
}
|
|
198
|
+
timersRef.current[id] = setTimeout(() => {
|
|
199
|
+
removeToast(id);
|
|
200
|
+
}, duration);
|
|
201
|
+
},
|
|
202
|
+
[removeToast]
|
|
203
|
+
);
|
|
204
|
+
const addToast = (0, import_react.useCallback)(
|
|
205
|
+
(toast) => {
|
|
206
|
+
var _a;
|
|
207
|
+
const id = Math.random().toString(36).substring(2, 9);
|
|
208
|
+
const defaultDuration = toast.type === "error" ? 1e4 : 6e3;
|
|
209
|
+
const duration = (_a = toast.duration) != null ? _a : defaultDuration;
|
|
210
|
+
const newToast = __spreadProps(__spreadValues({}, toast), { id, duration });
|
|
211
|
+
setToasts((prev) => [...prev, newToast]);
|
|
212
|
+
scheduleDismiss(id, duration);
|
|
213
|
+
return id;
|
|
214
|
+
},
|
|
215
|
+
[scheduleDismiss]
|
|
216
|
+
);
|
|
217
|
+
const showError = (0, import_react.useCallback)(
|
|
218
|
+
(error, title = "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E8\u05DB\u05D9\u05D1") => {
|
|
219
|
+
if (!error) return;
|
|
220
|
+
const message = typeof error === "string" ? error : error.message || String(error);
|
|
221
|
+
addToast({
|
|
222
|
+
title,
|
|
223
|
+
message,
|
|
224
|
+
type: "error",
|
|
225
|
+
duration: 12e3
|
|
226
|
+
});
|
|
227
|
+
},
|
|
228
|
+
[addToast]
|
|
229
|
+
);
|
|
230
|
+
const handleMouseEnter = (toast) => {
|
|
231
|
+
if (timersRef.current[toast.id]) {
|
|
232
|
+
clearTimeout(timersRef.current[toast.id]);
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
const handleMouseLeave = (toast) => {
|
|
236
|
+
var _a;
|
|
237
|
+
scheduleDismiss(toast.id, (_a = toast.duration) != null ? _a : 6e3);
|
|
238
|
+
};
|
|
239
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ToastContext.Provider, { value: { toasts, addToast, showError, removeToast }, children: [
|
|
240
|
+
children,
|
|
241
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
242
|
+
"div",
|
|
243
|
+
{
|
|
244
|
+
"aria-live": "assertive",
|
|
245
|
+
className: "fixed bottom-4 right-4 z-[9999] flex flex-col gap-3 max-w-md w-full pointer-events-none p-2",
|
|
246
|
+
dir: "rtl",
|
|
247
|
+
children: toasts.map((toast) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
248
|
+
ToastCard,
|
|
249
|
+
{
|
|
250
|
+
toast,
|
|
251
|
+
onClose: removeToast,
|
|
252
|
+
onMouseEnter: () => handleMouseEnter(toast),
|
|
253
|
+
onMouseLeave: () => handleMouseLeave(toast)
|
|
254
|
+
},
|
|
255
|
+
toast.id
|
|
256
|
+
))
|
|
257
|
+
}
|
|
258
|
+
)
|
|
259
|
+
] });
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// src/hooks/useToast.ts
|
|
263
|
+
function useToast() {
|
|
264
|
+
const context = (0, import_react2.useContext)(ToastContext);
|
|
265
|
+
if (!context) {
|
|
266
|
+
return {
|
|
267
|
+
toasts: [],
|
|
268
|
+
addToast: () => "",
|
|
269
|
+
showError: (err) => {
|
|
270
|
+
if (err) console.error("[UI Component Error]:", err);
|
|
271
|
+
},
|
|
272
|
+
removeToast: () => {
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
return context;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// src/components/TableBlock/fields/fieldRegistry.tsx
|
|
280
|
+
var import_react4 = __toESM(require("react"));
|
|
281
|
+
|
|
282
|
+
// src/components/TableBlock/fields/DrivePickerCell.tsx
|
|
283
|
+
var import_react3 = require("react");
|
|
284
|
+
var import_lucide_react2 = require("lucide-react");
|
|
285
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
286
|
+
function DrivePickerCell({ value, onChange, tableName, onMarkForDeletion, context }) {
|
|
287
|
+
const [isOpening, setIsOpening] = (0, import_react3.useState)(false);
|
|
288
|
+
const { showError } = useToast();
|
|
289
|
+
const openUploadPopup = async () => {
|
|
290
|
+
if (isOpening) return;
|
|
291
|
+
setIsOpening(true);
|
|
292
|
+
try {
|
|
293
|
+
if (context == null ? void 0 : context.executeAction) {
|
|
294
|
+
const width = 600;
|
|
295
|
+
const height = 600;
|
|
296
|
+
const left = typeof window !== "undefined" ? window.screen.width / 2 - width / 2 : 100;
|
|
297
|
+
const top = typeof window !== "undefined" ? window.screen.height / 2 - height / 2 : 100;
|
|
298
|
+
const popup = typeof window !== "undefined" ? window.open(
|
|
299
|
+
"about:blank",
|
|
300
|
+
"GoogleDrivePicker",
|
|
301
|
+
`width=${width},height=${height},top=${top},left=${left},resizable=yes,scrollbars=yes`
|
|
302
|
+
) : null;
|
|
303
|
+
if (!popup && typeof window !== "undefined") {
|
|
304
|
+
const popupErrMsg = "\u05E4\u05EA\u05D9\u05D7\u05EA \u05D7\u05DC\u05D5\u05DF PopUp \u05E0\u05D7\u05E1\u05DE\u05D4 \u05E2\u05DC \u05D9\u05D3\u05D9 \u05D4\u05D3\u05E4\u05D3\u05E4\u05DF. \u05D0\u05E0\u05D0 \u05D0\u05E4\u05E9\u05E8 \u05D7\u05DC\u05D5\u05E0\u05D5\u05EA \u05E7\u05D5\u05E4\u05E6\u05D9\u05DD \u05E2\u05D1\u05D5\u05E8 \u05D0\u05EA\u05E8 \u05D6\u05D4.";
|
|
305
|
+
console.error("[DrivePickerCell]", popupErrMsg);
|
|
306
|
+
showError(popupErrMsg, "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E4\u05EA\u05D9\u05D7\u05EA \u05E4\u05D5\u05E4\u05D0\u05E4");
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (popup) {
|
|
310
|
+
try {
|
|
311
|
+
popup.document.write(
|
|
312
|
+
"<html dir='rtl'><head><title>Google Drive</title><style>body { font-family: sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; background: #f8fafc; color: #475569; font-size: 14px; }</style></head><body>\u05D8\u05D5\u05E2\u05DF...</body></html>"
|
|
313
|
+
);
|
|
314
|
+
} catch (e) {
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
const actionResult = await context.executeAction("UPLOAD_DRIVE_FILE", { tableName });
|
|
318
|
+
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`);
|
|
320
|
+
if (popup) {
|
|
321
|
+
popup.location.href = pickerUrl;
|
|
322
|
+
}
|
|
323
|
+
const newFile = await new Promise((resolve) => {
|
|
324
|
+
let timer = null;
|
|
325
|
+
const handleMessage = (event) => {
|
|
326
|
+
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);
|
|
329
|
+
if (timer) clearInterval(timer);
|
|
330
|
+
resolve(event.data.payload);
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
timer = setInterval(() => {
|
|
334
|
+
if (!popup || popup.closed) {
|
|
335
|
+
if (timer) clearInterval(timer);
|
|
336
|
+
window.removeEventListener("message", handleMessage);
|
|
337
|
+
resolve(null);
|
|
338
|
+
}
|
|
339
|
+
}, 800);
|
|
340
|
+
window.addEventListener("message", handleMessage);
|
|
341
|
+
});
|
|
342
|
+
if (newFile) {
|
|
343
|
+
onChange(newFile);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
} catch (error) {
|
|
347
|
+
console.error("[DrivePickerCell] Error uploading file:", error);
|
|
348
|
+
const errorMessage = typeof error === "string" ? error : (error == null ? void 0 : error.message) || "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05DC\u05EA\u05D9 \u05E6\u05E4\u05D5\u05D9\u05D4 \u05D1\u05D2\u05D9\u05E9\u05D4 \u05DC-Google Drive";
|
|
349
|
+
showError(errorMessage, "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05D4\u05E2\u05DC\u05D0\u05EA \u05E7\u05D5\u05D1\u05E5 \u05DC-Drive");
|
|
350
|
+
} finally {
|
|
351
|
+
setIsOpening(false);
|
|
352
|
+
}
|
|
353
|
+
};
|
|
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)(
|
|
388
|
+
"button",
|
|
389
|
+
{
|
|
390
|
+
type: "button",
|
|
391
|
+
onClick: openUploadPopup,
|
|
392
|
+
disabled: isOpening || !(context == null ? void 0 : context.executeAction),
|
|
393
|
+
className: "inline-flex items-center gap-1.5 px-2 py-1 rounded-md text-xs font-medium text-slate-500 bg-slate-100 hover:bg-slate-200 hover:text-slate-700 transition-colors disabled:opacity-50",
|
|
394
|
+
children: [
|
|
395
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.Upload, { className: "w-3.5 h-3.5" }),
|
|
396
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: isOpening ? "Loading..." : "Upload File" })
|
|
397
|
+
]
|
|
398
|
+
}
|
|
399
|
+
) });
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// src/components/TableBlock/fields/fieldRegistry.tsx
|
|
403
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
404
|
+
var CURRENCY_SYMBOLS = {
|
|
405
|
+
USD: "$",
|
|
406
|
+
EUR: "\u20AC",
|
|
407
|
+
ILS: "\u20AA",
|
|
408
|
+
GBP: "\xA3"
|
|
409
|
+
};
|
|
410
|
+
function getCurrencySymbol(code) {
|
|
411
|
+
if (!code) return "";
|
|
412
|
+
return CURRENCY_SYMBOLS[code.toUpperCase()] || code;
|
|
413
|
+
}
|
|
414
|
+
function getRelationDisplayLabel(opt, column) {
|
|
415
|
+
if (!opt) return "\u05E8\u05E9\u05D5\u05DE\u05D4 \u05D7\u05E1\u05E8\u05D4";
|
|
416
|
+
const val = column.displayField && opt.data ? opt.data[column.displayField] : void 0;
|
|
417
|
+
if (val !== void 0 && val !== null && val !== "") {
|
|
418
|
+
return String(val);
|
|
419
|
+
}
|
|
420
|
+
if (opt.data) {
|
|
421
|
+
const fallbackField = Object.keys(opt.data).find((k) => {
|
|
422
|
+
if (k === "_id" || k === "id") return false;
|
|
423
|
+
const v = opt.data[k];
|
|
424
|
+
if (typeof v === "string" && v.trim() !== "") return true;
|
|
425
|
+
if (typeof v === "number") return true;
|
|
426
|
+
return false;
|
|
427
|
+
});
|
|
428
|
+
if (fallbackField) return String(opt.data[fallbackField]);
|
|
429
|
+
}
|
|
430
|
+
return "\u05E2\u05E8\u05DA \u05E8\u05D9\u05E7";
|
|
431
|
+
}
|
|
432
|
+
var FORM_INPUTS = {
|
|
433
|
+
CURRENCY: ({ value, column, onChange }) => {
|
|
434
|
+
const symbol = getCurrencySymbol(column.currencySymbol);
|
|
435
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "relative w-full h-full", children: [
|
|
436
|
+
symbol && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "absolute left-2 top-1/2 -translate-y-1/2 text-slate-400 pointer-events-none text-sm", children: symbol }),
|
|
437
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
438
|
+
"input",
|
|
439
|
+
{
|
|
440
|
+
type: "number",
|
|
441
|
+
step: "any",
|
|
442
|
+
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`,
|
|
443
|
+
value: value !== void 0 && value !== null ? value : "",
|
|
444
|
+
onChange: (e) => {
|
|
445
|
+
const val = e.target.value;
|
|
446
|
+
onChange(val === "" ? "" : Number(val));
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
)
|
|
450
|
+
] });
|
|
451
|
+
},
|
|
452
|
+
TIME: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
453
|
+
"input",
|
|
454
|
+
{
|
|
455
|
+
type: "time",
|
|
456
|
+
className: "w-full h-8 px-2 bg-transparent focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 text-sm",
|
|
457
|
+
value: value || "",
|
|
458
|
+
onChange: (e) => onChange(e.target.value)
|
|
459
|
+
}
|
|
460
|
+
),
|
|
461
|
+
LINK: ({ value, onChange }) => {
|
|
462
|
+
const [isEditing, setIsEditing] = import_react4.default.useState(false);
|
|
463
|
+
const label = (value == null ? void 0 : value.label) || "";
|
|
464
|
+
const url = (value == null ? void 0 : value.url) || "";
|
|
465
|
+
if (!isEditing) {
|
|
466
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-2 px-2 py-1 h-full w-full", children: [
|
|
467
|
+
url ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { href: url, target: "_blank", rel: "noopener noreferrer", className: "text-blue-600 hover:underline flex-1 truncate", children: label || url }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-slate-400 italic flex-1 text-sm", children: "\u05E8\u05D9\u05E7" }),
|
|
468
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
469
|
+
"button",
|
|
470
|
+
{
|
|
471
|
+
onClick: () => setIsEditing(true),
|
|
472
|
+
className: "text-xs font-medium text-slate-400 hover:text-blue-500 p-1 rounded transition-colors",
|
|
473
|
+
title: "\u05E2\u05E8\u05D5\u05DA \u05E7\u05D9\u05E9\u05D5\u05E8",
|
|
474
|
+
children: "\u05E2\u05E8\u05D9\u05DB\u05D4"
|
|
475
|
+
}
|
|
476
|
+
)
|
|
477
|
+
] });
|
|
478
|
+
}
|
|
479
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex gap-2 p-1 w-full min-w-[250px] items-center bg-white border border-blue-200 rounded shadow-sm z-10", children: [
|
|
480
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
481
|
+
"input",
|
|
482
|
+
{
|
|
483
|
+
type: "text",
|
|
484
|
+
placeholder: "Label",
|
|
485
|
+
className: "flex-1 h-8 px-2 bg-transparent focus:outline-none text-sm border-r",
|
|
486
|
+
value: label,
|
|
487
|
+
onChange: (e) => onChange({ label: e.target.value, url })
|
|
488
|
+
}
|
|
489
|
+
),
|
|
490
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
491
|
+
"input",
|
|
492
|
+
{
|
|
493
|
+
type: "url",
|
|
494
|
+
placeholder: "URL",
|
|
495
|
+
className: "flex-1 h-8 px-2 bg-transparent focus:outline-none text-sm",
|
|
496
|
+
value: url,
|
|
497
|
+
onChange: (e) => onChange({ label, url: e.target.value })
|
|
498
|
+
}
|
|
499
|
+
),
|
|
500
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
501
|
+
"button",
|
|
502
|
+
{
|
|
503
|
+
onClick: () => setIsEditing(false),
|
|
504
|
+
className: "text-xs font-medium text-green-600 hover:text-green-700 p-1 mx-1 rounded transition-colors",
|
|
505
|
+
title: "\u05E9\u05DE\u05D5\u05E8",
|
|
506
|
+
children: "\u05E9\u05DE\u05D5\u05E8"
|
|
507
|
+
}
|
|
508
|
+
)
|
|
509
|
+
] });
|
|
510
|
+
},
|
|
511
|
+
BOOLEAN: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex items-center justify-center w-full h-full p-2", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
512
|
+
"input",
|
|
513
|
+
{
|
|
514
|
+
type: "checkbox",
|
|
515
|
+
checked: !!value,
|
|
516
|
+
onChange: (e) => onChange(e.target.checked),
|
|
517
|
+
className: "w-4 h-4 rounded border-slate-300 text-brand"
|
|
518
|
+
}
|
|
519
|
+
) }),
|
|
520
|
+
GOOGLE_DRIVE_FILE: ({ value, onChange, context }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
521
|
+
DrivePickerCell,
|
|
522
|
+
{
|
|
523
|
+
value: value || null,
|
|
524
|
+
onChange,
|
|
525
|
+
tableName: context == null ? void 0 : context.tableName,
|
|
526
|
+
onMarkForDeletion: context == null ? void 0 : context.onMarkForDeletion,
|
|
527
|
+
context
|
|
528
|
+
}
|
|
529
|
+
),
|
|
530
|
+
RELATION: ({ value, onChange, column, context }) => {
|
|
531
|
+
var _a;
|
|
532
|
+
const options = ((_a = context == null ? void 0 : context.relationOptions) == null ? void 0 : _a[column.name]) || [];
|
|
533
|
+
import_react4.default.useEffect(() => {
|
|
534
|
+
if (typeof value === "string" && value !== "" && options.length > 0) {
|
|
535
|
+
const isValidId = options.some((o) => String(o.id) === String(value));
|
|
536
|
+
if (!isValidId) {
|
|
537
|
+
const match = options.find(
|
|
538
|
+
(o) => String(getRelationDisplayLabel(o, column)).trim() === String(value).trim()
|
|
539
|
+
);
|
|
540
|
+
if (match) {
|
|
541
|
+
onChange(match.id);
|
|
542
|
+
} else {
|
|
543
|
+
onChange("");
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}, [value, options, column, onChange]);
|
|
548
|
+
const processedOptions = options.map((opt) => __spreadProps(__spreadValues({}, opt), {
|
|
549
|
+
_displayLabel: getRelationDisplayLabel(opt, column)
|
|
550
|
+
}));
|
|
551
|
+
const validOptions = processedOptions.filter((o) => o._displayLabel !== "\u05D4\u05E2\u05E8\u05DA \u05E9\u05D1\u05E8\u05E9\u05D5\u05DE\u05D4 \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05EA \u05E0\u05E9\u05D0\u05E8 \u05E8\u05D9\u05E7");
|
|
552
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
553
|
+
"select",
|
|
554
|
+
{
|
|
555
|
+
className: "w-full h-8 px-2 bg-transparent focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 text-sm",
|
|
556
|
+
value: value !== void 0 && value !== null ? String(value) : "",
|
|
557
|
+
onChange: (e) => onChange(e.target.value),
|
|
558
|
+
onFocus: () => {
|
|
559
|
+
if (context == null ? void 0 : context.refetchRelation) {
|
|
560
|
+
context.refetchRelation(column.name);
|
|
561
|
+
}
|
|
562
|
+
},
|
|
563
|
+
children: [
|
|
564
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", children: "\u05D1\u05D7\u05E8..." }),
|
|
565
|
+
validOptions.length > 0 ? validOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: opt.id, children: opt._displayLabel }, opt.id)) : options.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "empty_all", disabled: true, children: "\u05DB\u05DC \u05D4\u05E2\u05E8\u05DB\u05D9\u05DD \u05D1\u05D8\u05D1\u05DC\u05D4 \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05EA \u05E8\u05D9\u05E7\u05D9\u05DD" }) : null
|
|
566
|
+
]
|
|
567
|
+
}
|
|
568
|
+
);
|
|
569
|
+
},
|
|
570
|
+
NUMBER: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
571
|
+
"input",
|
|
572
|
+
{
|
|
573
|
+
type: "number",
|
|
574
|
+
className: "w-full h-8 px-2 bg-transparent focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 text-sm",
|
|
575
|
+
value: value !== void 0 && value !== null ? value : "",
|
|
576
|
+
onChange: (e) => {
|
|
577
|
+
const val = e.target.value;
|
|
578
|
+
onChange(val === "" ? "" : Number(val));
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
),
|
|
582
|
+
DEFAULT: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
583
|
+
"input",
|
|
584
|
+
{
|
|
585
|
+
type: "text",
|
|
586
|
+
className: "w-full h-8 px-2 bg-transparent focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 text-sm",
|
|
587
|
+
value: value !== void 0 && value !== null ? String(value) : "",
|
|
588
|
+
onChange: (e) => onChange(e.target.value)
|
|
589
|
+
}
|
|
590
|
+
)
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
// src/components/TableBlock/TableBlockClient.tsx
|
|
594
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
595
|
+
function TableBlockClient({
|
|
596
|
+
data: initialRecords,
|
|
597
|
+
settings: schema,
|
|
598
|
+
executeAction,
|
|
599
|
+
emitEvent,
|
|
600
|
+
pageState,
|
|
601
|
+
isLoading,
|
|
602
|
+
isUpdating,
|
|
603
|
+
error,
|
|
604
|
+
isEmpty: isStateEmpty,
|
|
605
|
+
componentId,
|
|
606
|
+
orgId,
|
|
607
|
+
className = "",
|
|
608
|
+
"data-testid": dataTestId
|
|
609
|
+
}) {
|
|
610
|
+
const { showError, addToast } = useToast();
|
|
611
|
+
const normalizeRecords = (records) => {
|
|
612
|
+
return (records || []).map((row) => {
|
|
613
|
+
var _c;
|
|
614
|
+
if (!row) return { id: "", data: {} };
|
|
615
|
+
const rowData = row.data && typeof row.data === "object" ? __spreadValues({}, row.data) : ((_a) => {
|
|
616
|
+
var _b = _a, { id } = _b, rest = __objRest(_b, ["id"]);
|
|
617
|
+
return rest;
|
|
618
|
+
})(row);
|
|
619
|
+
(_c = schema == null ? void 0 : schema.columns) == null ? void 0 : _c.forEach((col) => {
|
|
620
|
+
var _a;
|
|
621
|
+
if (rowData[col.name] === void 0 && col.defaultValue !== void 0 && col.defaultValue !== null) {
|
|
622
|
+
let initialValue = col.defaultValue;
|
|
623
|
+
const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
|
|
624
|
+
if (typeUpper === "CURRENCY" || typeUpper === "NUMBER") {
|
|
625
|
+
initialValue = parseFloat(initialValue);
|
|
626
|
+
if (isNaN(initialValue)) initialValue = null;
|
|
627
|
+
} else if (typeUpper === "BOOLEAN") {
|
|
628
|
+
initialValue = initialValue === "true" || initialValue === true;
|
|
629
|
+
}
|
|
630
|
+
rowData[col.name] = initialValue;
|
|
631
|
+
}
|
|
632
|
+
});
|
|
633
|
+
return __spreadProps(__spreadValues({}, row), { id: String(row.id || ""), data: rowData });
|
|
634
|
+
});
|
|
635
|
+
};
|
|
636
|
+
const [localColumns, setLocalColumns] = (0, import_react5.useState)(() => (schema == null ? void 0 : schema.columns) || []);
|
|
637
|
+
(0, import_react5.useEffect)(() => {
|
|
638
|
+
if ((schema == null ? void 0 : schema.columns) && schema.columns.length > 0) {
|
|
639
|
+
setLocalColumns(schema.columns);
|
|
640
|
+
}
|
|
641
|
+
}, [schema == null ? void 0 : schema.columns]);
|
|
642
|
+
const [dirty, setDirty] = (0, import_react5.useState)({ added: [], modified: {}, deleted: [] });
|
|
643
|
+
const dirtyRef = (0, import_react5.useRef)(dirty);
|
|
644
|
+
(0, import_react5.useEffect)(() => {
|
|
645
|
+
dirtyRef.current = dirty;
|
|
646
|
+
}, [dirty]);
|
|
647
|
+
const mergeWithDirty = (0, import_react5.useCallback)((baseRecords) => {
|
|
648
|
+
const { added, modified, deleted } = dirtyRef.current;
|
|
649
|
+
const nonDeleted = (baseRecords || []).filter((r) => !deleted.includes(r.id));
|
|
650
|
+
const modifiedRecords = nonDeleted.map((r) => {
|
|
651
|
+
if (modified[r.id]) {
|
|
652
|
+
return __spreadProps(__spreadValues({}, r), { data: __spreadValues(__spreadValues({}, r.data), modified[r.id]) });
|
|
653
|
+
}
|
|
654
|
+
return r;
|
|
655
|
+
});
|
|
656
|
+
const baseIds = new Set(modifiedRecords.map((r) => r.id));
|
|
657
|
+
const uniqueAdded = added.filter((r) => !baseIds.has(r.id));
|
|
658
|
+
return [...uniqueAdded, ...modifiedRecords];
|
|
659
|
+
}, []);
|
|
660
|
+
const [data, setData] = (0, import_react5.useState)(() => normalizeRecords(initialRecords));
|
|
661
|
+
(0, import_react5.useEffect)(() => {
|
|
662
|
+
if (initialRecords) {
|
|
663
|
+
setData(mergeWithDirty(normalizeRecords(initialRecords)));
|
|
664
|
+
}
|
|
665
|
+
}, [initialRecords, mergeWithDirty]);
|
|
666
|
+
const isEqualValues = (a, b) => {
|
|
667
|
+
if (a === b) return true;
|
|
668
|
+
if ((a === null || a === void 0 || a === "") && (b === null || b === void 0 || b === "")) return true;
|
|
669
|
+
if (typeof a === "number" && typeof b === "string" && !isNaN(Number(b)) && Number(b) === a) return true;
|
|
670
|
+
if (typeof b === "number" && typeof a === "string" && !isNaN(Number(a)) && Number(a) === b) return true;
|
|
671
|
+
if (typeof a === "object" && typeof b === "object" && a !== null && b !== null) {
|
|
672
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
673
|
+
}
|
|
674
|
+
return false;
|
|
675
|
+
};
|
|
676
|
+
const [baseRecordsMap, setBaseRecordsMap] = (0, import_react5.useState)(() => {
|
|
677
|
+
const map = /* @__PURE__ */ new Map();
|
|
678
|
+
(normalizeRecords(initialRecords) || []).forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
|
|
679
|
+
return map;
|
|
680
|
+
});
|
|
681
|
+
(0, import_react5.useEffect)(() => {
|
|
682
|
+
if (initialRecords && initialRecords.length > 0) {
|
|
683
|
+
const map = /* @__PURE__ */ new Map();
|
|
684
|
+
(normalizeRecords(initialRecords) || []).forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
|
|
685
|
+
setBaseRecordsMap(map);
|
|
686
|
+
}
|
|
687
|
+
}, [initialRecords]);
|
|
688
|
+
(0, import_react5.useEffect)(() => {
|
|
689
|
+
const tableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.id) || (schema == null ? void 0 : schema.tableId);
|
|
690
|
+
if (!tableId || !executeAction) return;
|
|
691
|
+
if (!(schema == null ? void 0 : schema.columns) || schema.columns.length === 0 || (!initialRecords || initialRecords.length === 0)) {
|
|
692
|
+
executeAction("FETCH_TABLE_DATA", { tableId }).then((res) => {
|
|
693
|
+
var _a;
|
|
694
|
+
if (res) {
|
|
695
|
+
if (((_a = res.schema) == null ? void 0 : _a.columns) && res.schema.columns.length > 0) {
|
|
696
|
+
setLocalColumns(res.schema.columns);
|
|
697
|
+
}
|
|
698
|
+
if (res.records && Array.isArray(res.records)) {
|
|
699
|
+
const norm = normalizeRecords(res.records);
|
|
700
|
+
const map = /* @__PURE__ */ new Map();
|
|
701
|
+
norm.forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
|
|
702
|
+
setBaseRecordsMap(map);
|
|
703
|
+
setData(mergeWithDirty(norm));
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}).catch((err) => {
|
|
707
|
+
console.error("[TableBlock] Failed to auto-fetch table data:", err);
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
}, [schema == null ? void 0 : schema.tableMetaId, schema == null ? void 0 : schema.id, schema == null ? void 0 : schema.tableId, schema == null ? void 0 : schema.columns, initialRecords, executeAction, mergeWithDirty]);
|
|
711
|
+
(0, import_react5.useEffect)(() => {
|
|
712
|
+
if (error) {
|
|
713
|
+
showError(error, "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E8\u05DB\u05D9\u05D1");
|
|
714
|
+
}
|
|
715
|
+
}, [error, showError]);
|
|
716
|
+
const [searchQuery, setSearchQuery] = (0, import_react5.useState)("");
|
|
717
|
+
const [selectedIds, setSelectedIds] = (0, import_react5.useState)(/* @__PURE__ */ new Set());
|
|
718
|
+
const [pendingDeletions, setPendingDeletions] = (0, import_react5.useState)([]);
|
|
719
|
+
const [isSaving, setIsSaving] = (0, import_react5.useState)(false);
|
|
720
|
+
const [isSaveSuccess, setIsSaveSuccess] = (0, import_react5.useState)(false);
|
|
721
|
+
const [relationOptions, setRelationOptions] = (0, import_react5.useState)({});
|
|
722
|
+
const schemaColsString = (0, import_react5.useMemo)(() => JSON.stringify(localColumns || []), [localColumns]);
|
|
723
|
+
const refetchRelation = (0, import_react5.useCallback)(async (colName) => {
|
|
724
|
+
var _a;
|
|
725
|
+
let parsedCols = [];
|
|
726
|
+
try {
|
|
727
|
+
parsedCols = JSON.parse(schemaColsString);
|
|
728
|
+
} catch (e) {
|
|
729
|
+
}
|
|
730
|
+
const col = parsedCols.find((c) => c.name === colName);
|
|
731
|
+
if (!col || ((_a = col.type) == null ? void 0 : _a.toUpperCase()) !== "RELATION" || !col.referencedTableId) return;
|
|
732
|
+
try {
|
|
733
|
+
if (executeAction) {
|
|
734
|
+
const options = await executeAction("FETCH_RELATION", { referencedTableId: col.referencedTableId });
|
|
735
|
+
if (options && Array.isArray(options)) {
|
|
736
|
+
setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [colName]: options }));
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
} catch (err) {
|
|
740
|
+
console.warn(`[TableBlock] Could not fetch relation options for column ${colName}:`, err);
|
|
741
|
+
}
|
|
742
|
+
}, [schemaColsString, executeAction]);
|
|
743
|
+
(0, import_react5.useEffect)(() => {
|
|
744
|
+
let parsedCols = [];
|
|
745
|
+
try {
|
|
746
|
+
parsedCols = JSON.parse(schemaColsString);
|
|
747
|
+
} catch (e) {
|
|
748
|
+
}
|
|
749
|
+
const relationCols = parsedCols.filter((c) => {
|
|
750
|
+
var _a;
|
|
751
|
+
return ((_a = c.type) == null ? void 0 : _a.toUpperCase()) === "RELATION";
|
|
752
|
+
}) || [];
|
|
753
|
+
relationCols.forEach((col) => {
|
|
754
|
+
refetchRelation(col.name);
|
|
755
|
+
});
|
|
756
|
+
}, [schemaColsString, refetchRelation]);
|
|
757
|
+
const filteredColumns = (0, import_react5.useMemo)(() => {
|
|
758
|
+
const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
|
|
759
|
+
return (localColumns || []).filter((col) => !systemFields.includes(col.name));
|
|
760
|
+
}, [localColumns]);
|
|
761
|
+
const generateTempId = () => `temp_${Math.random().toString(36).substr(2, 9)}`;
|
|
762
|
+
const handleAddRow = () => {
|
|
763
|
+
const defaultData = {};
|
|
764
|
+
(localColumns || []).forEach((col) => {
|
|
765
|
+
var _a;
|
|
766
|
+
const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
|
|
767
|
+
let initialValue = col.defaultValue;
|
|
768
|
+
if (initialValue !== void 0 && initialValue !== null && initialValue !== "") {
|
|
769
|
+
if (typeUpper === "CURRENCY" || typeUpper === "NUMBER") {
|
|
770
|
+
initialValue = parseFloat(initialValue);
|
|
771
|
+
if (isNaN(initialValue)) initialValue = null;
|
|
772
|
+
} else if (typeUpper === "BOOLEAN") {
|
|
773
|
+
initialValue = initialValue === "true" || initialValue === true;
|
|
774
|
+
}
|
|
775
|
+
defaultData[col.name] = initialValue;
|
|
776
|
+
} else {
|
|
777
|
+
if (typeUpper === "NUMBER" || typeUpper === "CURRENCY") {
|
|
778
|
+
defaultData[col.name] = 0;
|
|
779
|
+
} else if (typeUpper === "BOOLEAN") {
|
|
780
|
+
defaultData[col.name] = false;
|
|
781
|
+
} else {
|
|
782
|
+
defaultData[col.name] = "";
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
});
|
|
786
|
+
const newRow = { id: generateTempId(), data: defaultData };
|
|
787
|
+
setData((prev) => [newRow, ...prev]);
|
|
788
|
+
setDirty((prev) => __spreadProps(__spreadValues({}, prev), { added: [newRow, ...prev.added] }));
|
|
789
|
+
};
|
|
790
|
+
const handleCellChange = (rowId, colName, value) => {
|
|
791
|
+
setData((prev) => prev.map(
|
|
792
|
+
(row) => row.id === rowId ? __spreadProps(__spreadValues({}, row), { data: __spreadProps(__spreadValues({}, row.data), { [colName]: value }) }) : row
|
|
793
|
+
));
|
|
794
|
+
const isAdded = dirty.added.some((r) => r.id === rowId);
|
|
795
|
+
if (isAdded) {
|
|
796
|
+
setDirty((prev) => __spreadProps(__spreadValues({}, prev), {
|
|
797
|
+
added: prev.added.map(
|
|
798
|
+
(r) => r.id === rowId ? __spreadProps(__spreadValues({}, r), { data: __spreadProps(__spreadValues({}, r.data), { [colName]: value }) }) : r
|
|
799
|
+
)
|
|
800
|
+
}));
|
|
801
|
+
} else {
|
|
802
|
+
const origData = baseRecordsMap.get(rowId) || {};
|
|
803
|
+
const origValue = origData[colName];
|
|
804
|
+
setDirty((prev) => {
|
|
805
|
+
const currentMods = __spreadValues({}, prev.modified[rowId] || {});
|
|
806
|
+
if (isEqualValues(value, origValue)) {
|
|
807
|
+
delete currentMods[colName];
|
|
808
|
+
} else {
|
|
809
|
+
currentMods[colName] = value;
|
|
810
|
+
}
|
|
811
|
+
const nextModified = __spreadValues({}, prev.modified);
|
|
812
|
+
if (Object.keys(currentMods).length === 0) {
|
|
813
|
+
delete nextModified[rowId];
|
|
814
|
+
} else {
|
|
815
|
+
nextModified[rowId] = currentMods;
|
|
816
|
+
}
|
|
817
|
+
return __spreadProps(__spreadValues({}, prev), {
|
|
818
|
+
modified: nextModified
|
|
819
|
+
});
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
};
|
|
823
|
+
const toggleSelectAll = (checked) => {
|
|
824
|
+
const nextSelected = checked ? new Set(filteredData.map((r) => r.id)) : /* @__PURE__ */ new Set();
|
|
825
|
+
setSelectedIds(nextSelected);
|
|
826
|
+
if (emitEvent) {
|
|
827
|
+
emitEvent("SELECTION_CHANGE", { selectedIds: Array.from(nextSelected), componentId });
|
|
828
|
+
}
|
|
829
|
+
};
|
|
830
|
+
const toggleSelectRow = (rowId, checked) => {
|
|
831
|
+
const newSelected = new Set(selectedIds);
|
|
832
|
+
if (checked) newSelected.add(rowId);
|
|
833
|
+
else newSelected.delete(rowId);
|
|
834
|
+
setSelectedIds(newSelected);
|
|
835
|
+
if (emitEvent) {
|
|
836
|
+
emitEvent("SELECTION_CHANGE", { selectedIds: Array.from(newSelected), componentId });
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
const handleDeleteSelected = () => {
|
|
840
|
+
const idsToDelete = Array.from(selectedIds);
|
|
841
|
+
if (idsToDelete.length === 0) return;
|
|
842
|
+
const filesToDelete = [];
|
|
843
|
+
const driveCols = (localColumns || []).filter((c) => {
|
|
844
|
+
var _a;
|
|
845
|
+
return ((_a = c.type) == null ? void 0 : _a.toUpperCase()) === "GOOGLE_DRIVE_FILE";
|
|
846
|
+
});
|
|
847
|
+
if (driveCols.length > 0) {
|
|
848
|
+
idsToDelete.forEach((id) => {
|
|
849
|
+
const row = data.find((r) => r.id === id);
|
|
850
|
+
if (row) {
|
|
851
|
+
driveCols.forEach((col) => {
|
|
852
|
+
const fileObj = row.data[col.name];
|
|
853
|
+
if (fileObj && fileObj.fileId) {
|
|
854
|
+
filesToDelete.push(fileObj.fileId);
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
if (filesToDelete.length > 0) {
|
|
861
|
+
setPendingDeletions((prev) => [...prev, ...filesToDelete]);
|
|
862
|
+
}
|
|
863
|
+
setData((prev) => prev.filter((row) => !idsToDelete.includes(row.id)));
|
|
864
|
+
setDirty((prev) => {
|
|
865
|
+
const newAdded = prev.added.filter((r) => !idsToDelete.includes(r.id));
|
|
866
|
+
const newModified = __spreadValues({}, prev.modified);
|
|
867
|
+
const newDeleted = [...prev.deleted];
|
|
868
|
+
idsToDelete.forEach((id) => {
|
|
869
|
+
if (!prev.added.some((r) => r.id === id) && id.length === 24 && !id.startsWith("temp_")) {
|
|
870
|
+
newDeleted.push(id);
|
|
871
|
+
}
|
|
872
|
+
delete newModified[id];
|
|
873
|
+
});
|
|
874
|
+
return { added: newAdded, modified: newModified, deleted: newDeleted };
|
|
875
|
+
});
|
|
876
|
+
setSelectedIds(/* @__PURE__ */ new Set());
|
|
877
|
+
};
|
|
878
|
+
const formatPayload = (payload) => {
|
|
879
|
+
const formatted = {};
|
|
880
|
+
(localColumns || []).forEach((col) => {
|
|
881
|
+
var _a;
|
|
882
|
+
if (["_id", "id", "createdAt", "updatedAt", "orgId", "tableId", "isSelected"].includes(col.name)) return;
|
|
883
|
+
let val = payload[col.name];
|
|
884
|
+
if (val !== void 0) {
|
|
885
|
+
if (val === null) {
|
|
886
|
+
formatted[col.name] = null;
|
|
887
|
+
} else {
|
|
888
|
+
if (((_a = col.type) == null ? void 0 : _a.toUpperCase()) === "NUMBER") {
|
|
889
|
+
val = val === "" ? 0 : Number(val);
|
|
890
|
+
if (isNaN(val)) val = 0;
|
|
891
|
+
}
|
|
892
|
+
formatted[col.name] = val;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
});
|
|
896
|
+
return formatted;
|
|
897
|
+
};
|
|
898
|
+
const hasChanges = dirty.added.length > 0 || Object.keys(dirty.modified).length > 0 || dirty.deleted.length > 0;
|
|
899
|
+
const handleSave = async () => {
|
|
900
|
+
var _a;
|
|
901
|
+
if (!hasChanges) {
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
const systemFields = ["_id", "id", "createdAt", "updatedAt", "orgId", "tableId", "isSelected"];
|
|
905
|
+
const requiredCols = (localColumns || []).filter((c) => c.isRequired && !systemFields.includes(c.name));
|
|
906
|
+
const isEmpty = (val) => val === void 0 || val === null || val === "";
|
|
907
|
+
for (const col of requiredCols) {
|
|
908
|
+
for (const row of dirty.added) {
|
|
909
|
+
if (isEmpty(row.data[col.name])) {
|
|
910
|
+
showError(`\u05E9\u05D2\u05D9\u05D0\u05EA \u05D5\u05DC\u05D9\u05D3\u05E6\u05D9\u05D4: \u05D4\u05E9\u05D3\u05D4 ${col.name} \u05D4\u05D5\u05D0 \u05D7\u05D5\u05D1\u05D4.`, "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05D5\u05D5\u05DC\u05D9\u05D3\u05E6\u05D9\u05D4");
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
for (const [rowId, mods] of Object.entries(dirty.modified)) {
|
|
915
|
+
const rowData = ((_a = data.find((r) => r.id === rowId)) == null ? void 0 : _a.data) || {};
|
|
916
|
+
const mergedData = __spreadValues(__spreadValues({}, rowData), mods);
|
|
917
|
+
if (isEmpty(mergedData[col.name])) {
|
|
918
|
+
showError(`\u05E9\u05D2\u05D9\u05D0\u05EA \u05D5\u05DC\u05D9\u05D3\u05E6\u05D9\u05D4: \u05D4\u05E9\u05D3\u05D4 ${col.name} \u05D4\u05D5\u05D0 \u05D7\u05D5\u05D1\u05D4.`, "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05D5\u05D5\u05DC\u05D9\u05D3\u05E6\u05D9\u05D4");
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
setIsSaving(true);
|
|
924
|
+
try {
|
|
925
|
+
if (!executeAction) {
|
|
926
|
+
showError("\u05E8\u05DB\u05D9\u05D1 \u05D4\u05EA\u05E7\u05E9\u05D5\u05E8\u05EA \u05DC\u05D0 \u05D0\u05D5\u05EA\u05D7\u05DC", "\u05E9\u05D2\u05D9\u05D0\u05EA \u05EA\u05E7\u05E9\u05D5\u05E8\u05EA");
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
const targetTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.id) || (schema == null ? void 0 : schema.tableId);
|
|
930
|
+
if (!targetTableId) {
|
|
931
|
+
showError("\u05DC\u05D0 \u05E0\u05D9\u05EA\u05DF \u05DC\u05E9\u05DE\u05D5\u05E8: \u05DE\u05D6\u05D4\u05D4 \u05D4\u05D8\u05D1\u05DC\u05D4 \u05D7\u05E1\u05E8 (tableId)", "\u05E9\u05D2\u05D9\u05D0\u05EA \u05E9\u05DE\u05D9\u05E8\u05D4");
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
if (dirty.added.length > 0) {
|
|
935
|
+
const payload = dirty.added.map((row) => formatPayload(row.data));
|
|
936
|
+
await executeAction("CREATE_RECORD", { tableId: targetTableId, tableMetaId: targetTableId, records: payload });
|
|
937
|
+
}
|
|
938
|
+
if (Object.keys(dirty.modified).length > 0) {
|
|
939
|
+
const payload = {};
|
|
940
|
+
for (const [id, modData] of Object.entries(dirty.modified)) {
|
|
941
|
+
payload[id] = formatPayload(modData);
|
|
942
|
+
}
|
|
943
|
+
await executeAction("UPDATE_RECORD", { tableId: targetTableId, tableMetaId: targetTableId, modifications: payload });
|
|
944
|
+
}
|
|
945
|
+
if (dirty.deleted.length > 0) {
|
|
946
|
+
await executeAction("DELETE_RECORD", { tableId: targetTableId, tableMetaId: targetTableId, ids: dirty.deleted });
|
|
947
|
+
}
|
|
948
|
+
if (pendingDeletions.length > 0) {
|
|
949
|
+
for (const fileId of pendingDeletions) {
|
|
950
|
+
await executeAction("DELETE_DRIVE_FILE", { fileId }).catch(() => {
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
setPendingDeletions([]);
|
|
954
|
+
}
|
|
955
|
+
setBaseRecordsMap((prev) => {
|
|
956
|
+
const next = new Map(prev);
|
|
957
|
+
dirty.added.forEach((r) => next.set(r.id, __spreadValues({}, r.data)));
|
|
958
|
+
Object.entries(dirty.modified).forEach(([id, mods]) => {
|
|
959
|
+
const existing = next.get(id) || {};
|
|
960
|
+
next.set(id, __spreadValues(__spreadValues({}, existing), mods));
|
|
961
|
+
});
|
|
962
|
+
dirty.deleted.forEach((id) => next.delete(id));
|
|
963
|
+
return next;
|
|
964
|
+
});
|
|
965
|
+
setDirty({ added: [], modified: {}, deleted: [] });
|
|
966
|
+
setIsSaveSuccess(true);
|
|
967
|
+
setTimeout(() => {
|
|
968
|
+
setIsSaveSuccess(false);
|
|
969
|
+
}, 2500);
|
|
970
|
+
} catch (err) {
|
|
971
|
+
setIsSaveSuccess(false);
|
|
972
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
973
|
+
showError(errorMsg, "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E9\u05DE\u05D9\u05E8\u05EA \u05D4\u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD");
|
|
974
|
+
} finally {
|
|
975
|
+
setIsSaving(false);
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
const filteredData = (0, import_react5.useMemo)(() => {
|
|
979
|
+
if (!searchQuery) return data;
|
|
980
|
+
const lowerQuery = searchQuery.toLowerCase();
|
|
981
|
+
return data.filter(
|
|
982
|
+
(row) => (row == null ? void 0 : row.data) && Object.values(row.data).some(
|
|
983
|
+
(val) => String(val != null ? val : "").toLowerCase().includes(lowerQuery)
|
|
984
|
+
)
|
|
985
|
+
);
|
|
986
|
+
}, [data, searchQuery]);
|
|
987
|
+
const isUpdatingActive = Boolean(isUpdating || isSaving);
|
|
988
|
+
const errorMessage = error ? typeof error === "string" ? error : error.message || String(error) : null;
|
|
989
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
990
|
+
"div",
|
|
991
|
+
{
|
|
992
|
+
id: componentId,
|
|
993
|
+
"data-testid": dataTestId || (componentId ? `table-block-${componentId}` : void 0),
|
|
994
|
+
className: `flex flex-col w-full bg-white border border-slate-200 rounded-xl shadow-xs overflow-hidden ${className}`,
|
|
995
|
+
dir: "rtl",
|
|
996
|
+
children: [
|
|
997
|
+
errorMessage && /* @__PURE__ */ (0, import_jsx_runtime4.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_runtime4.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
998
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.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_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
|
|
999
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: errorMessage })
|
|
1000
|
+
] }) }),
|
|
1001
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.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: [
|
|
1002
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-wrap items-center gap-2.5", children: [
|
|
1003
|
+
((schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.name)) && /* @__PURE__ */ (0, import_jsx_runtime4.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_runtime4.jsx)("span", { children: schema.title || schema.name }) }),
|
|
1004
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1005
|
+
"button",
|
|
1006
|
+
{
|
|
1007
|
+
onClick: handleAddRow,
|
|
1008
|
+
disabled: isLoading || isUpdatingActive,
|
|
1009
|
+
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",
|
|
1010
|
+
title: "\u05D4\u05D5\u05E1\u05E3 \u05E9\u05D5\u05E8\u05D4 \u05D7\u05D3\u05E9\u05D4",
|
|
1011
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-4.5 h-4.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M12 4v16m8-8H4" }) })
|
|
1012
|
+
}
|
|
1013
|
+
),
|
|
1014
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1015
|
+
"button",
|
|
1016
|
+
{
|
|
1017
|
+
onClick: handleDeleteSelected,
|
|
1018
|
+
disabled: isLoading || isUpdatingActive || selectedIds.size === 0,
|
|
1019
|
+
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",
|
|
1020
|
+
title: "\u05DE\u05D7\u05E7 \u05E9\u05D5\u05E8\u05D5\u05EA \u05E0\u05D1\u05D7\u05E8\u05D5\u05EA",
|
|
1021
|
+
children: [
|
|
1022
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.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_runtime4.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" }) }),
|
|
1023
|
+
selectedIds.size > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.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 })
|
|
1024
|
+
]
|
|
1025
|
+
}
|
|
1026
|
+
),
|
|
1027
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "h-5 w-px bg-slate-300 mx-1 hidden sm:block" }),
|
|
1028
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "relative flex-1 sm:w-64 max-w-xs", children: [
|
|
1029
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1030
|
+
"input",
|
|
1031
|
+
{
|
|
1032
|
+
placeholder: "\u05D7\u05D9\u05E4\u05D5\u05E9 \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA...",
|
|
1033
|
+
value: searchQuery,
|
|
1034
|
+
onChange: (e) => setSearchQuery(e.target.value),
|
|
1035
|
+
disabled: isLoading,
|
|
1036
|
+
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"
|
|
1037
|
+
}
|
|
1038
|
+
),
|
|
1039
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.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_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) })
|
|
1040
|
+
] })
|
|
1041
|
+
] }),
|
|
1042
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
1043
|
+
isUpdatingActive ? /* @__PURE__ */ (0, import_jsx_runtime4.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: [
|
|
1044
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "w-2 h-2 rounded-full bg-blue-500 inline-block" }),
|
|
1045
|
+
"\u05DE\u05E2\u05D3\u05DB\u05DF..."
|
|
1046
|
+
] }) : isSaveSuccess ? /* @__PURE__ */ (0, import_jsx_runtime4.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: [
|
|
1047
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.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_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M5 13l4 4L19 7" }) }),
|
|
1048
|
+
"\u05E2\u05D5\u05D3\u05DB\u05DF \u05D1\u05D4\u05E6\u05DC\u05D7\u05D4"
|
|
1049
|
+
] }) : hasChanges ? /* @__PURE__ */ (0, import_jsx_runtime4.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,
|
|
1050
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1051
|
+
"button",
|
|
1052
|
+
{
|
|
1053
|
+
onClick: handleSave,
|
|
1054
|
+
disabled: isUpdatingActive || isLoading || !hasChanges,
|
|
1055
|
+
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"}`,
|
|
1056
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: isUpdatingActive ? "\u05E9\u05D5\u05DE\u05E8..." : "\u05E9\u05DE\u05D9\u05E8\u05EA \u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD" })
|
|
1057
|
+
}
|
|
1058
|
+
)
|
|
1059
|
+
] })
|
|
1060
|
+
] }),
|
|
1061
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "overflow-x-auto relative", children: [
|
|
1062
|
+
isLoading && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "absolute inset-0 bg-white/80 backdrop-blur-xs z-20 flex flex-col items-center justify-center gap-2", children: [
|
|
1063
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "w-6 h-6 border-2 border-brand border-t-transparent rounded-full animate-spin" }),
|
|
1064
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-sm font-medium text-slate-600", children: "\u05D8\u05D5\u05E2\u05DF \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD..." })
|
|
1065
|
+
] }),
|
|
1066
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("table", { className: "w-full text-sm text-right border-collapse", children: [
|
|
1067
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("thead", { className: "bg-slate-100/80 text-slate-700 sticky top-0 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("tr", { children: [
|
|
1068
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "border-b border-l border-slate-200 p-2.5 w-10 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1069
|
+
"input",
|
|
1070
|
+
{
|
|
1071
|
+
type: "checkbox",
|
|
1072
|
+
checked: filteredData.length > 0 && selectedIds.size === filteredData.length,
|
|
1073
|
+
onChange: (e) => toggleSelectAll(e.target.checked),
|
|
1074
|
+
disabled: isLoading || isUpdatingActive,
|
|
1075
|
+
className: "w-4 h-4 rounded border-slate-300 text-brand"
|
|
1076
|
+
}
|
|
1077
|
+
) }),
|
|
1078
|
+
filteredColumns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime4.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))
|
|
1079
|
+
] }) }),
|
|
1080
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tbody", { className: "bg-white", children: (isStateEmpty || filteredData.length === 0) && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { colSpan: filteredColumns.length + 1, className: "text-center py-12 text-slate-400", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-col items-center justify-center gap-2", children: [
|
|
1081
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-8 h-8 text-slate-300", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.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" }) }),
|
|
1082
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05DC\u05D4\u05E6\u05D2\u05D4." })
|
|
1083
|
+
] }) }) }) : filteredData.map((row) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("tr", { className: "hover:bg-blue-50/30 transition-colors group", children: [
|
|
1084
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.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_runtime4.jsx)(
|
|
1085
|
+
"input",
|
|
1086
|
+
{
|
|
1087
|
+
type: "checkbox",
|
|
1088
|
+
checked: selectedIds.has(row.id),
|
|
1089
|
+
onChange: (e) => toggleSelectRow(row.id, e.target.checked),
|
|
1090
|
+
disabled: isLoading || isUpdatingActive,
|
|
1091
|
+
className: "w-4 h-4 rounded border-slate-300 text-brand"
|
|
1092
|
+
}
|
|
1093
|
+
) }),
|
|
1094
|
+
filteredColumns.map((col) => {
|
|
1095
|
+
var _a;
|
|
1096
|
+
const colType = ((_a = col.type) == null ? void 0 : _a.toUpperCase()) || "DEFAULT";
|
|
1097
|
+
const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
|
|
1098
|
+
let value = (row == null ? void 0 : row.data) ? row.data[col.name] : void 0;
|
|
1099
|
+
if (value === void 0 && col.defaultValue !== void 0) {
|
|
1100
|
+
value = colType === "CURRENCY" || colType === "NUMBER" ? parseFloat(col.defaultValue) : col.defaultValue;
|
|
1101
|
+
if (colType === "CURRENCY" || colType === "NUMBER") {
|
|
1102
|
+
if (isNaN(value)) value = null;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
if (value === void 0) value = null;
|
|
1106
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "border-b border-l border-slate-200 p-0 relative", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1107
|
+
InputComponent,
|
|
1108
|
+
{
|
|
1109
|
+
value,
|
|
1110
|
+
column: col,
|
|
1111
|
+
rowId: row.id,
|
|
1112
|
+
onChange: (v) => handleCellChange(row.id, col.name, v),
|
|
1113
|
+
context: {
|
|
1114
|
+
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",
|
|
1115
|
+
onMarkForDeletion: (fileId) => setPendingDeletions((prev) => [...prev, fileId]),
|
|
1116
|
+
relationOptions,
|
|
1117
|
+
refetchRelation,
|
|
1118
|
+
executeAction,
|
|
1119
|
+
emitEvent,
|
|
1120
|
+
pageState,
|
|
1121
|
+
componentId,
|
|
1122
|
+
orgId
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
) }, col.name);
|
|
1126
|
+
})
|
|
1127
|
+
] }, row.id)) })
|
|
1128
|
+
] })
|
|
1129
|
+
] })
|
|
1130
|
+
]
|
|
1131
|
+
}
|
|
1132
|
+
);
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
// src/components/TableBlock/TableBlock.tsx
|
|
1136
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1137
|
+
function TableBlock(props) {
|
|
1138
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TableBlockClient, __spreadValues({}, props));
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
// src/registry.ts
|
|
1142
|
+
var UNIVERSE_COMPONENTS = {
|
|
1143
|
+
TABLE: TableBlock
|
|
1144
|
+
};
|
|
37
1145
|
// Annotate the CommonJS export names for ESM import in node:
|
|
38
1146
|
0 && (module.exports = {
|
|
1147
|
+
TableBlock,
|
|
1148
|
+
ToastContext,
|
|
1149
|
+
ToastProvider,
|
|
1150
|
+
UNIVERSE_COMPONENTS,
|
|
39
1151
|
cn,
|
|
40
|
-
|
|
1152
|
+
useToast
|
|
41
1153
|
});
|