@nocobase/plugin-flow-engine 2.1.0-alpha.9 → 2.1.0-beta.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.
Files changed (51) hide show
  1. package/dist/ai/docs/runjs/context/block-model.md +35 -35
  2. package/dist/ai/docs/runjs/context/collection-field.md +51 -53
  3. package/dist/ai/docs/runjs/context/collection.md +39 -39
  4. package/dist/ai/docs/runjs/context/data-source-manager.md +30 -40
  5. package/dist/ai/docs/runjs/context/data-source.md +44 -52
  6. package/dist/ai/docs/runjs/context/element.md +38 -44
  7. package/dist/ai/docs/runjs/context/exit-all.md +35 -37
  8. package/dist/ai/docs/runjs/context/exit.md +35 -38
  9. package/dist/ai/docs/runjs/context/filter-manager.md +30 -36
  10. package/dist/ai/docs/runjs/context/form.md +57 -57
  11. package/dist/ai/docs/runjs/context/get-model.md +21 -22
  12. package/dist/ai/docs/runjs/context/get-value.md +19 -20
  13. package/dist/ai/docs/runjs/context/get-var.md +55 -61
  14. package/dist/ai/docs/runjs/context/i18n.md +14 -17
  15. package/dist/ai/docs/runjs/context/import-async.md +45 -333
  16. package/dist/ai/docs/runjs/context/init-resource.md +20 -20
  17. package/dist/ai/docs/runjs/context/libs.md +31 -31
  18. package/dist/ai/docs/runjs/context/location.md +31 -34
  19. package/dist/ai/docs/runjs/context/logger.md +40 -41
  20. package/dist/ai/docs/runjs/context/make-resource.md +26 -27
  21. package/dist/ai/docs/runjs/context/message.md +41 -42
  22. package/dist/ai/docs/runjs/context/modal.md +44 -44
  23. package/dist/ai/docs/runjs/context/model.md +33 -36
  24. package/dist/ai/docs/runjs/context/notification.md +40 -41
  25. package/dist/ai/docs/runjs/context/off.md +14 -14
  26. package/dist/ai/docs/runjs/context/on.md +29 -30
  27. package/dist/ai/docs/runjs/context/open-view.md +40 -40
  28. package/dist/ai/docs/runjs/context/render.md +32 -37
  29. package/dist/ai/docs/runjs/context/request.md +45 -46
  30. package/dist/ai/docs/runjs/context/require-async.md +25 -28
  31. package/dist/ai/docs/runjs/context/resource.md +34 -34
  32. package/dist/ai/docs/runjs/context/route.md +34 -36
  33. package/dist/ai/docs/runjs/context/router.md +31 -43
  34. package/dist/ai/docs/runjs/context/set-value.md +17 -18
  35. package/dist/ai/docs/runjs/context/t.md +17 -20
  36. package/dist/ai/docs/runjs/context/view.md +46 -49
  37. package/dist/ai/docs/runjs/document.md +0 -1
  38. package/dist/ai/docs/runjs/import-modules.md +32 -32
  39. package/dist/ai/docs/runjs/index.md +13 -13
  40. package/dist/ai/docs/runjs/jsx.md +19 -19
  41. package/dist/ai/docs/runjs/model/form-block-model.md +3 -1
  42. package/dist/ai/docs/runjs/render.md +15 -15
  43. package/dist/ai/docs/runjs/resource/api-resource.md +53 -53
  44. package/dist/ai/docs/runjs/resource/multi-record-resource.md +64 -64
  45. package/dist/ai/docs/runjs/resource/single-record-resource.md +55 -55
  46. package/dist/ai/docs/runjs/resource/sql-resource.md +57 -57
  47. package/dist/ai/docs/runjs/window.md +5 -5
  48. package/dist/externalVersion.js +10 -10
  49. package/dist/node_modules/ses/package.json +1 -1
  50. package/dist/node_modules/zod/package.json +1 -1
  51. package/package.json +2 -2
@@ -1,16 +1,16 @@
1
1
  # ctx.importAsync()
2
2
 
