@ramesesinc/platform-core 0.1.9 → 0.1.10
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/components/action/LookupPage.d.ts +2 -1
- package/dist/components/action/LookupPage.js +4 -3
- package/dist/components/action/Play.d.ts +6 -0
- package/dist/components/action/Play.js +40 -0
- package/dist/components/action/ProgressBar.d.ts +8 -0
- package/dist/components/action/ProgressBar.js +146 -0
- package/dist/components/action/ViewPage.d.ts +2 -1
- package/dist/components/action/ViewPage.js +19 -9
- package/dist/components/common/UIMenu.js +4 -3
- package/dist/components/index.d.ts +4 -1
- package/dist/components/index.js +4 -1
- package/dist/components/input/Combo.d.ts +21 -0
- package/dist/components/input/Combo.js +137 -0
- package/dist/components/input/DateField.js +7 -14
- package/dist/components/input/Text.d.ts +5 -0
- package/dist/components/input/Text.js +42 -7
- package/dist/components/list/EditableMenu.d.ts +2 -0
- package/dist/components/list/EditableMenu.js +128 -0
- package/dist/components/list/TabMenu.js +2 -2
- package/dist/components/list/TreeMenu.js +17 -12
- package/dist/components/table/DataList.d.ts +1 -1
- package/dist/components/table/DataList.js +49 -24
- package/dist/components/table/DataTable.d.ts +2 -0
- package/dist/components/table/DataTable.js +31 -22
- package/dist/components/view/FilterView.js +1 -1
- package/dist/components/view/HtmlForm.js +12 -9
- package/dist/components/view/PageView.js +36 -9
- package/dist/components/view/RootView.js +16 -16
- package/dist/core/AuthContext.js +1 -1
- package/dist/core/Page.js +2 -4
- package/dist/core/PageCache.d.ts +0 -2
- package/dist/core/PageCache.js +3 -8
- package/dist/core/PageContext.js +12 -0
- package/dist/core/PageViewContext.d.ts +8 -2
- package/dist/core/PageViewContext.js +129 -75
- package/dist/core/Panel.js +31 -9
- package/dist/index.css +79 -0
- package/dist/layouts/CardLayout.d.ts +2 -2
- package/dist/layouts/CardLayout.js +3 -4
- package/dist/layouts/HPanel.d.ts +2 -2
- package/dist/layouts/HPanel.js +1 -2
- package/dist/layouts/VPanel.d.ts +2 -2
- package/dist/layouts/VPanel.js +1 -2
- package/dist/layouts/index.d.ts +2 -3
- package/dist/layouts/index.js +2 -3
- package/dist/lib/utils/ExprUtil.js +18 -29
- package/dist/lib/utils/ResourceLoader.js +19 -7
- package/dist/lib/utils/SectionProvider.js +1 -1
- package/dist/lib/utils/initResourceLoader.d.ts +2 -0
- package/dist/lib/utils/initResourceLoader.js +64 -95
- package/dist/lib/utils/nunjucks.d.ts +2 -0
- package/dist/lib/utils/nunjucks.js +8 -0
- package/dist/templates/CrudFormTemplate.js +2 -3
- package/dist/templates/DataListTemplate.js +1 -1
- package/dist/templates/WizardTemplate.js +3 -1
- package/package.json +1 -1
- package/dist/components/input/Select.d.ts +0 -14
- package/dist/components/input/Select.js +0 -40
|
@@ -2,20 +2,38 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { useRef, useState } from "react";
|
|
3
3
|
import UIComponent from "../common/UIComponent";
|
|
4
4
|
import useUIInput from "../common/UIInput";
|
|
5
|
+
class TextCaseFormatter {
|
|
6
|
+
apply(value, mode) {
|
|
7
|
+
switch (mode) {
|
|
8
|
+
case "upper":
|
|
9
|
+
return value.toUpperCase();
|
|
10
|
+
case "lower":
|
|
11
|
+
return value.toLowerCase();
|
|
12
|
+
case "capitalize":
|
|
13
|
+
return value.replace(/\b\w/g, (char) => char.toUpperCase());
|
|
14
|
+
case "none":
|
|
15
|
+
default:
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export const applyTextCase = (value, mode) => {
|
|
21
|
+
return new TextCaseFormatter().apply(value, mode);
|
|
22
|
+
};
|
|
5
23
|
const TextField = (props) => {
|
|
6
|
-
|
|
7
|
-
const
|
|
24
|
+
var _a, _b;
|
|
25
|
+
const { immediate = true, align = "left", noSpace = false, required = false, placeholder } = props !== null && props !== void 0 ? props : {};
|
|
26
|
+
// const [focused, setFocused] = useState(false);
|
|
8
27
|
const inputRef = useRef(null);
|
|
9
28
|
const valueRef = useRef("");
|
|
10
|
-
const className = "border rounded px-2 py-1 w-full";
|
|
11
29
|
const handleFocus = () => {
|
|
12
|
-
setFocused(true);
|
|
30
|
+
// setFocused(true);
|
|
13
31
|
};
|
|
14
32
|
const handleBlur = () => {
|
|
15
33
|
if (!immediate) {
|
|
16
34
|
setValue(inputValue);
|
|
17
35
|
}
|
|
18
|
-
setFocused(false);
|
|
36
|
+
// setFocused(false);
|
|
19
37
|
};
|
|
20
38
|
const onRefresh = () => {
|
|
21
39
|
setInputValue(getValue());
|
|
@@ -25,7 +43,10 @@ const TextField = (props) => {
|
|
|
25
43
|
const [inputValue, setInputValue] = useState(valueRef.current);
|
|
26
44
|
const onChange = (e) => {
|
|
27
45
|
var _a;
|
|
28
|
-
|
|
46
|
+
let text = (_a = e.target.value) !== null && _a !== void 0 ? _a : "";
|
|
47
|
+
if (noSpace) {
|
|
48
|
+
text = text.replace(/\s+/g, "");
|
|
49
|
+
}
|
|
29
50
|
if (text !== inputValue) {
|
|
30
51
|
valueRef.current = text;
|
|
31
52
|
setInputValue(valueRef.current);
|
|
@@ -34,6 +55,20 @@ const TextField = (props) => {
|
|
|
34
55
|
setValue(text);
|
|
35
56
|
}
|
|
36
57
|
};
|
|
37
|
-
|
|
58
|
+
const handleKeyDown = (e) => {
|
|
59
|
+
if (noSpace && e.key === " ") {
|
|
60
|
+
e.preventDefault();
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const alignClass = {
|
|
64
|
+
left: "text-left",
|
|
65
|
+
center: "text-center",
|
|
66
|
+
right: "text-right",
|
|
67
|
+
}[align];
|
|
68
|
+
const inReadMode = (_b = (_a = binding === null || binding === void 0 ? void 0 : binding.isReadMode) === null || _a === void 0 ? void 0 : _a.call(binding)) !== null && _b !== void 0 ? _b : false;
|
|
69
|
+
const defaultStyleClass = "text-sm px-2 py-2 border rounded-md shadow-sm transition-colors duration-150 ease-in-out w-full";
|
|
70
|
+
const focusStyleClass = `focus:outline-none ${inReadMode ? "bg-gray-50" : "focus:bg-yellow-50"} focus:ring-1 focus:ring-blue-400`;
|
|
71
|
+
const borderClass = "border-gray-300";
|
|
72
|
+
return (_jsx(UIComponent, Object.assign({}, (props !== null && props !== void 0 ? props : {}), { children: _jsx("input", { type: "text", ref: inputRef, onChange: onChange, onKeyDown: handleKeyDown, value: inputValue, onFocus: handleFocus, onBlur: handleBlur, required: required, disabled: inReadMode, placeholder: inReadMode ? "" : placeholder, className: `${defaultStyleClass} ${focusStyleClass} ${alignClass} ${borderClass}` }) })));
|
|
38
73
|
};
|
|
39
74
|
export default TextField;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { DataBindingProvider } from "@/core/DataContext";
|
|
3
|
+
import DynamicIcon from "@/core/DynamicIcon";
|
|
4
|
+
import { usePageContext } from "@/core/PageContext";
|
|
5
|
+
import { usePageViewContext } from "@/core/PageViewContext";
|
|
6
|
+
import useDependHandler from "@/core/UIDependHandler";
|
|
7
|
+
import { replaceValues } from "@/lib/utils/BeanUtils";
|
|
8
|
+
import { Eye } from "lucide-react";
|
|
9
|
+
import { useEffect, useRef, useState } from "react";
|
|
10
|
+
import ViewPage from "../action/ViewPage";
|
|
11
|
+
import useUIMenu from "../common/UIMenu";
|
|
12
|
+
const EditableMenu = (props) => {
|
|
13
|
+
const { name, depends, title, menugroup, items: itemsProp, data, addPage, viewPage } = props !== null && props !== void 0 ? props : {};
|
|
14
|
+
const [activeItem, setActiveItem] = useState(null);
|
|
15
|
+
const [resolvedData, setResolvedData] = useState(data);
|
|
16
|
+
const [sortedItems, setSortedItems] = useState([]);
|
|
17
|
+
const pageContext = usePageContext();
|
|
18
|
+
const pageView = usePageViewContext();
|
|
19
|
+
const uuid = Math.random().toString(36).slice(2);
|
|
20
|
+
const dragHandler = useDragHandler({
|
|
21
|
+
items: sortedItems,
|
|
22
|
+
onSort: setSortedItems,
|
|
23
|
+
onDrop: async (draggedItem, updatedItems) => {
|
|
24
|
+
const reordered = updatedItems.map((item, idx) => ({
|
|
25
|
+
id: item.id,
|
|
26
|
+
sortorder: idx + 1, // ← 1-based sortorder
|
|
27
|
+
}));
|
|
28
|
+
console.log("resolvedData", JSON.stringify(resolvedData, null, 2));
|
|
29
|
+
console.log("reordered", JSON.stringify(reordered, null, 2));
|
|
30
|
+
// const status = await pageContext?.postMgmt("menus", "reorder", {
|
|
31
|
+
// type: resolvedData?.params?.type,
|
|
32
|
+
// groupid: resolvedData?.params?.groupid,
|
|
33
|
+
// items: reordered,
|
|
34
|
+
// });
|
|
35
|
+
// console.log("status", status);
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
const { items } = useUIMenu({ menugroup, items: itemsProp, data: resolvedData });
|
|
39
|
+
const handleItemClick = (item) => {
|
|
40
|
+
// console.log("Item clicked:", item);
|
|
41
|
+
pageContext === null || pageContext === void 0 ? void 0 : pageContext.set(name, item);
|
|
42
|
+
setActiveItem(item);
|
|
43
|
+
};
|
|
44
|
+
const handleAdd = () => {
|
|
45
|
+
console.log("Add clicked", addPage);
|
|
46
|
+
const { url, mode } = addPage !== null && addPage !== void 0 ? addPage : {};
|
|
47
|
+
const idx = ["window", "popup"].indexOf(String(mode).toLowerCase());
|
|
48
|
+
console.log(idx);
|
|
49
|
+
if (idx >= 0) {
|
|
50
|
+
// pageView.setPage(url, { mode });
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
// pageView.setSelectedPage(url);
|
|
54
|
+
pageContext.set(name, url);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const handleView = (item) => {
|
|
58
|
+
const { url, mode } = viewPage !== null && viewPage !== void 0 ? viewPage : {};
|
|
59
|
+
console.log("View clicked", url, mode, item);
|
|
60
|
+
};
|
|
61
|
+
const handleDelete = (item) => console.log("Delete clicked", item);
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (items.length === 0)
|
|
64
|
+
return;
|
|
65
|
+
const firstItem = items[0];
|
|
66
|
+
setActiveItem(firstItem);
|
|
67
|
+
setSortedItems(items);
|
|
68
|
+
pageContext === null || pageContext === void 0 ? void 0 : pageContext.set(name, items[0]);
|
|
69
|
+
}, [items]);
|
|
70
|
+
const resolveData = () => {
|
|
71
|
+
var _a;
|
|
72
|
+
if (!(data === null || data === void 0 ? void 0 : data.params))
|
|
73
|
+
return data;
|
|
74
|
+
const dependsValue = (_a = pageContext === null || pageContext === void 0 ? void 0 : pageContext.get(depends)) !== null && _a !== void 0 ? _a : {};
|
|
75
|
+
const resolvedParams = replaceValues(data.params, dependsValue);
|
|
76
|
+
return Object.assign(Object.assign({}, data), { params: resolvedParams });
|
|
77
|
+
};
|
|
78
|
+
const onRefresh = () => {
|
|
79
|
+
// when depends changes → re-resolve params
|
|
80
|
+
setResolvedData(resolveData());
|
|
81
|
+
// setActiveItem(null); // reset active item
|
|
82
|
+
};
|
|
83
|
+
useDependHandler({ name: depends, onRefresh });
|
|
84
|
+
return (_jsxs("div", { className: "p-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("p", { className: "text-lg font-semibold", children: title }), _jsx(ViewPage, { url: addPage === null || addPage === void 0 ? void 0 : addPage.url, mode: addPage === null || addPage === void 0 ? void 0 : addPage.mode, iconOnly: true, icon: _jsx(DynamicIcon, { icon: "Plus", size: 18 }), title: title })] }), _jsx("div", { className: "border-b border-gray-200 my-2" }), _jsx("div", { className: "flex flex-col gap-2", children: sortedItems.map((item, index) => {
|
|
85
|
+
var _a;
|
|
86
|
+
const isActive = (activeItem === null || activeItem === void 0 ? void 0 : activeItem.id) === item.id; // ← use activeItem
|
|
87
|
+
return (_jsx(DataBindingProvider, { data: { data: item }, children: _jsxs("div", { draggable: true, onDragStart: () => dragHandler.handleDragStart(index), onDragOver: (e) => dragHandler.handleDragOver(e, index), onDrop: dragHandler.handleDrop, onDragEnd: dragHandler.handleDragEnd, className: `flex items-center justify-between border-b p-2 cursor-pointer transition-colors
|
|
88
|
+
${isActive ? "bg-gray-200" : "bg-gray-50 border-gray-200 hover:bg-gray-200"}`, onClick: () => handleItemClick(item), children: [_jsx("span", { className: "text-gray-400 cursor-grab mr-2", children: _jsx(DynamicIcon, { icon: "GripVertical", size: 16 }) }), _jsx("span", { className: `text-base flex-1 ${isActive ? "font-medium" : ""}`, children: item.title }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(ViewPage, { url: viewPage === null || viewPage === void 0 ? void 0 : viewPage.url, mode: viewPage === null || viewPage === void 0 ? void 0 : viewPage.mode, popupClassName: viewPage === null || viewPage === void 0 ? void 0 : viewPage.popupClassName, iconOnly: true, icon: _jsx(Eye, { size: 16, color: "blue" }) }), renderButton((_a = item.deleteIcon) !== null && _a !== void 0 ? _a : "Trash", () => handleDelete(item), "text-red-500")] })] }) }, `${uuid}-${index}`));
|
|
89
|
+
}) })] }));
|
|
90
|
+
};
|
|
91
|
+
export default EditableMenu;
|
|
92
|
+
/* ------------------------------------------------------------------ */
|
|
93
|
+
/* Render Button */
|
|
94
|
+
/* ------------------------------------------------------------------ */
|
|
95
|
+
const renderButton = (icon, onClick, color = "text-gray-500") => (_jsx("span", { className: `${color} cursor-pointer hover:opacity-70 transition-opacity`, onClick: (e) => {
|
|
96
|
+
e.stopPropagation();
|
|
97
|
+
onClick();
|
|
98
|
+
}, children: _jsx(DynamicIcon, { icon: icon, size: 18 }) }));
|
|
99
|
+
const useDragHandler = ({ items, onSort, onDrop }) => {
|
|
100
|
+
const dragIndexRef = useRef(null);
|
|
101
|
+
const dragOverIndexRef = useRef(null);
|
|
102
|
+
const handleDragStart = (index) => {
|
|
103
|
+
dragIndexRef.current = index;
|
|
104
|
+
};
|
|
105
|
+
const handleDragOver = (e, index) => {
|
|
106
|
+
e.preventDefault();
|
|
107
|
+
dragOverIndexRef.current = index;
|
|
108
|
+
};
|
|
109
|
+
const handleDrop = () => {
|
|
110
|
+
const from = dragIndexRef.current;
|
|
111
|
+
const to = dragOverIndexRef.current;
|
|
112
|
+
if (from == null || to == null || from === to)
|
|
113
|
+
return;
|
|
114
|
+
const draggedItem = items[from];
|
|
115
|
+
const updated = [...items];
|
|
116
|
+
const [moved] = updated.splice(from, 1);
|
|
117
|
+
updated.splice(to, 0, moved);
|
|
118
|
+
onSort(updated);
|
|
119
|
+
onDrop === null || onDrop === void 0 ? void 0 : onDrop(draggedItem, updated);
|
|
120
|
+
dragIndexRef.current = null;
|
|
121
|
+
dragOverIndexRef.current = null;
|
|
122
|
+
};
|
|
123
|
+
const handleDragEnd = () => {
|
|
124
|
+
dragIndexRef.current = null;
|
|
125
|
+
dragOverIndexRef.current = null;
|
|
126
|
+
};
|
|
127
|
+
return { handleDragStart, handleDragOver, handleDrop, handleDragEnd };
|
|
128
|
+
};
|
|
@@ -4,8 +4,8 @@ import { useEffect, useState } from "react";
|
|
|
4
4
|
import { usePageContext } from "../../core/PageContext";
|
|
5
5
|
import { usePageViewContext } from "../../core/PageViewContext";
|
|
6
6
|
import useDependHandler from "../../core/UIDependHandler";
|
|
7
|
-
import HPanel from "../../layouts/HPanel";
|
|
8
|
-
import VPanel from "../../layouts/VPanel";
|
|
7
|
+
import { HPanel } from "../../layouts/HPanel";
|
|
8
|
+
import { VPanel } from "../../layouts/VPanel";
|
|
9
9
|
const TabMenu = (props) => {
|
|
10
10
|
var _a;
|
|
11
11
|
const { name, depends, items = [], data, menugroup, orientation = "horizontal" } = props !== null && props !== void 0 ? props : {};
|
|
@@ -84,6 +84,7 @@ const TreeMenu = (props) => {
|
|
|
84
84
|
const [openGroups, setOpenGroups] = useState([]);
|
|
85
85
|
const [activeItem, setActiveItem] = useState({});
|
|
86
86
|
const [items, setItems] = useState([]);
|
|
87
|
+
const [hashPage, setHashPage] = useState(null);
|
|
87
88
|
const initializedRef = useRef(false);
|
|
88
89
|
const { items: rawItems } = useUIMenu({
|
|
89
90
|
items: itemsProp,
|
|
@@ -95,7 +96,9 @@ const TreeMenu = (props) => {
|
|
|
95
96
|
const { path = "" } = (_a = pageView.getOriginalLocationInfo()) !== null && _a !== void 0 ? _a : {};
|
|
96
97
|
const [, ...anchors] = path.split("#");
|
|
97
98
|
const [selectedPath] = anchors;
|
|
98
|
-
|
|
99
|
+
if (selectedPath) {
|
|
100
|
+
pageContext.set(contextKey, selectedPath);
|
|
101
|
+
}
|
|
99
102
|
}, []);
|
|
100
103
|
/* ---------------------- Sync active item from page view ---------------------- */
|
|
101
104
|
useLayoutEffect(() => {
|
|
@@ -115,23 +118,27 @@ const TreeMenu = (props) => {
|
|
|
115
118
|
}, [rawItems]);
|
|
116
119
|
/* ---------------------- Auto-select first item on init ---------------------- */
|
|
117
120
|
useEffect(() => {
|
|
121
|
+
var _a;
|
|
118
122
|
if (initializedRef.current || items.length === 0)
|
|
119
123
|
return;
|
|
120
124
|
const firstItem = findFirstItem(items);
|
|
121
125
|
if (!(firstItem === null || firstItem === void 0 ? void 0 : firstItem.page))
|
|
122
126
|
return;
|
|
123
127
|
let selectedPage = pageContext.get(contextKey);
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
+
if (selectedPage == null) {
|
|
129
|
+
// fallback to window.location.hash
|
|
130
|
+
const hash = (_a = window.location.hash) !== null && _a !== void 0 ? _a : "";
|
|
131
|
+
const [, firstAnchor] = hash.split("#");
|
|
132
|
+
if (firstAnchor) {
|
|
133
|
+
selectedPage = firstAnchor; // strip query params
|
|
134
|
+
setHashPage(selectedPage);
|
|
135
|
+
}
|
|
128
136
|
}
|
|
129
|
-
// console.log("treemenu selected page final", contextKey, selectedPage);
|
|
130
137
|
if (selectedPage != null) {
|
|
131
138
|
const selectedItem = findItemByPage(items, selectedPage);
|
|
132
|
-
// console.log("treemenu findItemByPage", selectedPage, selectedItem);
|
|
133
139
|
if (selectedItem) {
|
|
134
|
-
|
|
140
|
+
const groupPath = findGroupPath(items, selectedPage);
|
|
141
|
+
setOpenGroups(groupPath);
|
|
135
142
|
setActiveItem(selectedItem);
|
|
136
143
|
}
|
|
137
144
|
else {
|
|
@@ -144,7 +151,7 @@ const TreeMenu = (props) => {
|
|
|
144
151
|
setActiveItem(firstItem);
|
|
145
152
|
}
|
|
146
153
|
initializedRef.current = true;
|
|
147
|
-
}, [items, contextKey]);
|
|
154
|
+
}, [items, contextKey, hashPage]);
|
|
148
155
|
/* ---------------------- Sync page context on active item change ---------------------- */
|
|
149
156
|
useEffect(() => {
|
|
150
157
|
const { mode, page } = (activeItem !== null && activeItem !== void 0 ? activeItem : {});
|
|
@@ -155,7 +162,6 @@ const TreeMenu = (props) => {
|
|
|
155
162
|
pageView.setPage(page, { mode });
|
|
156
163
|
}
|
|
157
164
|
else {
|
|
158
|
-
pageView.setSelectedPage(page);
|
|
159
165
|
pageContext.set(contextKey, page);
|
|
160
166
|
}
|
|
161
167
|
}, [activeItem]);
|
|
@@ -182,8 +188,7 @@ const TreeMenu = (props) => {
|
|
|
182
188
|
};
|
|
183
189
|
/* ---------------------- Events ---------------------- */
|
|
184
190
|
const handleSubItemClick = (item) => {
|
|
185
|
-
if (!item.page || item.page === activeItem.page)
|
|
186
|
-
return;
|
|
191
|
+
// if (!item.page || item.page === activeItem.page) return;
|
|
187
192
|
setActiveItem(item);
|
|
188
193
|
};
|
|
189
194
|
/* ---------------------- Recursive render ---------------------- */
|
|
@@ -50,7 +50,7 @@ export interface DataListAttr {
|
|
|
50
50
|
searchDebounce?: number;
|
|
51
51
|
onSearchChange?: (text: string) => void;
|
|
52
52
|
filters?: FilterDefinition[] | FilterDefinition[][];
|
|
53
|
-
|
|
53
|
+
filterPage?: Record<string, any>;
|
|
54
54
|
onFilterChange?: (filters: Record<string, any>) => void;
|
|
55
55
|
sortable?: boolean;
|
|
56
56
|
defaultSort?: {
|
|
@@ -10,8 +10,9 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import { Tooltip } from "@ramesesinc/client";
|
|
14
|
+
import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, Columns, Eye, Funnel, RefreshCcw, Search, Trash } from "lucide-react";
|
|
15
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
15
16
|
import { useApp } from "../../core/AppContext";
|
|
16
17
|
import { useDataContext } from "../../core/DataContext";
|
|
17
18
|
import { DynamicComponent } from "../../core/DynamicComponent";
|
|
@@ -20,10 +21,12 @@ import Panel from "../../core/Panel";
|
|
|
20
21
|
import useDependHandler from "../../core/UIDependHandler";
|
|
21
22
|
import { replaceValues } from "../../lib/utils/BeanUtils";
|
|
22
23
|
import { getUrlPageParams } from "../../lib/utils/PageUtils";
|
|
24
|
+
import LookupPage from "../action/LookupPage";
|
|
23
25
|
import { DataTable } from "./DataTable";
|
|
24
26
|
import ListHandler from "./ListHandler";
|
|
25
27
|
import { TableProvider, useTableContext } from "./TableContext";
|
|
26
|
-
const InnerDataList = ({ cols, emptyMessage = "No data available", errorMessage, striped = false, bordered = false, hover = true, dense = false, showPagination = true, paginationPosition = "bottom", showPageInfo = true, showTotalCount = true, showRowsPerPage = true, rowsPerPageOptions = [5, 10, 20, 50, 100], searchable = false, searchPlaceholder = "Search...", searchDebounce = 300, onSearchChange, filters = [],
|
|
28
|
+
const InnerDataList = ({ cols, emptyMessage = "No data available", errorMessage, striped = false, bordered = false, hover = true, dense = false, showPagination = true, paginationPosition = "bottom", showPageInfo = true, showTotalCount = true, showRowsPerPage = true, rowsPerPageOptions = [5, 10, 20, 50, 100], searchable = false, searchPlaceholder = "Search...", searchDebounce = 300, onSearchChange, filters = [], filterPage, onFilterChange, sortable = true, showSortIndicator = true, selectable = false, selectionMode = "multiple", onSelectionChange, selectOnRowClick = false, onRowClick, rowActions = [], bulkActions = [], showBulkActions = true, toolbarActions = [], showToolbar = true, toolbarTitle, showRefreshButton = true, showExportButton = false, onLoad, onError, onRefresh, onExport, className = "", rowClassName, depends, handle, }) => {
|
|
29
|
+
var _a;
|
|
27
30
|
const { listHandler, columns, rows, setRows, loading: ctxLoading, setLoading } = useTableContext();
|
|
28
31
|
// ============================================================================
|
|
29
32
|
// STATE
|
|
@@ -215,15 +218,15 @@ const InnerDataList = ({ cols, emptyMessage = "No data available", errorMessage,
|
|
|
215
218
|
// ============================================================================
|
|
216
219
|
// DISPLAY COLUMNS — actions + sort indicators
|
|
217
220
|
// ============================================================================
|
|
221
|
+
const actionUuid = useRef(Math.random().toString(36).slice(2));
|
|
218
222
|
const renderActionCell = (row, rowIndex) => {
|
|
219
223
|
const visible = rowActions.filter((a) => !a.show || a.show(row));
|
|
220
224
|
if (visible.length === 0)
|
|
221
225
|
return null;
|
|
222
|
-
const uuid = Math.random().toString(36).slice(2);
|
|
223
226
|
return (_jsx("div", { className: "dl-actions flex justify-center items-center", children: visible.map((action, i) => (_jsx("div", { children: _jsx(DynamicComponent, { config: {
|
|
224
227
|
component: action.component,
|
|
225
228
|
attr: Object.assign(Object.assign({}, action.attr), { opt: { data: row } }),
|
|
226
|
-
} }) }, `${
|
|
229
|
+
} }) }, `${actionUuid.current}-${i}`))) }));
|
|
227
230
|
};
|
|
228
231
|
const displayColumns = rowActions.length > 0 && visibleUserColumns.length > 0
|
|
229
232
|
? [
|
|
@@ -246,17 +249,24 @@ const InnerDataList = ({ cols, emptyMessage = "No data available", errorMessage,
|
|
|
246
249
|
// ============================================================================
|
|
247
250
|
// RENDER TOOLBAR
|
|
248
251
|
// ============================================================================
|
|
252
|
+
const toolbarUuid = useRef(Math.random().toString(36).slice(2));
|
|
249
253
|
const renderToolbar = () => {
|
|
250
254
|
if (!showToolbar)
|
|
251
255
|
return null;
|
|
252
|
-
const uuid = Math.random().toString(36).slice(2);
|
|
253
256
|
return (_jsxs("div", { className: "dl-toolbar", children: [_jsxs("div", { className: "dl-toolbar-left", children: [toolbarTitle && _jsx("h3", { className: "dl-toolbar-title", children: toolbarTitle }), _jsxs("div", { className: "dl-toolbar-right", children: [showBulkActions &&
|
|
254
257
|
selectedRows.length > 0 &&
|
|
255
258
|
bulkActions.map((action, i) => (_jsxs("button", { className: `dl-btn dl-btn-${action.variant || "default"}`, onClick: () => {
|
|
256
259
|
const selectedData = rows.filter((row) => selectedRows.includes(row.id || JSON.stringify(row)));
|
|
257
260
|
action.onClick(selectedData);
|
|
258
|
-
}, children: [action.icon && _jsx("span", { children: action.icon }), action.label] }, action.label || i))),
|
|
261
|
+
}, children: [action.icon && _jsx("span", { children: action.icon }), action.label] }, action.label || i))), _jsx(SearchBox, { searchable: searchable, searchPlaceholder: searchPlaceholder, searchText: searchText, onSearch: handleSearch })] })] }), MemoizedToolbar] }));
|
|
259
262
|
};
|
|
263
|
+
const handleRefreshRef = useRef(handleRefresh);
|
|
264
|
+
useEffect(() => {
|
|
265
|
+
handleRefreshRef.current = handleRefresh;
|
|
266
|
+
}, [handleRefresh]);
|
|
267
|
+
const MemoizedToolbar = useMemo(() => {
|
|
268
|
+
return (_jsxs("div", { className: "flex items-center gap-1", children: [toolbarActions.map((action, i) => (_jsx("div", { children: _jsx(DynamicComponent, { config: { component: action.component, attr: action.attr || {} } }) }, `${toolbarUuid.current}-${i}`))), _jsx(FilterButton, { filterPage: filterPage }), _jsx(RefreshButton, { show: showRefreshButton, onClick: handleRefresh }), _jsx(ColumnToggle, { columns: columns, hiddenColumns: hiddenColumns, setHiddenColumns: setHiddenColumns })] }));
|
|
269
|
+
}, [toolbarActions, filterPage, showRefreshButton, hiddenColumns, columns]);
|
|
260
270
|
// ============================================================================
|
|
261
271
|
// RENDER FILTER PANEL
|
|
262
272
|
// ============================================================================
|
|
@@ -279,11 +289,11 @@ const InnerDataList = ({ cols, emptyMessage = "No data available", errorMessage,
|
|
|
279
289
|
const hasPrev = listHandler.hasPrevPage();
|
|
280
290
|
const startRecord = (currentPage - 1) * rowsPerPage + 1;
|
|
281
291
|
const endRecord = Math.min(currentPage * rowsPerPage, totalRecords);
|
|
282
|
-
return (_jsxs("div", { className: "dl-pagination", children: [
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
292
|
+
return (_jsxs("div", { className: "dl-pagination", children: [_jsx("div", { className: "dl-pagination-info", children: showPageInfo && !showTotalCount && _jsxs("span", { children: ["Page ", currentPage] }) }), _jsxs("div", { className: "dl-pagination-controls", children: [showRowsPerPage && (_jsxs("div", { className: "dl-rows-per-page", children: [_jsx("span", { children: "Rows per page" }), _jsx("select", { value: rowsPerPage, onChange: (e) => handleRowsPerPage(Number(e.target.value)), children: rowsPerPageOptions.map((o) => (_jsx("option", { value: o, children: o }, o))) })] })), showPageInfo && showTotalCount && (_jsxs("span", { className: "text-sm", children: ["Page ", startRecord, " of ", endRecord] })), _jsxs("div", { className: "flex gap-2", children: [_jsx("button", { className: "dl-page-btn", disabled: !hasPrev, onClick: handleFirstPage, children: _jsx(ChevronLeft, { size: 16 }) }), _jsx("button", { className: "dl-page-btn", disabled: !hasPrev, onClick: handlePrevPage, children: _jsx(ChevronsLeft, { size: 16 }) }), totalPages > 0 &&
|
|
293
|
+
[...Array(Math.min(totalPages, 5))].map((_, i) => {
|
|
294
|
+
const page = i + 1;
|
|
295
|
+
return (_jsx("button", { className: `dl-page-btn ${currentPage === page ? "active" : ""}`, onClick: () => handlePageChange(page), children: page }, page));
|
|
296
|
+
}), _jsx("button", { className: "dl-page-btn", disabled: !hasNext, onClick: handleNextPage, children: _jsx(ChevronRight, { size: 16 }) }), _jsx("button", { className: "dl-page-btn", disabled: !hasNext, onClick: handleLastPage, children: _jsx(ChevronsRight, { size: 16 }) })] })] })] }));
|
|
287
297
|
};
|
|
288
298
|
// ============================================================================
|
|
289
299
|
// ERROR STATE
|
|
@@ -294,7 +304,8 @@ const InnerDataList = ({ cols, emptyMessage = "No data available", errorMessage,
|
|
|
294
304
|
// ============================================================================
|
|
295
305
|
// MAIN RENDER
|
|
296
306
|
// ============================================================================
|
|
297
|
-
|
|
307
|
+
const rowsPerPage = (_a = listHandler === null || listHandler === void 0 ? void 0 : listHandler.getRowsPerPage()) !== null && _a !== void 0 ? _a : 10;
|
|
308
|
+
return (_jsxs("div", { className: `data-list ${className}`, children: [renderToolbar(), renderFilterPanel(), (paginationPosition === "both" || paginationPosition === "top") && renderPagination(), _jsx(DataTable, { data: rows, columns: sortableColumns, loading: isLoading, emptyMessage: emptyMessage, striped: striped, bordered: bordered, hover: hover, dense: dense, rowKey: "id", onRowClick: handleRowClick, selectedRows: selectedRows, onSelectionChange: handleSelectionChange, selectable: selectable, rowClassName: rowClassName, rowsPerPage: rowsPerPage }), (paginationPosition === "both" || paginationPosition === "bottom") && rows.length > 0 && renderPagination()] }));
|
|
298
309
|
};
|
|
299
310
|
export const DataList = ({ attr }) => {
|
|
300
311
|
const { title, depends, cols, data, rowsPerPage, disableTotalCount, commonActions, rowActions, toolbarActions } = attr, rest = __rest(attr, ["title", "depends", "cols", "data", "rowsPerPage", "disableTotalCount", "commonActions", "rowActions", "toolbarActions"]);
|
|
@@ -337,13 +348,17 @@ export const DataList = ({ attr }) => {
|
|
|
337
348
|
attr: Object.assign(Object.assign({}, commonActions.newPage), { title: "New" }),
|
|
338
349
|
});
|
|
339
350
|
}
|
|
340
|
-
if (commonActions
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
351
|
+
// if (commonActions?.filterPage) {
|
|
352
|
+
// newToolbarActions.push({
|
|
353
|
+
// label: "Filter",
|
|
354
|
+
// component: "LookupPage",
|
|
355
|
+
// attr: {
|
|
356
|
+
// ...commonActions.filterPage,
|
|
357
|
+
// name: "customFilter",
|
|
358
|
+
// title: "Filter",
|
|
359
|
+
// },
|
|
360
|
+
// });
|
|
361
|
+
// }
|
|
347
362
|
const handleRef = useRef(null);
|
|
348
363
|
const onRefresh = () => {
|
|
349
364
|
var _a;
|
|
@@ -356,17 +371,21 @@ export const DataList = ({ attr }) => {
|
|
|
356
371
|
handleRef.current = ref;
|
|
357
372
|
},
|
|
358
373
|
};
|
|
359
|
-
return (_jsx(TableProvider, { data: data, columns: cols, rowsPerPage: rowsPerPage, disableTotalCount: disableTotalCount, listHandlerFactory: listHandlerFactory, tenant: tenant !== null && tenant !== void 0 ? tenant : "", module: module !== null && module !== void 0 ? module : "", resolvedParams: resolveParams(), children: _jsx(InnerDataList, Object.assign({}, rest, { toolbarTitle: title, cols: cols, rowActions: newRowActions, toolbarActions: newToolbarActions, depends: depends, handle: innerHandle })) }));
|
|
374
|
+
return (_jsx(TableProvider, { data: data, columns: cols, rowsPerPage: rowsPerPage, disableTotalCount: disableTotalCount, listHandlerFactory: listHandlerFactory, tenant: tenant !== null && tenant !== void 0 ? tenant : "", module: module !== null && module !== void 0 ? module : "", resolvedParams: resolveParams(), children: _jsx(InnerDataList, Object.assign({}, rest, { toolbarTitle: title, cols: cols, rowActions: newRowActions, toolbarActions: newToolbarActions, depends: depends, handle: innerHandle, filterPage: commonActions === null || commonActions === void 0 ? void 0 : commonActions.filterPage })) }));
|
|
360
375
|
};
|
|
361
376
|
export default DataList;
|
|
362
377
|
const RefreshButton = ({ show, onClick, size = 18 }) => {
|
|
363
378
|
if (!show)
|
|
364
379
|
return null;
|
|
365
|
-
return (_jsx("span", { className: "text-gray-600 hover:bg-gray-200 rounded p-2", children: _jsx(RefreshCcw, { size: size
|
|
380
|
+
return (_jsx(Tooltip, { content: "Refresh", children: _jsx("span", { className: "text-gray-600 hover:bg-gray-200 rounded p-2 cursor-pointer flex items-center", onClick: onClick, children: _jsx(RefreshCcw, { size: size }) }) })
|
|
381
|
+
// <Button onClick={onClick} variant="outlined" icon={<RefreshCcw size={size} />} className="text-black border-gray-300 hover:bg-gray-100">
|
|
382
|
+
// Refresh
|
|
383
|
+
// </Button>
|
|
384
|
+
);
|
|
366
385
|
};
|
|
367
386
|
const ColumnToggle = ({ columns, hiddenColumns, setHiddenColumns }) => {
|
|
368
387
|
const [showColumnToggle, setShowColumnToggle] = useState(false);
|
|
369
|
-
return (_jsxs("div", { className: "relative", children: [_jsx("span", { className: "text-gray-600 hover:bg-gray-200 rounded p-2 cursor-pointer flex items-center", onClick: () => setShowColumnToggle(!showColumnToggle), children: _jsx(Columns, { size: 18 }) }), showColumnToggle && (_jsxs("div", { className: "absolute right-0 top-8 z-50 bg-white border
|
|
388
|
+
return (_jsxs("div", { className: "relative", children: [_jsx(Tooltip, { content: "Columns", children: _jsx("span", { className: "text-gray-600 hover:bg-gray-200 rounded p-2 cursor-pointer flex items-center", onClick: () => setShowColumnToggle(!showColumnToggle), children: _jsx(Columns, { size: 18 }) }) }), showColumnToggle && (_jsxs("div", { className: "absolute right-0 top-8 z-50 bg-white border rounded-lg shadow-lg p-3 min-w-[180px]", children: [_jsx("p", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wide mb-2", children: "Columns" }), columns.map((col) => {
|
|
370
389
|
const colId = col.id || String(col.title);
|
|
371
390
|
const isHidden = hiddenColumns.includes(colId);
|
|
372
391
|
return (_jsxs("label", { className: "flex items-center gap-2 py-1 cursor-pointer hover:bg-gray-50 px-1 rounded", children: [_jsx("input", { type: "checkbox", checked: !isHidden, onChange: () => setHiddenColumns((prev) => (isHidden ? prev.filter((id) => id !== colId) : [...prev, colId])) }), _jsx("span", { className: "text-sm text-gray-700", children: String(col.title || col.id) })] }, colId));
|
|
@@ -375,5 +394,11 @@ const ColumnToggle = ({ columns, hiddenColumns, setHiddenColumns }) => {
|
|
|
375
394
|
const SearchBox = ({ searchable, searchPlaceholder, searchText, onSearch }) => {
|
|
376
395
|
if (!searchable)
|
|
377
396
|
return null;
|
|
378
|
-
return (_jsxs("div", { className: "dl-search-box
|
|
397
|
+
return (_jsxs("div", { className: "dl-search-box", children: [_jsx("span", { children: _jsx(Search, { size: 16 }) }), _jsx("input", { type: "text", placeholder: searchPlaceholder, value: searchText, onChange: (e) => onSearch(e.target.value), className: "focus:outline-none focus:ring-0 focus:shadow-none focus:bg-white" })] }));
|
|
398
|
+
};
|
|
399
|
+
const FilterButton = ({ filterPage }) => {
|
|
400
|
+
const { url, name, icon } = filterPage || {};
|
|
401
|
+
if (!filterPage)
|
|
402
|
+
return null;
|
|
403
|
+
return (_jsx(Tooltip, { content: "Filter", children: _jsx(LookupPage, { url: url, name: name, title: "Filter", icon: icon || _jsx(Funnel, { size: 18, className: "cursor-pointer text-black " }), iconOnly: true, variant: "outlined", className: "text-gray-600 hover:bg-gray-200 rounded p-2 flex items-center" }) }));
|
|
379
404
|
};
|
|
@@ -16,6 +16,7 @@ export interface ColumnDefinition {
|
|
|
16
16
|
expr?: string;
|
|
17
17
|
primary?: boolean;
|
|
18
18
|
component?: string | null;
|
|
19
|
+
attr?: Record<string, any>;
|
|
19
20
|
}
|
|
20
21
|
export interface DataTableProps {
|
|
21
22
|
data?: any[];
|
|
@@ -41,6 +42,7 @@ export interface DataTableProps {
|
|
|
41
42
|
multiRowHeader?: ColumnDefinition[][];
|
|
42
43
|
rowActions?: (row: any, rowIndex: number) => React.ReactNode;
|
|
43
44
|
rowsPerItem?: number;
|
|
45
|
+
rowsPerPage?: number;
|
|
44
46
|
}
|
|
45
47
|
export declare const DataTable: React.FC<DataTableProps>;
|
|
46
48
|
export default DataTable;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import React, { memo, useMemo } from "react";
|
|
3
|
+
import { DynamicComponent } from "../../core/DynamicComponent";
|
|
3
4
|
import { RowProvider } from "../../core/RowContext";
|
|
4
5
|
import { render } from "../../lib/utils/ExprUtil";
|
|
5
6
|
import { useTableContext } from "./TableContext";
|
|
@@ -53,7 +54,7 @@ const TableHeader = memo(({ visibleColumns, selectable, rowActions, data, select
|
|
|
53
54
|
return (_jsx("th", { style: { width: column.width, textAlign: column.align || "left" }, className: column.sortable ? "sortable" : "", children: renderHeader(column) }, getColumnKey(column, index)));
|
|
54
55
|
}), rowActions && _jsx("th", { className: "dt-actions-cell", children: "Actions" })] }));
|
|
55
56
|
});
|
|
56
|
-
const TableBody = memo(({ sortedData, visibleColumns, emptyMessage, selectable, rowActions, selectedRows, handleSelectRow, handleRowClick, handleCellClick, rowClassName, rowKey, rowsPerItem, cellRenderer, }) => {
|
|
57
|
+
const TableBody = memo(({ sortedData, visibleColumns, emptyMessage, selectable, rowActions, selectedRows, handleSelectRow, handleRowClick, handleCellClick, rowClassName, rowKey, rowsPerItem, cellRenderer, rowsPerPage, }) => {
|
|
57
58
|
const generateKey = () => `RP-${Math.random().toString(36).slice(2)}`;
|
|
58
59
|
const getNestedValue = (obj, path) => {
|
|
59
60
|
if (!path)
|
|
@@ -63,6 +64,8 @@ const TableBody = memo(({ sortedData, visibleColumns, emptyMessage, selectable,
|
|
|
63
64
|
const getRowKey = (row) => row[rowKey] || JSON.stringify(row);
|
|
64
65
|
const isRowSelected = (row) => selectedRows.includes(getRowKey(row));
|
|
65
66
|
const getColumnKey = (column, index) => column.id || column.expr || `col-${index}`;
|
|
67
|
+
const colCount = visibleColumns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0);
|
|
68
|
+
const fillerCount = rowsPerPage ? Math.max(0, rowsPerPage - sortedData.length) : 0;
|
|
66
69
|
/*
|
|
67
70
|
const renderExpression = (expr: string, row: any): string => {
|
|
68
71
|
try {
|
|
@@ -92,6 +95,12 @@ const TableBody = memo(({ sortedData, visibleColumns, emptyMessage, selectable,
|
|
|
92
95
|
}
|
|
93
96
|
};
|
|
94
97
|
const renderCellContent = (row, column, rowIndex) => {
|
|
98
|
+
if (column.component) {
|
|
99
|
+
return (_jsx(DynamicComponent, { config: {
|
|
100
|
+
component: column.component,
|
|
101
|
+
attr: Object.assign(Object.assign({}, column.attr), { opt: { data: row } }),
|
|
102
|
+
} }));
|
|
103
|
+
}
|
|
95
104
|
if (column.expr) {
|
|
96
105
|
const rendered = render(column.expr, row);
|
|
97
106
|
if (column.render)
|
|
@@ -110,35 +119,35 @@ const TableBody = memo(({ sortedData, visibleColumns, emptyMessage, selectable,
|
|
|
110
119
|
if (!sortedData || sortedData.length === 0) {
|
|
111
120
|
return (_jsx("tr", { children: _jsx("td", { colSpan: visibleColumns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0), style: { textAlign: "center", padding: "24px" }, children: emptyMessage }) }));
|
|
112
121
|
}
|
|
113
|
-
return (
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
122
|
+
return (_jsxs(_Fragment, { children: [sortedData.map((row, itemIndex) => {
|
|
123
|
+
const isSelected = isRowSelected(row);
|
|
124
|
+
const customRowClass = rowClassName ? rowClassName(row, itemIndex) : "";
|
|
125
|
+
const rows = [];
|
|
126
|
+
for (let subrowIndex = 0; subrowIndex < rowsPerItem; subrowIndex++) {
|
|
127
|
+
const rowClasses = [isSelected && "dt-selected", customRowClass].filter(Boolean).join(" ");
|
|
128
|
+
rows.push(_jsx(RowProvider, { data: row, children: _jsxs("tr", { className: rowClasses, onClick: () => handleRowClick(row, itemIndex), children: [selectable && subrowIndex === 0 && (_jsx("td", { className: "dt-checkbox-cell", rowSpan: rowsPerItem, children: _jsx("input", { type: "checkbox", checked: isSelected, onChange: () => handleSelectRow(row), onClick: (e) => e.stopPropagation() }) })), visibleColumns.map((column, colIndex) => {
|
|
129
|
+
if (!column.id && !column.expr && !column.component)
|
|
130
|
+
return null;
|
|
131
|
+
if ((column.subrow || 0) !== subrowIndex)
|
|
132
|
+
return null;
|
|
133
|
+
if (column.subrow && column.subrow > 0 && subrowIndex > 0)
|
|
134
|
+
return null;
|
|
135
|
+
const value = column.id ? getNestedValue(row, column.id) : null;
|
|
136
|
+
return (_jsx("td", { style: { textAlign: column.align || "left" }, className: `
|
|
128
137
|
${column.datatype === "number" || column.datatype === "currency" ? "dt-numeric" : ""}
|
|
129
138
|
${column.datatype === "boolean" ? "dt-boolean" : ""}
|
|
130
139
|
`.trim(), onClick: (e) => handleCellClick(e, value, row, column, itemIndex, colIndex), children: renderCellContent(row, column, itemIndex) }, getColumnKey(column, colIndex)));
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
140
|
+
}), rowActions && subrowIndex === 0 && (_jsx("td", { className: "dt-actions-cell", rowSpan: rowsPerItem, children: rowActions(row, itemIndex) }))] }, `${getRowKey(row)}-subrow-${subrowIndex}`) }, generateKey()));
|
|
141
|
+
}
|
|
142
|
+
return rows;
|
|
143
|
+
}), [...Array(fillerCount)].map((_, i) => (_jsx("tr", { className: "filler-row", children: [...Array(colCount)].map((_, j) => (_jsx("td", { children: "\u00A0" }, j))) }, `filler-${i}`)))] }));
|
|
135
144
|
});
|
|
136
145
|
// ============================================================================
|
|
137
146
|
// DATATABLE COMPONENT
|
|
138
147
|
// ============================================================================
|
|
139
148
|
export const DataTable = ({
|
|
140
149
|
// Direct props (fallback when used outside TableProvider)
|
|
141
|
-
data: propData, columns: propColumns, loading: propLoading = false, emptyMessage = "No data available", striped = false, bordered = false, hover = true, dense = false, stickyHeader = false, maxHeight, rowKey = "id", onRowClick, onCellClick, selectedRows = [], onSelectionChange, selectable = false, className = "", rowClassName, cellRenderer, headerRenderer, multiRowHeader, rowActions, rowsPerItem = 1, }) => {
|
|
150
|
+
data: propData, columns: propColumns, loading: propLoading = false, emptyMessage = "No data available", striped = false, bordered = false, hover = true, dense = false, stickyHeader = false, maxHeight, rowKey = "id", onRowClick, onCellClick, selectedRows = [], onSelectionChange, selectable = false, className = "", rowClassName, cellRenderer, headerRenderer, multiRowHeader, rowActions, rowsPerItem = 1, rowsPerPage = 10, }) => {
|
|
142
151
|
var _a, _b;
|
|
143
152
|
// Try to consume context; if not inside a provider, ctx will be null.
|
|
144
153
|
let ctxColumns;
|
|
@@ -248,6 +257,6 @@ data: propData, columns: propColumns, loading: propLoading = false, emptyMessage
|
|
|
248
257
|
if (loading) {
|
|
249
258
|
return (_jsxs("div", { className: "dt-loading", children: [_jsx("div", { className: "dt-spinner" }), _jsx("p", { children: "Loading..." })] }));
|
|
250
259
|
}
|
|
251
|
-
return (_jsx("div", { className: "dt-container", style: containerStyle, children: _jsxs("table", { className: tableClasses, children: [_jsx("thead", { children: _jsx(TableHeader, { visibleColumns: visibleColumns, selectable: selectable, rowActions: rowActions, data: data, selectedRows: selectedRows, handleSelectAll: handleSelectAll, sortConfig: sortConfig, handleSort: handleSort, headerRenderer: headerRenderer, multiRowHeader: multiRowHeader }) }), _jsx("tbody", { children: _jsx(TableBody, { sortedData: sortedData, visibleColumns: visibleColumns, emptyMessage: emptyMessage, selectable: selectable, rowActions: rowActions, selectedRows: selectedRows, handleSelectRow: handleSelectRow, handleRowClick: handleRowClick, handleCellClick: handleCellClick, rowClassName: rowClassName, rowKey: rowKey, rowsPerItem: rowsPerItem, cellRenderer: cellRenderer }) })] }) }));
|
|
260
|
+
return (_jsx("div", { className: "dt-container", style: containerStyle, children: _jsxs("table", { className: tableClasses, children: [_jsx("thead", { children: _jsx(TableHeader, { visibleColumns: visibleColumns, selectable: selectable, rowActions: rowActions, data: data, selectedRows: selectedRows, handleSelectAll: handleSelectAll, sortConfig: sortConfig, handleSort: handleSort, headerRenderer: headerRenderer, multiRowHeader: multiRowHeader }) }), _jsx("tbody", { children: _jsx(TableBody, { sortedData: sortedData, visibleColumns: visibleColumns, emptyMessage: emptyMessage, selectable: selectable, rowActions: rowActions, selectedRows: selectedRows, handleSelectRow: handleSelectRow, handleRowClick: handleRowClick, handleCellClick: handleCellClick, rowClassName: rowClassName, rowKey: rowKey, rowsPerItem: rowsPerItem, cellRenderer: cellRenderer, rowsPerPage: rowsPerPage }) })] }) }));
|
|
252
261
|
};
|
|
253
262
|
export default DataTable;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import VPanel from "../../layouts/VPanel";
|
|
2
|
+
import { VPanel } from "../../layouts/VPanel";
|
|
3
3
|
import { renderListDef } from "../../lib/utils/SectionProvider";
|
|
4
4
|
const FilterView = (props) => {
|
|
5
5
|
const { items = [] } = props !== null && props !== void 0 ? props : {};
|