@ramesesinc/platform-core 0.1.6 → 0.1.9

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.
Files changed (90) hide show
  1. package/dist/components/action/LookupPage.js +9 -31
  2. package/dist/components/action/ViewPage.d.ts +2 -0
  3. package/dist/components/action/ViewPage.js +25 -31
  4. package/dist/components/common/UIComponent.js +4 -3
  5. package/dist/components/index.d.ts +3 -0
  6. package/dist/components/index.js +1 -0
  7. package/dist/components/table/DataList.js +2 -2
  8. package/dist/components/view/PopupView.d.ts +13 -0
  9. package/dist/components/view/PopupView.js +25 -20
  10. package/dist/core/DataContext.d.ts +7 -4
  11. package/dist/core/DataContext.js +16 -4
  12. package/dist/core/Page.js +25 -26
  13. package/dist/core/PageCache.js +7 -7
  14. package/dist/core/PageContext.js +17 -7
  15. package/dist/core/PageViewContext.d.ts +13 -1
  16. package/dist/core/PageViewContext.js +75 -2
  17. package/dist/core/PopupContext.d.ts +49 -0
  18. package/dist/core/PopupContext.js +380 -0
  19. package/dist/core/RowContext.js +1 -1
  20. package/dist/core/WindowContext.d.ts +15 -0
  21. package/dist/core/WindowContext.js +28 -0
  22. package/dist/core/index.d.ts +17 -0
  23. package/dist/core/index.js +1 -0
  24. package/dist/index.css +25 -7
  25. package/dist/lib/utils/BeanUtils.js +7 -7
  26. package/dist/templates/DataListTemplate.js +7 -2
  27. package/dist/templates/ExplorerTemplate.js +1 -1
  28. package/package.json +5 -5
  29. package/dist/components/action/AlertMessage.tsx +0 -38
  30. package/dist/components/action/Button.tsx +0 -230
  31. package/dist/components/action/CancelEdit.tsx +0 -40
  32. package/dist/components/action/DeleteData.tsx +0 -73
  33. package/dist/components/action/Edit.tsx +0 -40
  34. package/dist/components/action/LookupPage.tsx +0 -113
  35. package/dist/components/action/ProcessRunner.tsx +0 -337
  36. package/dist/components/action/Refresh.tsx +0 -35
  37. package/dist/components/action/SaveData.tsx +0 -74
  38. package/dist/components/action/SelectData.tsx +0 -47
  39. package/dist/components/action/Undo.tsx +0 -50
  40. package/dist/components/action/UpdateData.tsx +0 -49
  41. package/dist/components/action/UpdateState.tsx +0 -40
  42. package/dist/components/action/ViewBackPage.tsx +0 -46
  43. package/dist/components/action/ViewPage.tsx +0 -141
  44. package/dist/components/common/UIComponent.tsx +0 -86
  45. package/dist/components/common/UIInput.tsx +0 -49
  46. package/dist/components/common/UIMenu.tsx +0 -91
  47. package/dist/components/index.ts +0 -51
  48. package/dist/components/input/CodeEditor.tsx +0 -188
  49. package/dist/components/input/DateField.tsx +0 -274
  50. package/dist/components/input/DayPicker.tsx +0 -5
  51. package/dist/components/input/HtmlCode.tsx +0 -203
  52. package/dist/components/input/JsonCode.tsx +0 -205
  53. package/dist/components/input/MonthPicker.tsx +0 -5
  54. package/dist/components/input/ScriptCode.tsx +0 -195
  55. package/dist/components/input/Select.tsx +0 -78
  56. package/dist/components/input/SqlCode.tsx +0 -162
  57. package/dist/components/input/StringDecision.tsx +0 -64
  58. package/dist/components/input/Text.tsx +0 -57
  59. package/dist/components/input/YearPicker.tsx +0 -81
  60. package/dist/components/list/IconMenu.tsx +0 -115
  61. package/dist/components/list/TabMenu.tsx +0 -127
  62. package/dist/components/list/TreeMenu.tsx +0 -279
  63. package/dist/components/list/TxnTaskList.tsx +0 -198
  64. package/dist/components/output/Label.tsx +0 -50
  65. package/dist/components/table/DataList.tsx +0 -820
  66. package/dist/components/table/DataTable.tsx +0 -572
  67. package/dist/components/table/ListHandler.ts +0 -276
  68. package/dist/components/table/TableContext.tsx +0 -122
  69. package/dist/components/view/ComponentView.tsx +0 -102
  70. package/dist/components/view/FilterView.tsx +0 -21
  71. package/dist/components/view/HtmlForm.tsx +0 -176
  72. package/dist/components/view/HtmlView.tsx +0 -98
  73. package/dist/components/view/IFrameView.tsx +0 -48
  74. package/dist/components/view/Modal.tsx +0 -72
  75. package/dist/components/view/PageView.tsx +0 -131
  76. package/dist/components/view/PopupView.tsx +0 -160
  77. package/dist/components/view/RootView.tsx +0 -109
  78. package/dist/components/view/WizardView.tsx +0 -48
  79. package/dist/lib/layouts/BorderLayout.tsx +0 -31
  80. package/dist/lib/layouts/CardLayout.tsx +0 -73
  81. package/dist/lib/layouts/CenterLayout.tsx +0 -20
  82. package/dist/lib/layouts/GridLayout.tsx +0 -20
  83. package/dist/lib/layouts/HPanel.tsx +0 -31
  84. package/dist/lib/layouts/HorizontalLayout.tsx +0 -29
  85. package/dist/lib/layouts/MainLayout.tsx +0 -16
  86. package/dist/lib/layouts/PageLayout.tsx +0 -29
  87. package/dist/lib/layouts/VPanel.tsx +0 -27
  88. package/dist/lib/layouts/XLayout.tsx +0 -29
  89. package/dist/lib/layouts/YLayout.tsx +0 -29
  90. package/dist/lib/layouts/index.ts +0 -13