3
- Dynamically load **ESM modules** or **CSS** via URL, applicable to various RunJS scenarios. Use `ctx.importAsync()` when third-party ESM libraries are required, and `ctx.requireAsync()` for UMD/AMD libraries. Passing a `.css` address will load and inject the styles into the page.
3
+ Dynamically loads **ESM modules** or **CSS** by URL; use in all RunJS scenarios. For third-party ESM use `ctx.importAsync()`; for UMD/AMD use `ctx.requireAsync()`. Pass a `.css` URL to load and inject styles.
4
4
 
5
5
  ## Use Cases
6
6
 
7
7
  | Scenario | Description |
8
- |------|------|
9
- | **JSBlock** | Dynamically load ESM libraries such as Vue, ECharts, or Tabulator to implement custom charts, tables, dashboards, etc. |
10
- | **JSField / JSItem / JSColumn** | Load lightweight ESM utility libraries (e.g., dayjs plugins) to assist in rendering. |
11
- | **Workflow / Action Events** | Load dependencies on demand before executing business logic. |
8
+ |----------|-------------|
9
+ | **JSBlock** | Load Vue, ECharts, Tabulator, etc. for custom charts, tables, boards |
10
+ | **JSField / JSItem / JSColumn** | Load small ESM utils (e.g. dayjs plugins) for rendering |
11
+ | **Event flow / action events** | Load dependencies then run logic |
12
12
 
13
- ## Type Definition
13
+ ## Type
14
14
 