@@ -1,113 +0,0 @@
1
- "use client";
2
-
3
- import React, { forwardRef, memo, useImperativeHandle, useRef, useState } from "react";
4
- import { usePageContext } from "../../core/PageContext";
5
- import { getValue, substituteExpr } from "../../lib/utils/BeanUtils";
6
- import { AbstractComponent } from "../../types/component";
7
- import PopupView from "../view/PopupView";
8
-
9
- /* ------------------------------------------------------------------ */
10
- /* Types */
11
-
12
- interface LookupPageProps extends AbstractComponent {
13
- url: string;
14
- name?: string;
15
- result?: Record<string, any>;
16
- children?: React.ReactNode;
17
- className?: string;
18
- title?: string;
19
- icon?: string;
20
- opt?: Record<string, any>;
21
- iconOnly?: boolean; // ✅ added
22
- popupClassName?: string;
23
- }
24
-
25
- /* ------------------------------------------------------------------ */
26
- /* Component */
27
-
28
- const LookupPage = (props: LookupPageProps) => {
29
- const { url, name = "", result = null, children, className = "", title, icon, opt = {}, popupClassName = "", iconOnly = false } = props ?? {};
30
- const { data = {} } = opt;
31
-
32
- const pageContext = usePageContext();
33
- const [showPopup, setShowPopup] = useState(false);
34
- const [popupUrl, setPopupUrl] = useState("");
35
- const slotRef = useRef<ChildrenSlotHandle>(null);
36
-
37
- const onClose = () => {
38
- slotRef.current?.update(null);
39
- };
40
-
41
- /* ---------------------- Events ---------------------- */
42
- const handleClick = () => {
43
- if (!url) return;
44
- //combine data if specified and pageContext all data if specified
45
- const surl = substituteExpr(url, { ...pageContext?.getAllData(), ...data });
46
- setPopupUrl(surl);
47
- setShowPopup(true);
48
-
49
- const handler = {
50
- onSelect: (itm: any) => {
51
- let resdata = itm;
52
- if (result != null) {
53
- resdata = getValue(result, itm);
54
- }
55
- alert("item selected " + JSON.stringify(resdata));
56
- if (name) {
57
- pageContext.set(name, resdata);
58
- }
59
- onClose();
60
- //pageContext.refresh();
61
- },
62
- };
63
- //eventHandler={handler}
64
- slotRef.current?.update(<PopupView url={surl} onClose={onClose} eventHandler={handler} />);
65
- };
66
-
67
- const handleClosePopup = () => {
68
- setShowPopup(false);
69
- };
70
-
71
- /* ---------------------- Render ---------------------- */
72
- return (
73
- <>
74
- {iconOnly ? (
75
- <span onClick={handleClick} className={`cursor-pointer ${className}`}>
76
- {icon}
77
- </span>
78
- ) : (
79
- <button onClick={handleClick} className={`px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors ${className}`}>
80
- {icon && <span className="dl-action-icon">{icon}</span>}
81
- {title || "View Page"}
82
- </button>
83
- )}
84
-
85
- <ChildrenSlot ref={slotRef} />
86
- </>
87
- );
88
- };
89
-
90
- export default LookupPage;
91
-
92
- type ChildrenSlotHandle = {
93
- update: (content: React.ReactNode) => void;
94
- };
95
-
96
- const ChildrenSlot = memo(
97
- forwardRef<ChildrenSlotHandle>((_, ref) => {
98
- const [content, setContent] = useState<React.ReactNode>(null);
99
-
100
- useImperativeHandle(
101
- ref,
102
- () => ({
103
- update: (content: React.ReactNode) => {
104
- // console.log("view page children slot", content);
105
- setContent(content);
106
- },
107
- }),
108
- [],
109
- );
110
-
111
- return <>{content == null ? null : content}</>;
112
- }),
113
- );
@@ -1,337 +0,0 @@
1
- "use client";
2
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
- import { usePageContext } from "../../core/PageContext";
4
- import { getValue, substituteExpr } from "../../lib/utils/BeanUtils";
5
- import { getUrlPageParams } from "../../lib/utils/PageUtils";
6
- import { AbstractComponent } from "../../types/component";
7
-
8
- /* ------------------------------------------------------------------ */
9
- /* Types */
10
-
11
- // Display state is always derived from the server record — never set directly.
12
- type RunnerState = "idle" | "running" | "paused" | "done";
13
-
14
- interface ProcessRunnerProps extends AbstractComponent {
15
- /**
16
- * Field expression for current progress value. Default: "{processedcount}"
17
- */
18
- value?: string;
19
- /**
20
- * Field expression for max value. Default: "{totalcount}"
21
- */
22
- maxValue?: string;
23
- /**
24
- * Field expression resolving to the server-side status field.
25
- * Expected values (case-insensitive): IDLE | RUNNING | PAUSED | DONE.
26
- * Default: "{status}"
27
- */
28
- statusValue?: string;
29
- /**
30
- * Optional label expression shown below the bar.
31
- * Only rendered when provided.
32
- * Example: "{processedcount} of {totalcount} records processed"
33
- */
34
- labelExpr?: string;
35
- /**
36
- * Data config: the API endpoint polled on interval to refresh the record.
37
- * Should return the single record object: { _id, status, processedcount, totalcount, ... }
38
- * May contain bound param expressions, e.g. "/processtask?_id={_id}"
39
- *
40
- * Note: The DataList (parent) fetches the initial list. This component
41
- * polls independently for live updates on its own record.
42
- */
43
- data?: {
44
- api: string;
45
- /** Action APIs called on button click, then immediately re-fetches. */
46
- actions?: {
47
- start?: string; // e.g. "/processtask/start?_id={_id}"
48
- pause?: string; // e.g. "/processtask/pause?_id={_id}"
49
- resume?: string; // e.g. "/processtask/resume?_id={_id}"
50
- end?: string; // e.g. "/processtask/end?_id={_id}"
51
- };
52
- };
53
- /**
54
- * Polling interval in milliseconds. Default: 5000.
55
- * Timer only fires while status === "running".
56
- */
57
- interval?: number;
58
- /** Button label overrides */
59
- labels?: {
60
- start?: string;
61
- pause?: string;
62
- resume?: string;
63
- end?: string;
64
- };
65
- /**
66
- * Row data injected by the Table renderer (same as ViewPage opt.data).
67
- * Carries the initial record: { _id, status, processedcount, totalcount }
68
- * This is the seed — polling overlays it with fresh values.
69
- */
70
- opt?: Record<string, any>;
71
- className?: string;
72
- }
73
-
74
- /* ------------------------------------------------------------------ */
75
- /* Helpers */
76
-
77
- const toRunnerState = (raw: unknown): RunnerState => {
78
- switch (String(raw ?? "").toUpperCase()) {
79
- case "RUNNING":
80
- return "running";
81
- case "PAUSED":
82
- return "paused";
83
- case "DONE":
84
- return "done";
85
- default:
86
- return "idle";
87
- }
88
- };
89
-
90
- const resolveNumeric = (expr: string, data: Record<string, any>): number => {
91
- const n = Number(getValue(expr, data));
92
- return isNaN(n) ? 0 : n;
93
- };
94
-
95
- /* ------------------------------------------------------------------ */
96
- /* Component */
97
- const ProcessRunner = (props: ProcessRunnerProps) => {
98
- const {
99
- value: valueProp = "{processedcount}",
100
- maxValue: maxValueProp = "{totalcount}",
101
- statusValue = "{status}",
102
- labelExpr,
103
- data,
104
- interval = 5000,
105
- labels = {},
106
- opt = {},
107
- className = "",
108
- } = props ?? {};
109
-
110
- const { data: optData = {} } = opt;
111
-
112
- const { start: startLabel = "Start", pause: pauseLabel = "Pause", resume: resumeLabel = "Resume", end: endLabel = "End" } = labels;
113
-
114
- const pageContext = usePageContext();
115
-
116
- /* ----------------------------------------------------------------
117
- liveData is the SOLE source of truth.
118
-
119
- Seed it with optData (the row record from DataList) so the
120
- component displays correctly on first render — before any poll fires.
121
- Subsequent polls overwrite it entirely with the server's response.
122
- ---------------------------------------------------------------- */
123
- const [liveData, setLiveData] = useState<Record<string, any>>(optData);
124
- const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
125
- const [isBusy, setIsBusy] = useState(false); // prevents double-clicks during action API call
126
-
127
- // When optData changes from outside (table refresh, parent re-render),
128
- // merge it in — but don't overwrite fields already updated by polling.
129
- useEffect(() => {
130
- setLiveData((prev) => ({ ...optData, ...prev }));
131
- }, [optData]);
132
-
133
- /* ----------------------------------------------------------------
134
- Resolution context — built from all data sources.
135
- Priority (low → high): url params → page data → liveData
136
- liveData already contains optData as its seed, so per-row fields
137
- like {_id} resolve correctly from the very first render.
138
- ---------------------------------------------------------------- */
139
- const resolveCtx = useMemo(() => {
140
- const { params } = getUrlPageParams();
141
- return {
142
- ...params,
143
- ...pageContext.getAllData(),
144
- ...optData, // row record from Table — always live, not just a one-time seed
145
- ...liveData, // polled data wins last — overwrites optData after first fetch
146
- };
147
- }, [liveData, optData, pageContext]);
148
-
149
- /* ----------------------------------------------------------------
150
- All display values are derived from resolveCtx — no separate state.
151
- This is what makes multi-browser sync work: any change in the DB
152
- flows through poll → liveData → resolveCtx → these values → render.
153
- ---------------------------------------------------------------- */
154
- const state = toRunnerState(getValue(statusValue, resolveCtx));
155
- const currentValue = resolveNumeric(valueProp, resolveCtx);
156
- const maxValue = resolveNumeric(maxValueProp, resolveCtx);
157
- const percent = maxValue > 0 ? Math.min((currentValue / maxValue) * 100, 100) : 0;
158
- const resolvedLabel = labelExpr ? substituteExpr(labelExpr, resolveCtx) : null;
159
-
160
- /* ----------------------------------------------------------------
161
- Core fetch — retrieves the latest record and overwrites liveData.
162
- Called both by the interval timer AND immediately after button actions.
163
- ---------------------------------------------------------------- */
164
- const fetchRecord = useCallback(async () => {
165
- if (!data?.api) return;
166
- try {
167
- const url = substituteExpr(data.api, resolveCtx);
168
- const json = await pageContext?.execService(url, resolveCtx);
169
- if (!json) return;
170
- // Full overwrite — server response is authoritative.
171
- // state, currentValue, maxValue all re-derive from this on next render.
172
- setLiveData(json);
173
- } catch {
174
- // Silently ignore — next tick will retry
175
- }
176
- }, [data?.api, resolveCtx, pageContext]);
177
-
178
- /* ----------------------------------------------------------------
179
- Polling — only runs while state === "running".
180
- Starts automatically when state becomes "running" (either from a
181
- button click confirming via re-fetch, or from another browser
182
- changing the DB and the interval picking it up).
183
- ---------------------------------------------------------------- */
184
- const startPolling = useCallback(() => {
185
- if (intervalRef.current) return;
186
- intervalRef.current = setInterval(fetchRecord, interval);
187
- }, [fetchRecord, interval]);
188
-
189
- const stopPolling = useCallback(() => {
190
- if (intervalRef.current) {
191
- clearInterval(intervalRef.current);
192
- intervalRef.current = null;
193
- }
194
- }, []);
195
-
196
- // Manage timer based on derived state — not on button clicks.
197
- // This means another browser pausing/completing the job will also
198
- // stop the timer on this browser after the next tick confirms it.
199
- useEffect(() => {
200
- if (state === "running") {
201
- startPolling();
202
- } else {
203
- stopPolling();
204
- }
205
- }, [state, startPolling, stopPolling]);
206
-
207
- // Cleanup on unmount (row removed from table, page navigated away)
208
- useEffect(() => () => stopPolling(), [stopPolling]);
209
-
210
- /* ----------------------------------------------------------------
211
- Action handler — the key pattern for button clicks:
212
- 1. Call action API (POST/GET — whatever your backend expects)
213
- 2. Immediately re-fetch the record — don't wait for next tick
214
- 3. liveData updates → state re-derives → UI updates instantly
215
- No optimistic setState — server response is always the authority.
216
- ---------------------------------------------------------------- */
217
- const fireAction = useCallback(
218
- async (actionUrl: string | undefined) => {
219
- if (!actionUrl || isBusy) return;
220
- setIsBusy(true);
221
- try {
222
- const url = substituteExpr(actionUrl, resolveCtx);
223
- await pageContext?.execService(url, resolveCtx);
224
- } catch {
225
- // Action failed — re-fetch anyway to show real current state
226
- } finally {
227
- // Always re-fetch immediately after action — this is what makes
228
- // the button feel instant rather than waiting for the next tick.
229
- await fetchRecord();
230
- setIsBusy(false);
231
- }
232
- },
233
- [isBusy, resolveCtx, fetchRecord, pageContext],
234
- );
235
-
236
- /* ----------------------------------------------------------------
237
- Handlers — just delegate to fireAction with the right endpoint.
238
- If no action API is configured, fetchRecord still runs so the
239
- UI reflects whatever the server currently has.
240
- ---------------------------------------------------------------- */
241
- const handleStart = () => fireAction(data?.actions?.start);
242
- const handlePause = () => fireAction(data?.actions?.pause);
243
- const handleResume = () => fireAction(data?.actions?.resume);
244
- const handleEnd = () => fireAction(data?.actions?.end);
245
-
246
- /* ----------------------------------------------------------------
247
- Render
248
- ---------------------------------------------------------------- */
249
- return (
250
- <div className={`flex flex-col gap-2 ${className}`}>
251
- {/* IDLE — Start button */}
252
- {state === "idle" && (
253
- <button
254
- onClick={handleStart}
255
- disabled={isBusy}
256
- className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50 transition-colors text-sm font-medium"
257
- >
258
- {isBusy ? "…" : startLabel}
259
- </button>
260
- )}
261
-
262
- {/* RUNNING / PAUSED / DONE — progress bar + controls */}
263
- {state !== "idle" && (
264
- <div className="flex flex-col gap-1 w-full">
265
- <div className="flex items-center gap-2">
266
- {/* Bar */}
267
- <div
268
- className="flex-1 h-4 bg-gray-200 rounded-full overflow-hidden"
269
- role="progressbar"
270
- aria-valuenow={currentValue}
271
- aria-valuemin={0}
272
- aria-valuemax={maxValue || undefined}
273
- aria-label="Process progress"
274
- >
275
- <div
276
- className={`h-full rounded-full transition-all duration-500 ${
277
- state === "done" ? "bg-green-500" : state === "paused" ? "bg-yellow-400" : "bg-blue-500"
278
- }`}
279
- style={{ width: `${percent}%` }}
280
- />
281
- </div>
282
-
283
- {/* Percent */}
284
- <span className="text-xs text-gray-600 w-10 text-right tabular-nums">{Math.round(percent)}%</span>
285
-
286
- {/* RUNNING → Pause */}
287
- {state === "running" && (
288
- <button
289
- onClick={handlePause}
290
- disabled={isBusy}
291
- className="px-3 py-1 bg-yellow-400 text-yellow-900 rounded-md hover:bg-yellow-500 disabled:opacity-50 transition-colors text-xs font-medium"
292
- >
293
- {isBusy ? "…" : pauseLabel}
294
- </button>
295
- )}
296
-
297
- {/* PAUSED → Resume | End */}
298
- {state === "paused" && (
299
- <>
300
- <button
301
- onClick={handleResume}
302
- disabled={isBusy}
303
- className="px-3 py-1 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50 transition-colors text-xs font-medium"
304
- >
305
- {isBusy ? "…" : resumeLabel}
306
- </button>
307
- <button
308
- onClick={handleEnd}
309
- disabled={isBusy}
310
- className="px-3 py-1 bg-gray-500 text-white rounded-md hover:bg-gray-600 disabled:opacity-50 transition-colors text-xs font-medium"
311
- >
312
- {isBusy ? "…" : endLabel}
313
- </button>
314
- </>
315
- )}
316
-
317
- {/* DONE → End (reset) */}
318
- {state === "done" && (
319
- <button
320
- onClick={handleEnd}
321
- disabled={isBusy}
322
- className="px-3 py-1 bg-green-600 text-white rounded-md hover:bg-green-700 disabled:opacity-50 transition-colors text-xs font-medium"
323
- >
324
- {isBusy ? "…" : endLabel}
325
- </button>
326
- )}
327
- </div>
328
-
329
- {/* Label below bar — only when labelExpr is provided */}
330
- {resolvedLabel && <p className="text-xs text-gray-500 mt-0.5">{resolvedLabel}</p>}
331
- </div>
332
- )}
333
- </div>
334
- );
335
- };
336
-
337
- export default ProcessRunner;
@@ -1,35 +0,0 @@
1
- "use client";
2
-
3
- import { usePageContext } from "../../core/PageContext";
4
- import { AbstractComponent } from "../../types/component";
5
-
6
- /* ------------------------------------------------------------------ */
7
- /* Types */
8
-
9
- interface RefreshProps extends AbstractComponent {
10
- className?: string;
11
- title?: string;
12
- }
13
-
14
- /* ------------------------------------------------------------------ */
15
- /* Component */
16
-
17
- const Refresh = (props: RefreshProps) => {
18
- const { className = "", title } = props ?? {};
19
- const pageContext = usePageContext();
20
-
21
- /* ---------------------- Events ---------------------- */
22
- const handleClick = () => {
23
- // console.log("Refresh button", pageContext.refresh());
24
- pageContext.notifyDepends();
25
- };
26
-
27
- /* ---------------------- Render ---------------------- */
28
- return (
29
- <button onClick={handleClick} className={`px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors ${className}`}>
30
- {title || "Refresh"}
31
- </button>
32
- );
33
- };
34
-
35
- export default Refresh;
@@ -1,74 +0,0 @@
1
- "use client";
2
-
3
- import { usePageContext } from "../../core/PageContext";
4
- import { usePageViewContext } from "../../core/PageViewContext";
5
- import { getValue } from "../../lib/utils/BeanUtils";
6
- import { getUrlPageParams } from "../../lib/utils/PageUtils";
7
- import { AbstractComponent } from "../../types/component";
8
-
9
- /* ------------------------------------------------------------------ */
10
- /* Types */
11
-
12
- interface SaveDataProps extends AbstractComponent {
13
- className?: string;
14
- title?: string;
15
- api: string;
16
- params?: string;
17
- data?: Record<string, any> | null;
18
- }
19
-
20
- /* ------------------------------------------------------------------ */
21
- /* Component */
22
-
23
- const SaveData = (props: SaveDataProps) => {
24
- const { className = "", title, api, params, data = {} } = props ?? {};
25
- // console.log("save data props", { api, params, props });
26
- const pageContext = usePageContext();
27
- const pageViewContext = usePageViewContext();
28
-
29
- /* ---------------------- Events ---------------------- */
30
- const handleClick = async (e: React.MouseEvent<HTMLButtonElement>) => {
31
- e.preventDefault();
32
-
33
- try {
34
- if (!api) throw new Error("api not defined");
35
- if (params) {
36
- const allData = pageContext?.getAllData() ?? {};
37
- // console.log("save data 1.1", allData);
38
- const urlParams = getUrlPageParams() ?? {};
39
- // console.log("save data 1.2", urlParams);
40
- const d = getValue(params, { ...allData, ...urlParams?.params });
41
- // console.log("save data", { api, d });
42
-
43
- // console.log("data before save is ", params, d);
44
- // throw new Error("test error");
45
- await pageContext?.execService(api, d);
46
- } else {
47
- const vdata = pageContext?.getData() ?? {};
48
- const req = {
49
- data: vdata,
50
- };
51
- // console.log("save data", { api, vdata });
52
- await pageContext?.execService(api, req);
53
- }
54
-
55
- const eventHandler = pageViewContext.getEventHandler() ?? {};
56
- const { onSave } = eventHandler;
57
- if (typeof onSave === "function") {
58
- onSave({});
59
- }
60
- } catch (err: any) {
61
- console.log("error save data", err);
62
- alert(err.message);
63
- }
64
- };
65
-
66
- /* ---------------------- Render ---------------------- */
67
- return (
68
- <button onClick={handleClick} className={`px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors ${className}`}>
69
- {title || "Save"}
70
- </button>
71
- );
72
- };
73
-
74
- export default SaveData;
@@ -1,47 +0,0 @@
1
- "use client";
2
-
3
- import { usePageContext } from "../../core/PageContext";
4
- import { usePageViewContext } from "../../core/PageViewContext";
5
- import { AbstractComponent } from "../../types/component";
6
-
7
- /* ------------------------------------------------------------------ */
8
- /* Types */
9
-
10
- interface SelectDataProps extends AbstractComponent {
11
- className?: string;
12
- title?: string;
13
- name: string; //target name of data to extract
14
- }
15
-
16
- /* ------------------------------------------------------------------ */
17
- /* Component */
18
-
19
- const SelectData = (props: SelectDataProps) => {
20
- const { className = "", title, name } = props ?? {};
21
- const pageContext = usePageContext();
22
- const pageViewContext = usePageViewContext();
23
-
24
- /* ---------------------- Events ---------------------- */
25
- const handleClick = async () => {
26
- try {
27
- const eventHandler = pageViewContext.getEventHandler() ?? {};
28
- const { onSelect } = eventHandler;
29
-
30
- if (typeof onSelect === "function") {
31
- const d = pageContext.get(name);
32
- onSelect(d);
33
- }
34
- } catch (err: any) {
35
- alert(err.message);
36
- }
37
- };
38
-
39
- /* ---------------------- Render ---------------------- */
40
- return (
41
- <button onClick={handleClick} className={`px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors ${className}`}>
42
- {title || "Save"}
43
- </button>
44
- );
45
- };
46
-
47
- export default SelectData;
@@ -1,50 +0,0 @@
1
- "use client";
2
-
3
- import { usePageContext } from "../../core/PageContext";
4
- import { AbstractComponent } from "../../types/component";
5
-
6
- /* ------------------------------------------------------------------ */
7
- /* Types */
8
-
9
- interface UndoProps extends AbstractComponent {
10
- className?: string;
11
- title?: string;
12
- api: string;
13
- data?: string;
14
- }
15
-
16
- /* ------------------------------------------------------------------ */
17
- /* Component */
18
-
19
- const Undo = (props: UndoProps) => {
20
- const { className = "", title, api, data } = props ?? {};
21
- const pageContext = usePageContext();
22
-
23
- /* ---------------------- Events ---------------------- */
24
- const handleClick = async () => {
25
- try {
26
- /*
27
- if(!api) throw new Error("api not defined");
28
- const allData = pageContext?.getAllData() ?? {};
29
- if( data ) {
30
- const d = getValue( data, allData );
31
- await pageContext?.execService( api, d );
32
- }
33
- else {
34
- await pageContext?.execService( api, allData );
35
- }
36
- */
37
- } catch (err: any) {
38
- alert(err.message);
39
- }
40
- };
41
-
42
- /* ---------------------- Render ---------------------- */
43
- return (
44
- <button onClick={handleClick} className={`px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors ${className}`}>
45
- {title || "Update Context"}
46
- </button>
47
- );
48
- };
49
-
50
- export default Undo;