15
15
  ```ts
16
16
  importAsync<T = any>(url: string): Promise<T>;
@@ -19,134 +19,90 @@ importAsync<T = any>(url: string): Promise<T>;
19
19
  ## Parameters
20
20
 
21
21
  | Parameter | Type | Description |
22
- |------|------|------|
23
- | `url` | `string` | The address of the ESM module or CSS. Supports shorthand `<package>@<version>` or subpaths `<package>@<version>/<file-path>` (e.g., `vue@3.4.0`, `dayjs@1/plugin/relativeTime.js`), which will be concatenated with the CDN prefix according to the configuration. Full URLs are also supported. When a `.css` file is passed, it will be loaded and injected as a style. For libraries depending on React, you can append `?deps=react@18.2.0,react-dom@18.2.0` to ensure they share the same React instance with the page. |
22
+ |-----------|------|-------------|
23
+ | `url` | `string` | ESM or CSS URL. Supports shorthand `<package>@<version>` or subpath `<package>@<version>/<path>` (e.g. `vue@3.4.0`, `dayjs@1/plugin/relativeTime.js`), resolved with configured CDN prefix; full URLs also supported. For `.css` URLs, loads and injects styles. For React-dependent libs add `?deps=react@18.2.0,react-dom@18.2.0` to share the same React instance. |
24
24
 
25
- ## Return Value
25
+ ## Returns
26
26
 
27
- - A Promise that resolves to the module's namespace object.
27
+ - Resolved module namespace object (Promise value).
28
28
 
29
- ## URL Format Description
29
+ ## URL format
30
30
 
31
- - **ESM and CSS**: In addition to ESM modules, loading CSS is also supported (pass a `.css` URL to load and inject it into the page).
32
- - **Shorthand Format**: Defaults to **https://esm.sh** as the CDN prefix if not configured. For example, `vue@3.4.0` actually requests `https://esm.sh/vue@3.4.0`.
33
- - **?deps**: Libraries that depend on React (such as `@dnd-kit/core`, `react-big-calendar`) should append `?deps=react@18.2.0,react-dom@18.2.0` to avoid conflicts with the page's React instance, which could lead to "Invalid hook call" errors.
34
- - **Self-hosted CDN**: You can specify an internal network or self-hosted service via environment variables:
35
- - **ESM_CDN_BASE_URL**: The base URL for the ESM CDN (default is `https://esm.sh`).
36
- - **ESM_CDN_SUFFIX**: Optional suffix (e.g., `/+esm` for jsDelivr).
37
- - For self-hosted services, refer to: [nocobase/esm-server](https://github.com/nocobase/esm-server)
31
+ - **ESM and CSS**: Besides ESM, you can load CSS (pass a `.css` URL; it is injected into the page).
32
+ - **Shorthand**: When not configured, **https://esm.sh** is used as CDN prefix. E.g. `vue@3.4.0` `https://esm.sh/vue@3.4.0`.
33
+ - **?deps**: For React-dependent libs (e.g. `@dnd-kit/core`, `react-big-calendar`) add `?deps=react@18.2.0,react-dom@18.2.0` to avoid Invalid hook call from multiple React instances.
34
+ - **Self-hosted CDN**: Set env vars for intranet or custom service:
35
+ - **ESM_CDN_BASE_URL**: ESM CDN base (default `https://esm.sh`)
36
+ - **ESM_CDN_SUFFIX**: Optional suffix (e.g. jsDelivr `/+esm`)
37
+ - Reference: [nocobase/esm-server](https://github.com/nocobase/esm-server)
38
38
 
39
- ## Difference from ctx.requireAsync()
39
+ ## vs ctx.requireAsync()
40
40
 
41
- - **ctx.importAsync()**: Loads **ESM modules** and returns the module namespace. Suitable for modern libraries (ESM builds like Vue, dayjs, etc.).
42
- - **ctx.requireAsync()**: Loads **UMD/AMD** modules or scripts that attach to the global scope. Often used for UMD libraries like ECharts or FullCalendar. If a library provides both ESM and UMD, `ctx.importAsync()` is preferred.
41
+ - **ctx.importAsync()**: Loads **ESM**; returns module namespace; good for Vue, dayjs, etc. (ESM builds).
42
+ - **ctx.requireAsync()**: Loads **UMD/AMD** or global scripts; good for ECharts, FullCalendar (UMD), etc. If a lib has ESM, prefer `ctx.importAsync()`.
43
43
 
44
44
  ## Examples
45
45
 
46
- ### Basic Usage
47
-
48
- Demonstrates the most basic usage of dynamically loading ESM modules and CSS by package name or full URL.
46
+ ### Basic
49
47
 
50
48
  ```javascript
51
49
  const Vue = await ctx.importAsync('vue@3.4.0');
52
- // Equivalent to loading from https://esm.sh/vue@3.4.0
53
50
 
54
51
  const relativeTime = await ctx.importAsync('dayjs@1/plugin/relativeTime.js');
55
- // With subpath (e.g., dayjs plugin)
56
52
 
57
53
  const pkg = await ctx.importAsync('https://cdn.example.com/my-module.js');
58
- // Full URL
59
54
 
60
55
  await ctx.importAsync('https://cdn.example.com/theme.css');
61
- // Load CSS and inject into the page
62
56
  ```
63
57
 
64
- ### ECharts Example
65
-
66
- Use ECharts to draw a sales overview chart with bar and line graphs.
58
+ ### ECharts
67
59
 
68
60
  ```ts
69
- // 1. Dynamically load ECharts module
70
61
  const echarts = await ctx.importAsync('echarts@5.4.3');
71
62
 
72
- // 2. Create chart container and render
73
63
  const chartEl = document.createElement('div');
74
64
  chartEl.style.width = '100%';
75
65
  chartEl.style.height = '400px';
76
66
  ctx.render(chartEl);
77
67
 
78
- // 3. Initialize ECharts instance
79
68
  const chart = echarts.init(chartEl);
80
69
 
81
- // 4. Configure chart
82
70
  const option = {
83
- title: {
84
- text: 'Sales Overview',
85
- left: 'center',
86
- },
87
- tooltip: {
88
- trigger: 'axis',
89
- },
90
- legend: {
91
- data: ['Sales', 'Profit'],
92
- top: '10%',
93
- },
94
- xAxis: {
95
- type: 'category',
96
- data: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
97
- },
98
- yAxis: {
99
- type: 'value',
100
- },
71
+ title: { text: 'Sales Overview', left: 'center' },
72
+ tooltip: { trigger: 'axis' },
73
+ legend: { data: ['Sales', 'Profit'], top: '10%' },
74
+ xAxis: { type: 'category', data: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'] },
75
+ yAxis: { type: 'value' },
101
76
  series: [
102
- {
103
- name: 'Sales',
104
- type: 'bar',
105
- data: [120, 200, 150, 80, 70, 110],
106
- },
107
- {
108
- name: 'Profit',
109
- type: 'line',
110
- data: [20, 40, 30, 15, 12, 25],
111
- },
77
+ { name: 'Sales', type: 'bar', data: [120, 200, 150, 80, 70, 110] },
78
+ { name: 'Profit', type: 'line', data: [20, 40, 30, 15, 12, 25] },
112
79
  ],
113
80
  };
114
81
 
115
- // 5. Set option and render chart
116
82
  chart.setOption(option);
117
83
 
118
- // 6. Optional: Responsive sizing
119
- window.addEventListener('resize', () => {
120
- chart.resize();
121
- });
84
+ window.addEventListener('resize', () => chart.resize());
122
85
 
123
- // 7. Optional: Event listener
124
86
  chart.on('click', (params) => {
125
87
  ctx.message.info(`Clicked ${params.seriesName} on ${params.name}, value: ${params.value}`);
126
88
  });
127
89
  ```
128
90
 
129
- ### Tabulator Example
130
-
131
- Demonstrates rendering a data table with pagination and row click events in a block using Tabulator.
91
+ ### Tabulator
132
92
 
133
93
  ```ts
134
- // 1. Load Tabulator styles
135
94
  await ctx.importAsync('tabulator-tables@6.2.5/dist/css/tabulator.min.css');
136
95
 
137
- // 2. Dynamically load Tabulator module
138
96
  const { TabulatorFull } = await ctx.importAsync('tabulator-tables@6.2.5');
139
97
 
140
- // 3. Create table container and render
141
98
  const tableEl = document.createElement('div');
142
99
  ctx.render(tableEl);
143
100
 
144
- // 4. Initialize Tabulator table
145
101
  const table = new TabulatorFull(tableEl, {
146
102
  data: [
147
- { id: 1, name: 'Alice', age: 25, city: 'New York' },
148
- { id: 2, name: 'Bob', age: 30, city: 'London' },
149
- { id: 3, name: 'Charlie', age: 28, city: 'Paris' },
103
+ { id: 1, name: 'Alice', age: 25, city: 'Beijing' },
104
+ { id: 2, name: 'Bob', age: 30, city: 'Shanghai' },
105
+ { id: 3, name: 'Charlie', age: 28, city: 'Guangzhou' },
150
106
  ],
151
107
  columns: [
152
108
  { title: 'ID', field: 'id', width: 80 },
@@ -159,30 +115,22 @@ const table = new TabulatorFull(tableEl, {
159
115
  paginationSize: 10,
160
116
  });
161
117
 
162
- // 5. Optional: Event listener
163
118
  table.on('rowClick', (e, row) => {
164
119
  const rowData = row.getData();
165
120
  ctx.message.info(`Row clicked: ${rowData.name}`);
166
121
  });
167
122
  ```
168
123
 
169
- ### FullCalendar (ESM) Example
170
-
171
- Shows how to load FullCalendar and its plugins via ESM and render a basic monthly view calendar.
124
+ ### FullCalendar (ESM)
172
125
 
173
126
  ```ts
174
- // 1. Dynamically load FullCalendar core module
175
127
  const { Calendar } = await ctx.importAsync('@fullcalendar/core@6.1.20');
176
-
177
- // 2. Dynamically load dayGrid plugin
178
128
  const dayGridPlugin = await ctx.importAsync('@fullcalendar/daygrid@6.1.20');
179
129
 
180
- // 3. Create calendar container and render
181
130
  const calendarEl = document.createElement('div');
182
131
  calendarEl.id = 'calendar';
183
132
  ctx.render(calendarEl);
184
133
 
185
- // 4. Initialize and render calendar
186
134
  const calendar = new Calendar(calendarEl, {
187
135
  plugins: [dayGridPlugin.default || dayGridPlugin],
188
136
  headerToolbar: {
@@ -195,160 +143,22 @@ const calendar = new Calendar(calendarEl, {
195
143
  calendar.render();
196
144
  ```
197
145
 
198
- ### dnd-kit Simple Drag-and-Drop Example
146
+ ### dnd-kit (with ?deps)
199
147
 
200
- Uses `@dnd-kit/core` to implement a minimal example of dragging a Box to a target area within a block.
148
+ For React-based libs like `@dnd-kit/core`, use `?deps=react@18.2.0,react-dom@18.2.0` so the same React instance is used and hooks work:
201
149
 
202
150
  ```ts
203
- // 1. Load React, react-dom, @dnd-kit/core (?deps ensures same React instance to avoid Invalid hook call)
204
151
  const React = await ctx.importAsync('react@18.2.0');
205
152
  const { createRoot } = await ctx.importAsync('react-dom@18.2.0/client');
206
153
  const core = await ctx.importAsync('@dnd-kit/core@6.3.1?deps=react@18.2.0,react-dom@18.2.0');
207
- const { DndContext, closestCenter, PointerSensor, useSensor, useSensors, useDraggable, useDroppable } = core;
208
-
209
- function DraggableBox() {
210
- const { attributes, listeners, setNodeRef, transform } = useDraggable({ id: 'box' });
211
- const style = {
212
- padding: 12,
213
- marginBottom: 8,
214
- background: '#e6f7ff',
215
- cursor: 'grab',
216
- transform: transform ? 'translate3d(' + transform.x + 'px,' + transform.y + 'px,0)' : undefined,
217
- };
218
- return React.createElement('div', { ref: setNodeRef, style, ...attributes, ...listeners }, 'Drag me');
219
- }
220
-
221
- function DropZone() {
222
- const { setNodeRef, isOver } = useDroppable({ id: 'zone' });
223
- return React.createElement(
224
- 'div',
225
- {
226
- ref: setNodeRef,
227
- style: { padding: 24, background: isOver ? '#b7eb8f' : '#f5f5f5', borderRadius: 8, minHeight: 80 },
228
- },
229
- 'Drop here',
230
- );
231
- }
232
-
233
- function App() {
234
- const sensors = useSensors(useSensor(PointerSensor));
235
- function onDragEnd(e) {
236
- if (e.over && e.over.id === 'zone') ctx.message.success('Dropped in zone');
237
- }
238
- return React.createElement(
239
- DndContext,
240
- { sensors, collisionDetection: closestCenter, onDragEnd },
241
- React.createElement(
242
- 'div',
243
- { style: { maxWidth: 280 } },
244
- React.createElement(DraggableBox),
245
- React.createElement(DropZone),
246
- ),
247
- );
248
- }
249
-
250
- // 2. Render
251
- ctx.render(<App />);
154
+ // Use core (DndContext, useDraggable, useDroppable, etc.) with React
252
155
  ```
253
156
 
254
- This example relies only on `@dnd-kit/core` to trigger a notification when a Box is dropped into a specific area, demonstrating the simplest drag-and-drop interaction combining `ctx.importAsync` and React in RunJS.
255
-
256
- ### dnd-kit Sortable List Example
257
-
258
- Implements a vertical sortable list using dnd-kit's core, sortable, and utilities.
259
-
260
- ```ts
261
- // 1. Load React and dnd-kit related packages (?deps ensures same React instance)
262
- const React = await ctx.importAsync('react@18.2.0');
263
- const { createRoot } = await ctx.importAsync('react-dom@18.2.0/client');
264
- const dndCore = await ctx.importAsync('@dnd-kit/core@6.3.1?deps=react@18.2.0,react-dom@18.2.0');
265
- const dndSortable = await ctx.importAsync('@dnd-kit/sortable@10.0.0?deps=react@18.2.0,react-dom@18.2.0');
266
- const dndUtils = await ctx.importAsync('@dnd-kit/utilities@3.2.2');
267
-
268
- const { useState } = React;
269
- const { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors } = dndCore;
270
- const {
271
- arrayMove,
272
- SortableContext,
273
- sortableKeyboardCoordinates,
274
- verticalListSortingStrategy,
275
- useSortable,
276
- } = dndSortable;
277
- const { CSS } = dndUtils;
278
-
279
- // 2. SortableItem component (must be inside SortableContext)
280
- function SortableItem(props) {
281
- const { id, label } = props;
282
- const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id });
283
- const style = {
284
- transform: CSS.Transform.toString(transform),
285
- transition,
286
- padding: '12px 16px',
287
- marginBottom: 8,
288
- background: '#f5f5f5',
289
- borderRadius: 6,
290
- cursor: 'grab',
291
- };
292
- return React.createElement('div', { ref: setNodeRef, style, ...attributes, ...listeners }, label);
293
- }
294
-
295
- // 3. App: DndContext + SortableContext + Drag end handler
296
- const labels = { 1: 'First', 2: 'Second', 3: 'Third', 4: 'Fourth' };
297
- function App() {
298
- const [items, setItems] = useState([1, 2, 3, 4]);
299
- const sensors = useSensors(
300
- useSensor(PointerSensor),
301
- useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }),
302
- );
303
-
304
- function handleDragEnd(event) {
305
- const { active, over } = event;
306
- if (over && active.id !== over.id) {
307
- setItems((prev) => {
308
- const oldIndex = prev.indexOf(active.id);
309
- const newIndex = prev.indexOf(over.id);
310
- return arrayMove(prev, oldIndex, newIndex);
311
- });
312
- ctx.message.success('List reordered');
313
- }
314
- }
315
-
316
- return React.createElement(
317
- DndContext,
318
- {
319
- sensors,
320
- collisionDetection: closestCenter,
321
- onDragEnd: handleDragEnd,
322
- },
323
- React.createElement(
324
- SortableContext,
325
- { items, strategy: verticalListSortingStrategy },
326
- React.createElement(
327
- 'div',
328
- { style: { maxWidth: 320 } },
329
- items.map((id) => React.createElement(SortableItem, { key: id, id, label: labels[id] })),
330
- ),
331
- ),
332
- );
333
- }
334
-
335
- // 4. Create container and mount React
336
- const rootEl = document.createElement('div');
337
- ctx.render(rootEl);
338
- createRoot(rootEl).render(React.createElement(App));
339
- ```
340
-
341
- This example uses `@dnd-kit/core`, `@dnd-kit/sortable`, and `@dnd-kit/utilities` to implement a sortable list that updates its order and displays a "List reordered" message after dragging.
342
-
343
- ### react-big-calendar Example
344
-
345
- Renders a calendar component supporting event display in the current block using `react-big-calendar` and `date-fns` for localization.
157
+ ### react-big-calendar
346
158
 
347
159
  ```tsx
348
- // 1. Load styles (ctx.importAsync uses ctx.loadCSS for .css files)
349
160
  await ctx.importAsync('react-big-calendar@1.11.4/lib/css/react-big-calendar.css');
350
161
 
351
- // 2. Load React, react-dom, react-big-calendar, date-fns, and locale (ensuring same React instance)
352
162
  const React = await ctx.importAsync('react@18.2.0');
353
163
  const { Calendar, dateFnsLocalizer } = await ctx.importAsync('react-big-calendar@1.11.4?deps=react@18.2.0,react-dom@18.2.0');
354
164
  const { format, parse, startOfWeek, getDay } = await ctx.importAsync('date-fns@2.30.0');
@@ -367,7 +177,6 @@ const events = [
367
177
  { title: 'Meeting', start: new Date(2026, 0, 29, 10, 0), end: new Date(2026, 0, 29, 11, 0) },
368
178
  ];
369
179
 
370
- // 3. Render React Calendar
371
180
  ctx.render(
372
181
  <Calendar
373
182
  localizer={localizer}
@@ -379,110 +188,13 @@ ctx.render(
379
188
  );
380
189
  ```
381
190
 
382
- ### frappe-gantt Example
383
-
384
- Uses `frappe-gantt` to render a Gantt chart view showing task start/end times and progress.
385
-
386
- ```ts
387
- // 1. Dynamically load Gantt styles and constructor
388
- // Depends on ESM_CDN_BASE_URL (default https://esm.sh), shorthand paths can be used
389
- await ctx.importAsync('frappe-gantt@1.0.4/dist/frappe-gantt.css');
390
- const Gantt = await ctx.importAsync('frappe-gantt@1.0.4');
391
-
392
- // 2. Prepare task data
393
- let tasks = [
394
- {
395
- id: '1',
396
- name: 'Redesign website',
397
- start: '2016-12-28',
398
- end: '2016-12-31',
399
- progress: 20,
400
- },
401
- {
402
- id: '2',
403
- name: 'Develop new feature',
404
- start: '2017-01-01',
405
- end: '2017-01-05',
406
- progress: 40,
407
- dependencies: '1',
408
- },
409
- {
410
- id: '3',
411
- name: 'QA & testing',
412
- start: '2017-01-06',
413
- end: '2017-01-10',
414
- progress: 10,
415
- dependencies: '2',
416
- },
417
- ];
418
-
419
- // 3. Create container and render
420
- const ganttEl = document.createElement('div');
421
- ganttEl.id = 'gantt';
422
- ganttEl.style.height = '400px';
423
- ctx.render(ganttEl);
424
-
425
- // 4. Initialize Gantt chart
426
- let gantt = new Gantt('#gantt', tasks, {
427
- view_mode: 'Day', // View granularity: 'Quarter Day' | 'Half Day' | 'Day' | 'Week' | 'Month'
428
- language: 'en',
429
- bar_height: 24,
430
- padding: 18,
431
- custom_popup_html(task) {
432
- return `
433
- <div class="details-container">
434
- <h5>${task.name}</h5>
435
- <p>Start: ${task._start.toISOString().slice(0, 10)}</p>
436
- <p>End: ${task._end.toISOString().slice(0, 10)}</p>
437
- <p>Progress: ${task.progress}%</p>
438
- </div>
439
- `;
440
- },
441
- });
442
- ```
443
-
444
- ### @asseinfo/react-kanban Example
445
-
446
- Utilizes `@asseinfo/react-kanban` to render a basic Kanban board with columns like Backlog and Doing within a block.
447
-
448
- ```ts
449
- // 1. Load styles (ctx.importAsync directly loads .css)
450
- await ctx.importAsync('@asseinfo/react-kanban@2.2.0/dist/styles.css');
451
-
452
- // 2. Load React, react-dom, @asseinfo/react-kanban (?deps ensures same React instance)
453
- const React = await ctx.importAsync('react@18.2.0');
454
- const { default: Board } = await ctx.importAsync('@asseinfo/react-kanban@2.2.0?deps=react@18.2.0,react-dom@18.2.0');
455
-
456
- const board = {
457
- columns: [
458
- {
459
- id: 1,
460
- title: 'Backlog',
461
- cards: [
462
- { id: 1, title: 'Add card', description: 'Add capability to add a card in a column' },
463
- ],
464
- },
465
- {
466
- id: 2,
467
- title: 'Doing',
468
- cards: [
469
- { id: 2, title: 'Drag-n-drop support', description: 'Move a card between the columns' },
470
- ],
471
- },
472
- ],
473
- };
474
-
475
- // 4. Mount the board
476
- ctx.render(<Board initialBoard={board} />);
477
- ```
478
-
479
191
  ## Notes
480
192
 
481
- - This feature depends on an external network or CDN. In internal network environments, **ESM_CDN_BASE_URL** must be configured to point to a self-hosted service.
482
- - When a library provides both ESM and UMD, prefer `ctx.importAsync()` for better module semantics.
483
- - For libraries depending on React, ensure you append `?deps=react@18.2.0,react-dom@18.2.0`. The version must match the React version used by the page, otherwise, an "Invalid hook call" error may occur.
193
+ - Depends on network/CDN; for intranet set **ESM_CDN_BASE_URL** to your own service.
194
+ - When a lib has both ESM and UMD, prefer `ctx.importAsync()` for better module semantics.
195
+ - For React-dependent libs always add `?deps=react@18.2.0,react-dom@18.2.0` (or the version your app uses) to avoid Invalid hook call.
484
196
 
485
197
  ## Related
486
198
 
487
- - [ctx.requireAsync()](./require-async.md): Load UMD/AMD or globally attached scripts, suitable for UMD libraries like ECharts and FullCalendar.
488
- - [ctx.render()](./render.md): Render content into a container.
199
+ - [ctx.requireAsync()](./require-async.md): load UMD/AMD or global scripts; good for ECharts, FullCalendar (UMD)
200
+ - [ctx.render()](./render.md): render into container
@@ -1,12 +1,12 @@
1
1
  # ctx.initResource()
2
2
 
3
- **Initializes** the resource for the current context. If `ctx.resource` does not already exist, it creates one of the specified type and binds it to the context; if it already exists, it is used directly. Afterward, it can be accessed via `ctx.resource`.
3
+ **Initializes** the current context’s resource: if `ctx.resource` does not exist, creates one of the given type and binds it; otherwise uses the existing one. After that you can use `ctx.resource`.
4
4
 
5
5
  ## Use Cases
6
6
 
7
- Generally used in **JSBlock** (independent block) scenarios. Most blocks, popups, and other components have `ctx.resource` pre-bound and do not require manual calls. JSBlock has no resource by default, so you must call `ctx.initResource(type)` before loading data via `ctx.resource`.
7
+ Typically used only in **JSBlock** (standalone block). Most blocks and popups already have `ctx.resource`; JSBlock does not, so call `ctx.initResource(type)` first, then use `ctx.resource`.
8
8
 
9
- ## Type Definition
9
+ ## Type
10
10
 
11
11
  ```ts
12
12
  initResource(
@@ -18,18 +18,18 @@ initResource(
18
18
  |-----------|------|-------------|
19
19
  | `type` | `string` | Resource type: `'APIResource'`, `'SingleRecordResource'`, `'MultiRecordResource'`, `'SQLResource'` |
20
20
 
21
- **Returns**: The resource instance in the current context (i.e., `ctx.resource`).
21
+ **Returns**: The resource instance in the current context (i.e. `ctx.resource`).
22
22
 
23
- ## Difference from ctx.makeResource()
23
+ ## Relation to ctx.makeResource()
24
24
 
25
25
  | Method | Behavior |
26
26
  |--------|----------|
27
- | `ctx.initResource(type)` | Creates and binds if `ctx.resource` does not exist; returns the existing one if it does. Ensures `ctx.resource` is available. |
28
- | `ctx.makeResource(type)` | Only creates and returns a new instance, does **not** write to `ctx.resource`. Suitable for scenarios requiring multiple independent resources or temporary use. |
27
+ | `ctx.initResource(type)` | Creates and binds if `ctx.resource` is missing; otherwise returns existing. Ensures `ctx.resource` is set |
28
+ | `ctx.makeResource(type)` | Creates a new instance and returns it; **does not** set `ctx.resource`. Use when you need multiple resources or a temporary one |
29
29
 
30
30
  ## Examples
31
31
 
32
- ### List Data (MultiRecordResource)
32
+ ### List data (MultiRecordResource)
33
33
 
34
34
  ```ts
35
35
  ctx.initResource('MultiRecordResource');
@@ -39,17 +39,17 @@ const rows = ctx.resource.getData();
39
39
  ctx.render(<pre>{JSON.stringify(rows, null, 2)}</pre>);
40
40
  ```
41
41
 
42
- ### Single Record (SingleRecordResource)
42
+ ### Single record (SingleRecordResource)
43
43
 
44
44
  ```ts
45
45
  ctx.initResource('SingleRecordResource');
46
46
  ctx.resource.setResourceName('users');
47
- ctx.resource.setFilterByTk(1); // Specify primary key
47
+ ctx.resource.setFilterByTk(1);
48
48
  await ctx.resource.refresh();
49
49
  const record = ctx.resource.getData();
50
50
  ```
51
51
 
52
- ### Specify Data Source
52
+ ### Specify data source
53
53
 
54
54
  ```ts
55
55
  ctx.initResource('MultiRecordResource');
@@ -60,15 +60,15 @@ await ctx.resource.refresh();
60
60
 
61
61
  ## Notes
62
62
 
63
- - In most block scenarios (Forms, Tables, Details, etc.) and popups, `ctx.resource` is already pre-bound by the runtime environment, so calling `ctx.initResource` is unnecessary.
64
- - Manual initialization is only required in contexts like JSBlock where there is no default resource.
65
- - After initialization, you must call `setResourceName(name)` to specify the collection, and then call `refresh()` to load the data.
63
+ - In most blocks (form, table, detail, etc.) and popups, `ctx.resource` is already bound; no need to call `ctx.initResource`.
64
+ - Only in contexts like JSBlock that have no resource by default do you need to initialize.
65
+ - After init, call `setResourceName(name)` and then `refresh()` to load data.
66
66
 
67
67
  ## Related
68
68
 
69
- - [ctx.resource](./resource.md) — The resource instance in the current context
70
- - [ctx.makeResource()](./make-resource.md) Creates a new resource instance without binding it to `ctx.resource`
71
- - [MultiRecordResource](../resource/multi-record-resource.md) — Multiple records/List
72
- - [SingleRecordResource](../resource/single-record-resource.md) — Single record
73
- - [APIResource](../resource/api-resource.md) — General API resource
74
- - [SQLResource](../resource/sql-resource.md) — SQL query resource
69
+ - [ctx.resource](./resource.md): resource in current context
70
+ - [ctx.makeResource()](./make-resource.md): create resource without binding to `ctx.resource`
71
+ - [MultiRecordResource](../resource/multi-record-resource.md)
72
+ - [SingleRecordResource](../resource/single-record-resource.md)
73
+ - [APIResource](../resource/api-resource.md)
74
+ - [SQLResource](../resource/sql-resource.md)