robobyte-front-builder 1.0.21 → 1.0.23
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/INTEGRATION.md +1586 -0
- package/README.md +791 -74
- package/RoboByteBuilder_User_Manual.docx +0 -0
- package/package.json +4 -2
- package/src/context/BuilderContext.jsx +63 -7
- package/src/pages/api/ai.js +20 -0
- package/src/pages/printBuilder/index.jsx +3 -3
- package/src/pages/reportModule/reportBuilder/reportViewer/index.js +59 -3
- package/src/pages/viewBuilder/index.jsx +2 -2
- package/src/services/Endpoints/ReportBuilderEndpoints.js +7 -7
- package/src/services/sessionLog.js +171 -0
- package/src/views/builder/SessionLogDialog.jsx +350 -0
- package/src/views/builder/UnsavedChangesGuard.jsx +103 -0
- package/src/views/builder/inspector/definitions/reportViewer/main.js +13 -0
- package/src/views/builder/sidebar/tabs/AiTab/aiProvider.js +7 -3
- package/src/views/builder/sidebar/tabs/AiTab/schemaTransformer.js +65 -0
- package/src/views/builder/sidebar/tabs/AiTab/trainingExport.js +131 -0
- package/src/views/builder/sidebar/tabs/ViewTab.jsx +173 -13
- package/src/views/builder/viewer/ViewerComponentWrapper.jsx +9 -5
- package/src/views/builder/viewer/ViewerToolbar.jsx +18 -3
- package/src/views/builder/viewer/renderers/ReportViewerRenderer.jsx +46 -2
- package/src/views/genericTable/SGrid.js +656 -384
- package/src/views/printBuilder/PrintBuilderViewer.jsx +22 -2
package/README.md
CHANGED
|
@@ -1,15 +1,50 @@
|
|
|
1
1
|
# robobyte-front-builder
|
|
2
2
|
|
|
3
|
-
A low-code UI
|
|
3
|
+
A low-code **UI Builder**, **Report Builder**, **Print Layout Designer**, and **Navigation Extension API** for Next.js applications.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/robobyte-front-builder)
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
1. [What's included](#whats-included)
|
|
12
|
+
2. [Requirements](#requirements)
|
|
13
|
+
3. [Installation](#installation)
|
|
14
|
+
4. [Peer dependencies](#peer-dependencies)
|
|
15
|
+
5. [next.config.js setup](#nextconfigjs-setup)
|
|
16
|
+
6. [Provider setup](#provider-setup-_appjs)
|
|
17
|
+
7. [Builder pages](#builder-pages)
|
|
18
|
+
8. [Navigation Extension API](#navigation-extension-api)
|
|
19
|
+
9. [Provider props reference](#provider-props-reference)
|
|
20
|
+
10. [fetchReportDataByPageId](#fetchreportdatabypageid)
|
|
21
|
+
11. [ReportViewer as a component](#reportviewer-as-a-component)
|
|
22
|
+
12. [Data Grid component](#data-grid-component)
|
|
23
|
+
13. [Dialog component](#dialog-component)
|
|
24
|
+
14. [Popover component](#popover-component)
|
|
25
|
+
15. [Excel Upload component](#excel-upload-component)
|
|
26
|
+
16. [Wizard component](#wizard-component)
|
|
27
|
+
17. [Repeater component](#repeater-component)
|
|
28
|
+
18. [Menu component](#menu-component)
|
|
29
|
+
19. [View Renderer component](#view-renderer-component)
|
|
30
|
+
20. [Layout Grid component](#layout-grid-component)
|
|
31
|
+
21. [Breadcrumb component](#breadcrumb-component)
|
|
32
|
+
22. [Print Layout Builder](#print-layout-builder)
|
|
33
|
+
23. [Calculation Scope Reference](#calculation-scope-reference)
|
|
34
|
+
24. [KPI Component Actions](#kpi-component-actions)
|
|
35
|
+
25. [Global Data Store](#global-data-store)
|
|
36
|
+
26. [Dark / Light theme](#dark--light-theme)
|
|
37
|
+
27. [Syncing local changes](#syncing-local-changes)
|
|
38
|
+
28. [Troubleshooting](#troubleshooting)
|
|
39
|
+
29. [Publishing](#publishing)
|
|
40
|
+
30. [Changelog](#changelog)
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
9
44
|
## What's included
|
|
10
45
|
|
|
11
46
|
- **UI Builder** — drag-and-drop canvas for building data-driven views with 50+ components
|
|
12
|
-
- **Report Builder** — design and preview paginated reports
|
|
47
|
+
- **Report Builder** — design and preview paginated reports with AG Grid
|
|
13
48
|
- **Print Layout Designer** — multi-zone print templates (header / body pages / footer)
|
|
14
49
|
- **Navigator Builder** — configure sidebar navigation
|
|
15
50
|
- **Viewer** — production read-only renderer for saved UI Builder views
|
|
@@ -17,6 +52,7 @@ A low-code UI builder, Report builder, Print Layout designer, and Navigation ext
|
|
|
17
52
|
- **KPI Components** — 12 ready-to-use metric visualisations (gauge, trend, bullet chart, rating, countdown, …)
|
|
18
53
|
- **Timer Engine** — configurable auto-refresh timers per view
|
|
19
54
|
- **Undo / Redo / Copy / Paste** — full clipboard and history support in the builder
|
|
55
|
+
- **Global Data Store** — cross-route reactive state that survives client-side navigations
|
|
20
56
|
|
|
21
57
|
---
|
|
22
58
|
|
|
@@ -38,9 +74,11 @@ A low-code UI builder, Report builder, Print Layout designer, and Navigation ext
|
|
|
38
74
|
npm install robobyte-front-builder
|
|
39
75
|
```
|
|
40
76
|
|
|
41
|
-
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Peer dependencies
|
|
42
80
|
|
|
43
|
-
|
|
81
|
+
Only the libraries that **must be shared as a single instance** are declared as `peerDependencies` — React, MUI, Emotion, and AG Grid. Everything else ships inside the package so the host app doesn't need to install them manually.
|
|
44
82
|
|
|
45
83
|
```bash
|
|
46
84
|
npm install \
|
|
@@ -52,152 +90,826 @@ npm install \
|
|
|
52
90
|
xlsx react-hot-toast
|
|
53
91
|
```
|
|
54
92
|
|
|
55
|
-
> Everything else
|
|
93
|
+
> **Why only these?** React and MUI use context and module registries that break if two copies exist in the same app (hooks errors, theme not applied, AG Grid license warnings). `xlsx` is required by the Excel Upload component and is resolved from the host app's `node_modules` because the builder source is transpiled in the host's webpack context. Everything else — `dayjs`, `lodash`, `recharts`, etc. — can safely run from the package's own `node_modules` copy with no side effects.
|
|
56
94
|
|
|
57
95
|
---
|
|
58
96
|
|
|
59
|
-
##
|
|
60
|
-
|
|
61
|
-
### 1. next.config.js
|
|
97
|
+
## `next.config.js` setup
|
|
62
98
|
|
|
63
|
-
|
|
99
|
+
Two things are required: **transpile** the package and set up the **context-aware bare-alias webpack plugin** so that bare imports like `services/*`, `context/*`, etc. resolve to the correct source tree.
|
|
64
100
|
|
|
65
101
|
```js
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
102
|
+
const path = require('path')
|
|
103
|
+
const withTM = require('next-transpile-modules')(['robobyte-front-builder'])
|
|
104
|
+
|
|
105
|
+
const hostSrc = path.resolve(__dirname, 'src')
|
|
106
|
+
const builderSrc = path.resolve(__dirname, 'node_modules/robobyte-front-builder/src')
|
|
107
|
+
|
|
108
|
+
module.exports = withTM({
|
|
109
|
+
webpack(config, { isServer }) {
|
|
110
|
+
if (isServer) {
|
|
111
|
+
config.resolve.conditionNames = ['require', 'node', 'default']
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const { NormalModuleReplacementPlugin } = require('webpack')
|
|
115
|
+
|
|
116
|
+
// Package-owned services — always resolved from the package
|
|
117
|
+
const packageOwnedServices = [
|
|
118
|
+
'services/reportData/fetchReportData',
|
|
119
|
+
]
|
|
120
|
+
packageOwnedServices.forEach(mod => {
|
|
121
|
+
config.plugins.push(
|
|
122
|
+
new NormalModuleReplacementPlugin(
|
|
123
|
+
new RegExp(`^${mod.replace(/\//g, '\\/')}(\\.js)?$`),
|
|
124
|
+
resource => { resource.request = path.join(builderSrc, mod) }
|
|
125
|
+
)
|
|
126
|
+
)
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
// Context-aware bare alias routing
|
|
130
|
+
config.plugins.push(
|
|
131
|
+
new NormalModuleReplacementPlugin(
|
|
132
|
+
/^(services|views|context|src|pages)(\/|$)/,
|
|
133
|
+
resource => {
|
|
134
|
+
const isBuilder =
|
|
135
|
+
resource.context.includes('robobyte-front-builder') ||
|
|
136
|
+
resource.context.includes('RoboByteFrontBuilder')
|
|
137
|
+
const root = isBuilder ? builderSrc : hostSrc
|
|
138
|
+
resource.request = resource.request.replace(
|
|
139
|
+
/^(services|views|context|src|pages)(\/|$)/,
|
|
140
|
+
(_, prefix, sep) =>
|
|
141
|
+
prefix === 'src'
|
|
142
|
+
? root + sep
|
|
143
|
+
: path.join(root, prefix) + sep
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
return config
|
|
150
|
+
},
|
|
151
|
+
})
|
|
72
152
|
```
|
|
73
153
|
|
|
74
|
-
|
|
154
|
+
> **Restart the dev server** whenever `next.config.js` changes — hot-reload does not apply to webpack plugin changes.
|
|
75
155
|
|
|
76
|
-
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Provider setup (`_app.js`)
|
|
159
|
+
|
|
160
|
+
Wrap the component tree with `RoboByteFrontBuilderProvider`. Bridge your host auth context into it so the package attaches auth headers to every API call.
|
|
77
161
|
|
|
78
162
|
```jsx
|
|
79
163
|
import { RoboByteFrontBuilderProvider } from 'robobyte-front-builder'
|
|
80
164
|
|
|
81
|
-
|
|
165
|
+
function RoboByteBridge({ children }) {
|
|
166
|
+
const auth = useContext(YourAuthContext)
|
|
82
167
|
return (
|
|
83
168
|
<RoboByteFrontBuilderProvider
|
|
84
|
-
baseURL=
|
|
85
|
-
apiURL=
|
|
86
|
-
|
|
87
|
-
|
|
169
|
+
baseURL={process.env.NEXT_PUBLIC_API_BASE_URL}
|
|
170
|
+
apiURL={process.env.NEXT_PUBLIC_API_URL}
|
|
171
|
+
user={auth.user}
|
|
172
|
+
accessToken={auth.accessToken}
|
|
173
|
+
agGridLicenseKey={process.env.NEXT_PUBLIC_AG_GRID_LICENSE_KEY}
|
|
88
174
|
>
|
|
89
|
-
|
|
175
|
+
{children}
|
|
90
176
|
</RoboByteFrontBuilderProvider>
|
|
91
177
|
)
|
|
92
178
|
}
|
|
179
|
+
|
|
180
|
+
export default function App({ Component, pageProps }) {
|
|
181
|
+
const getLayout = Component.getLayout ?? (page => page)
|
|
182
|
+
return (
|
|
183
|
+
<YourAuthProvider>
|
|
184
|
+
<RoboByteBridge>
|
|
185
|
+
{getLayout(<Component {...pageProps} />)}
|
|
186
|
+
</RoboByteBridge>
|
|
187
|
+
</YourAuthProvider>
|
|
188
|
+
)
|
|
189
|
+
}
|
|
93
190
|
```
|
|
94
191
|
|
|
95
|
-
|
|
192
|
+
---
|
|
96
193
|
|
|
97
|
-
|
|
194
|
+
## Builder pages
|
|
98
195
|
|
|
99
|
-
|
|
100
|
-
// pages/ui-builder/[id].js
|
|
101
|
-
export { default } from 'robobyte-front-builder/UIBuilderPage'
|
|
102
|
-
// or:
|
|
103
|
-
import { UIBuilderPage } from 'robobyte-front-builder'
|
|
104
|
-
export default UIBuilderPage
|
|
105
|
-
```
|
|
196
|
+
All builder routes live under the `/builders/` prefix. Create a thin wrapper page in your host app for each route.
|
|
106
197
|
|
|
107
|
-
|
|
|
198
|
+
| Route | Package export |
|
|
108
199
|
|---|---|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
|
|
|
112
|
-
|
|
|
113
|
-
|
|
|
114
|
-
|
|
|
115
|
-
|
|
|
116
|
-
|
|
|
117
|
-
| `
|
|
200
|
+
| `/builders/ui` | `UIBuilderPage` |
|
|
201
|
+
| `/builders/ui/views` | `ViewsList` |
|
|
202
|
+
| `/builders/report` | `ReportBuilderPage` |
|
|
203
|
+
| `/builders/report/list` | `ReportsList` |
|
|
204
|
+
| `/builders/report/viewer` | `ReportViewer` |
|
|
205
|
+
| `/builders/report/reportsPermissions` | `ReportsCard` |
|
|
206
|
+
| `/builders/navigator` | `NavigatorBuilderPage` |
|
|
207
|
+
| `/viewer/[id]` | `ViewerPage` |
|
|
208
|
+
| `/printBuilder` | `PrintBuilderPage` |
|
|
209
|
+
| `/printBuilder/layouts` | `PrintLayoutsList` |
|
|
210
|
+
|
|
211
|
+
### Page wrapper pattern
|
|
212
|
+
|
|
213
|
+
Use explicit import + static property assignment. A bare `export { X as default }` does **not** reliably carry `getLayout`, `acl`, `authGuard` across package boundaries in Next.js.
|
|
214
|
+
|
|
215
|
+
```jsx
|
|
216
|
+
// pages/builders/report/viewer/index.jsx
|
|
217
|
+
import { ReportViewer } from 'robobyte-front-builder'
|
|
218
|
+
import BlankLayout from 'src/@core/layouts/BlankLayout'
|
|
219
|
+
import PermissionsSubjects from 'src/configs/Permissions/PermissionsSubjects.json'
|
|
220
|
+
|
|
221
|
+
ReportViewer.getLayout = page => <BlankLayout>{page}</BlankLayout>
|
|
222
|
+
ReportViewer.acl = { action: 'view', subject: PermissionsSubjects.Free }
|
|
223
|
+
ReportViewer.authGuard = true
|
|
224
|
+
ReportViewer.guestGuard = false
|
|
225
|
+
export default ReportViewer
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Viewer page (`/viewer/[id]`)
|
|
229
|
+
|
|
230
|
+
```jsx
|
|
231
|
+
import { useContext } from 'react'
|
|
232
|
+
import { ViewerPage, SystemContext } from 'robobyte-front-builder'
|
|
233
|
+
import { YourNavContext } from 'src/context/YourNavContext'
|
|
234
|
+
|
|
235
|
+
function SystemContextBridge({ children }) {
|
|
236
|
+
const { nav } = useContext(YourNavContext)
|
|
237
|
+
return (
|
|
238
|
+
<SystemContext.Provider value={{ nav }}>
|
|
239
|
+
{children}
|
|
240
|
+
</SystemContext.Provider>
|
|
241
|
+
)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export default function ViewerRoute() {
|
|
245
|
+
return (
|
|
246
|
+
<SystemContextBridge>
|
|
247
|
+
<ViewerPage />
|
|
248
|
+
</SystemContextBridge>
|
|
249
|
+
)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
ViewerRoute.authGuard = true
|
|
253
|
+
ViewerRoute.guestGuard = false
|
|
254
|
+
```
|
|
118
255
|
|
|
119
256
|
---
|
|
120
257
|
|
|
121
258
|
## Navigation Extension API
|
|
122
259
|
|
|
123
|
-
|
|
260
|
+
### Option A — Static items via the Provider
|
|
261
|
+
|
|
262
|
+
```jsx
|
|
263
|
+
<RoboByteFrontBuilderProvider
|
|
264
|
+
navExtensions={[
|
|
265
|
+
{
|
|
266
|
+
id: 'host-analytics',
|
|
267
|
+
title: 'Analytics',
|
|
268
|
+
icon: 'ChartBar',
|
|
269
|
+
type: 'static',
|
|
270
|
+
path: '/analytics',
|
|
271
|
+
insertAt: 'end',
|
|
272
|
+
},
|
|
273
|
+
]}
|
|
274
|
+
>
|
|
275
|
+
...
|
|
276
|
+
</RoboByteFrontBuilderProvider>
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Option B — Dynamic items via `useNavExtension` hook
|
|
124
280
|
|
|
125
281
|
```jsx
|
|
126
282
|
import { useNavExtension } from 'robobyte-front-builder'
|
|
127
283
|
|
|
128
|
-
|
|
129
|
-
useNavExtension(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
284
|
+
function MyFeaturePlugin() {
|
|
285
|
+
useNavExtension(
|
|
286
|
+
[{ id: 'my-feature', title: 'My Feature', icon: 'StarOutline', type: 'static', path: '/my-feature', insertAt: 'start' }],
|
|
287
|
+
'my-feature-plugin'
|
|
288
|
+
)
|
|
289
|
+
return null
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Nav item shape
|
|
294
|
+
|
|
295
|
+
| Field | Type | Required | Description |
|
|
296
|
+
|---|---|---|---|
|
|
297
|
+
| `id` | string | yes | Stable unique identifier |
|
|
298
|
+
| `title` | string | yes | Display label |
|
|
299
|
+
| `icon` | string | no | mdi-material-ui icon name |
|
|
300
|
+
| `type` | `'static'` \| `'dynamic'` \| `'external'` | yes | Route type |
|
|
301
|
+
| `path` | string | for `static` | Absolute path |
|
|
302
|
+
| `viewId` | number | for `dynamic` | Registered view ID |
|
|
303
|
+
| `externalUrl` | string | for `external` | Full URL, opens in new tab |
|
|
304
|
+
| `insertAt` | `'start'` \| `'end'` \| number \| `{ afterId }` \| `{ beforeId }` | no | Placement (default `'end'`) |
|
|
305
|
+
| `children` | NavItem[] | no | Collapsible group |
|
|
306
|
+
| `action` / `subject` | string | no | CASL ACL visibility |
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Provider props reference
|
|
311
|
+
|
|
312
|
+
| Prop | Type | Description |
|
|
313
|
+
|---|---|---|
|
|
314
|
+
| `baseURL` | string | Root API server URL |
|
|
315
|
+
| `apiURL` | string | `/api` prefix URL |
|
|
316
|
+
| `user` | object | Current user object from your auth context |
|
|
317
|
+
| `accessToken` | string | Bearer token attached to every service call |
|
|
318
|
+
| `agGridLicenseKey` | string | AG Grid Enterprise license key — the provider calls `LicenseManager.setLicenseKey()` and registers all enterprise modules internally |
|
|
319
|
+
| `navExtensions` | array | Static nav items to inject into the sidebar |
|
|
320
|
+
| `endpoints` | object | Full-URL overrides per endpoint group + name |
|
|
321
|
+
|
|
322
|
+
> **AG Grid note:** Do not call `LicenseManager` or `ModuleRegistry` in the host app — the provider handles it entirely.
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## `fetchReportDataByPageId`
|
|
136
327
|
|
|
137
|
-
|
|
328
|
+
Fetches report data by `pageId` without any AG Grid dependency. Always imported from the package path — the `NormalModuleReplacementPlugin` in `next.config.js` routes it to the package's canonical implementation.
|
|
329
|
+
|
|
330
|
+
```js
|
|
331
|
+
import fetchReportDataByPageId from 'services/reportData/fetchReportData'
|
|
332
|
+
|
|
333
|
+
const result = await fetchReportDataByPageId({
|
|
334
|
+
pageId, // required
|
|
335
|
+
filter, // { Tfilter, TFilter, customFilterCode, ... }
|
|
336
|
+
isDataOnly, // return raw rows only (default false)
|
|
337
|
+
dataAsObject, // key rows by unique id (default false)
|
|
338
|
+
isPagination, // server-side pagination (default true)
|
|
339
|
+
isSingle, // return first row only (default false)
|
|
340
|
+
globalParams, // override selectionParams by index
|
|
341
|
+
page, // page number (default 1)
|
|
342
|
+
pageSize, // page size (default 50)
|
|
343
|
+
authContext,
|
|
344
|
+
context,
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
if (result.success) {
|
|
348
|
+
console.log(result.rows)
|
|
349
|
+
console.log(result.total)
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### `customFilterCode`
|
|
354
|
+
|
|
355
|
+
```js
|
|
356
|
+
const filter = {
|
|
357
|
+
customFilterCode: `
|
|
358
|
+
if (authContext?.user?.shopId) {
|
|
359
|
+
customFilter.push({ field: 'ShopId', value: authContext.user.shopId, operation: 'Equal' })
|
|
360
|
+
}
|
|
361
|
+
`
|
|
138
362
|
}
|
|
139
363
|
```
|
|
140
364
|
|
|
141
365
|
---
|
|
142
366
|
|
|
143
|
-
##
|
|
367
|
+
## ReportViewer as a component
|
|
368
|
+
|
|
369
|
+
`ReportViewer` can be rendered inline anywhere — not only as a full page:
|
|
370
|
+
|
|
371
|
+
```jsx
|
|
372
|
+
import { ReportViewer } from 'robobyte-front-builder'
|
|
373
|
+
|
|
374
|
+
<ReportViewer
|
|
375
|
+
pageId="your-page-id"
|
|
376
|
+
minimized={true}
|
|
377
|
+
noHeader={true}
|
|
378
|
+
filter={{ Tfilter: [...] }}
|
|
379
|
+
height="400px"
|
|
380
|
+
/>
|
|
381
|
+
```
|
|
144
382
|
|
|
145
383
|
| Prop | Type | Description |
|
|
146
384
|
|---|---|---|
|
|
147
|
-
| `
|
|
148
|
-
| `
|
|
149
|
-
| `
|
|
150
|
-
| `
|
|
151
|
-
| `
|
|
152
|
-
| `
|
|
385
|
+
| `id` | string | Report ID |
|
|
386
|
+
| `pageId` | string | Report page ID |
|
|
387
|
+
| `filter` | object | External filter |
|
|
388
|
+
| `minimized` | bool | Removes padding and box shadow |
|
|
389
|
+
| `noHeader` | bool | Hides the report title and studio button |
|
|
390
|
+
| `height` | string | Grid height (default `85vh`) |
|
|
391
|
+
| `isSingle` | bool | Return only the first row |
|
|
392
|
+
| `dataAsObject` | bool | Key rows by unique id |
|
|
393
|
+
| `setData` | function | Callback receiving the loaded rows |
|
|
394
|
+
| `setOutGridApi` | function | Callback receiving the AG Grid API instance |
|
|
395
|
+
| `refresh` | any | Change this value to force a data reload |
|
|
396
|
+
| `actions` | array | Custom row action buttons |
|
|
397
|
+
| `columnsConfig` | array | Column overrides |
|
|
398
|
+
| `globalParams` | array | Override selectionParams by index |
|
|
399
|
+
| `sessionId` | string | Load filter payload from localStorage |
|
|
400
|
+
| `updateRef` | ref | Ref for programmatic updates |
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## Data Grid component
|
|
405
|
+
|
|
406
|
+
The **Data Grid** wraps AG Grid Enterprise and is configurable entirely from the builder inspector.
|
|
407
|
+
|
|
408
|
+
### Inspector — Main tab
|
|
409
|
+
|
|
410
|
+
| Field | Description |
|
|
411
|
+
|---|---|
|
|
412
|
+
| `Key` | Reference key for `reportRefs` access |
|
|
413
|
+
| `Data Key` | Key to read/write row data in page `data` |
|
|
414
|
+
| `Columns` | Expression returning an AG Grid `colDef[]` array |
|
|
415
|
+
| `Extra Columns` | Visual editor for adding new columns on top of data-driven ones |
|
|
416
|
+
| `Columns Config` | Visual editor for overriding existing column properties by `field` name |
|
|
417
|
+
| `Row Actions` | Visual editor for per-row action buttons |
|
|
418
|
+
| `Add Button Label` | Label for the add-row button (default `"Add"`) |
|
|
419
|
+
| `New Row Template` | Code returning the default object for a new row |
|
|
420
|
+
| `Read Only` | Expression — when truthy, disables all editing |
|
|
421
|
+
| `Show Add Button` | Toggle the add-row button |
|
|
422
|
+
| `Show Delete Col` | Toggle the delete-row column |
|
|
423
|
+
| `Height` | Grid height expression (e.g. `'400px'`, `'60vh'`) |
|
|
424
|
+
| `Row Selection` | `none` / `single` / `multiple` |
|
|
425
|
+
| `Pagination` | Enable client-side pagination |
|
|
426
|
+
| `Page Size` | Rows per page |
|
|
427
|
+
|
|
428
|
+
### `reportRefs` API
|
|
429
|
+
|
|
430
|
+
```js
|
|
431
|
+
const grid = reportRefs['myGridKey']
|
|
432
|
+
grid.getRows() // current row data array
|
|
433
|
+
grid.setRows(arr) // replace all rows
|
|
434
|
+
grid.addRow(obj) // append a row
|
|
435
|
+
grid.updateRow(index, obj) // update a row by index
|
|
436
|
+
grid.deleteRow(index) // delete a row by index
|
|
437
|
+
grid.getGridApi() // raw AG Grid API instance
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## Dialog component
|
|
443
|
+
|
|
444
|
+
Renders a hidden MUI Dialog opened programmatically via `openDialog(key)` / `closeDialog(key)`.
|
|
445
|
+
|
|
446
|
+
### Inspector — Main tab
|
|
447
|
+
|
|
448
|
+
| Field | Description |
|
|
449
|
+
|---|---|
|
|
450
|
+
| `Key` | Identifier used to open/close — must be unique on the page |
|
|
451
|
+
| `View ID` | When set, renders a full embedded view inside the dialog body |
|
|
452
|
+
| `Title` | Dialog title bar text (expression) |
|
|
453
|
+
| `Hide Title Bar` | Hides the entire title bar |
|
|
454
|
+
| `Max Width` | `xs` / `sm` / `md` / `lg` / `xl` |
|
|
455
|
+
| `Full Width` | Stretch to max width breakpoint |
|
|
456
|
+
| `Full Screen` | Full-screen mode |
|
|
457
|
+
| `Show Close Button` | Shows the × icon |
|
|
458
|
+
| `Close on Backdrop` | Closes when user clicks outside |
|
|
459
|
+
| `Action Buttons` | Footer buttons, each with its own Calculation code |
|
|
460
|
+
|
|
461
|
+
### Usage
|
|
462
|
+
|
|
463
|
+
```js
|
|
464
|
+
// Open with optional seed data
|
|
465
|
+
openDialog('confirmDelete')
|
|
466
|
+
openDialog('editUser', { userId: row.id, name: row.name })
|
|
467
|
+
|
|
468
|
+
// Close
|
|
469
|
+
closeDialog('confirmDelete')
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Isolated data store
|
|
473
|
+
|
|
474
|
+
Each dialog gets its own `data` / `setData` scope. To read or write the parent page state from inside a dialog use `pageData` and `pageSetData`:
|
|
475
|
+
|
|
476
|
+
```js
|
|
477
|
+
// Inside a dialog action:
|
|
478
|
+
pageSetData(prev => ({ ...prev, lastEdited: data.userId }))
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
## Popover component
|
|
484
|
+
|
|
485
|
+
A self-contained trigger (button, icon button, or text) that opens a floating panel. No `openDialog` call needed.
|
|
486
|
+
|
|
487
|
+
### Inspector — Main tab
|
|
488
|
+
|
|
489
|
+
| Field | Description |
|
|
490
|
+
|---|---|
|
|
491
|
+
| `Trigger Type` | `button` / `icon-button` / `text` |
|
|
492
|
+
| `Trigger Label` | Label text |
|
|
493
|
+
| `Placement` | `bottom-start`, `bottom`, `bottom-end`, `top-start`, etc. |
|
|
494
|
+
| `Trigger On` | `click` (default) or `hover` |
|
|
495
|
+
| `Controlled Open` | Expression — overrides the internal open/close state |
|
|
496
|
+
| `Close On Content Click` | Closes when any child inside is clicked |
|
|
153
497
|
|
|
154
498
|
---
|
|
155
499
|
|
|
156
|
-
##
|
|
500
|
+
## Excel Upload component
|
|
501
|
+
|
|
502
|
+
Lets users upload `.xlsx`, `.xls`, or `.csv` files, map columns to field names, and access the result in actions.
|
|
503
|
+
|
|
504
|
+
### Display variants
|
|
505
|
+
|
|
506
|
+
| Variant | Description |
|
|
507
|
+
|---|---|
|
|
508
|
+
| `dropzone` | Large dashed drop zone with drag & drop |
|
|
509
|
+
| `button` | Compact outlined button |
|
|
510
|
+
| `icon` | Icon-only button |
|
|
511
|
+
|
|
512
|
+
### Actions
|
|
513
|
+
|
|
514
|
+
| Event | `newValue` | Notes |
|
|
515
|
+
|---|---|---|
|
|
516
|
+
| `onUpload` | `{ fileName, headers, rowCount }` | Fires after parsing, before the mapping dialog |
|
|
517
|
+
| `onMapped` | `Array<object>` | Fires before data is saved — **return a modified array** to override |
|
|
518
|
+
| `onClear` | `[]` | Fires when the user clears the data |
|
|
157
519
|
|
|
158
|
-
|
|
520
|
+
### `reportRefs` API
|
|
159
521
|
|
|
160
522
|
```js
|
|
161
|
-
|
|
523
|
+
const uploader = reportRefs['myUploaderKey']
|
|
524
|
+
uploader.rows // current mapped rows
|
|
525
|
+
uploader.setRows(arr) // replace stored rows
|
|
526
|
+
uploader.clear() // clear all stored rows
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
---
|
|
530
|
+
|
|
531
|
+
## Wizard component
|
|
532
|
+
|
|
533
|
+
A MUI Stepper with optional validation, async lifecycle hooks, and controlled or uncontrolled step state.
|
|
162
534
|
|
|
163
|
-
|
|
535
|
+
### Inspector props — Wizard
|
|
536
|
+
|
|
537
|
+
| Prop | Type | Default | Description |
|
|
538
|
+
|---|---|---|---|
|
|
539
|
+
| `orientation` | `'horizontal'` \| `'vertical'` | `'horizontal'` | Stepper orientation |
|
|
540
|
+
| `linear` | boolean | `true` | Prevent skipping ahead |
|
|
541
|
+
| `hideNavigation` | boolean | `false` | Hide Back / Next / Finish buttons |
|
|
542
|
+
| `key` | string | `'wizardStep'` | `data` key written with the current step index |
|
|
543
|
+
| `activeStep` | number \| expression | — | When set, wizard is controlled by `data[key]` |
|
|
544
|
+
| `onStepChange` | JS action | — | Receives `{ from, to, direction, goToStep, nextStep, prevStep }` |
|
|
545
|
+
| `onFinish` | JS action | — | Runs when user clicks Finish on the last step |
|
|
546
|
+
|
|
547
|
+
### Inspector props — Wizard Step
|
|
548
|
+
|
|
549
|
+
| Prop | Type | Description |
|
|
550
|
+
|---|---|---|
|
|
551
|
+
| `label` | string | Step label in the stepper header |
|
|
552
|
+
| `optional` | boolean | Marks the step as optional |
|
|
553
|
+
| `onEnter` | JS action | Fires when this step becomes active |
|
|
554
|
+
| `onNext` | JS action | Return `false` to block navigation (validation) |
|
|
555
|
+
|
|
556
|
+
### Navigation helpers
|
|
557
|
+
|
|
558
|
+
```js
|
|
559
|
+
goToStep(n) // jump to step n (0-based)
|
|
560
|
+
nextStep() // advance one step
|
|
561
|
+
prevStep() // go back one step
|
|
164
562
|
```
|
|
165
563
|
|
|
166
564
|
---
|
|
167
565
|
|
|
168
|
-
##
|
|
566
|
+
## Repeater component
|
|
567
|
+
|
|
568
|
+
Renders a list of identical template items from a static array, a dynamic count, or a fetched API endpoint.
|
|
569
|
+
|
|
570
|
+
| Mode | How to configure |
|
|
571
|
+
|---|---|
|
|
572
|
+
| Static items | Set `items` to a static or expression array |
|
|
573
|
+
| Count | Set `count` to a number; optionally `dataKey` to store values |
|
|
574
|
+
| Endpoint | Set `endpoint` + `serviceId` or `widgetId` |
|
|
575
|
+
|
|
576
|
+
### Expressions inside a Repeater
|
|
577
|
+
|
|
578
|
+
| Variable | Value |
|
|
579
|
+
|---|---|
|
|
580
|
+
| `dataItem` | The current array element |
|
|
581
|
+
| `itemIndex` | Zero-based item index |
|
|
582
|
+
| `form[key]` | The current item's scoped form value |
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
## Menu component
|
|
587
|
+
|
|
588
|
+
Renders a MUI Tabs bar in two modes: **navigation mode** (items-based, each tab is a link/action) and **tab-panel mode** (tabs-based, each tab owns a drop zone).
|
|
589
|
+
|
|
590
|
+
| Prop | Type | Description |
|
|
591
|
+
|---|---|---|
|
|
592
|
+
| `items` | array | Navigation items `{ title, icon?, href? }` — enables navigation mode |
|
|
593
|
+
| `tabs` | array | Tab panel items `{ label, icon? }` — enables tab-panel mode |
|
|
594
|
+
| `vertical` | boolean | Render tabs vertically |
|
|
595
|
+
| `justified` | boolean | Stretch tabs to fill full width |
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
## View Renderer component
|
|
600
|
+
|
|
601
|
+
Embeds a saved builder view inline inside another view, with isolated or shared state.
|
|
602
|
+
|
|
603
|
+
| Prop | Type | Description |
|
|
604
|
+
|---|---|---|
|
|
605
|
+
| `viewId` | string | **Required.** ID of the saved view to embed |
|
|
606
|
+
| `isolated` | boolean | `true` = own data/form/refs, `false` = shares parent state |
|
|
607
|
+
| `initialData` | expression | Seed data passed on mount (isolated mode only) |
|
|
608
|
+
| `externalData` | expression | Additional data merged on every parent re-render |
|
|
609
|
+
| `heightMode` | `'auto'` \| `'fixed'` | `'fixed'` enables a pixel height with scroll |
|
|
610
|
+
| `height` | number | Pixel height when `heightMode` is `'fixed'` |
|
|
611
|
+
|
|
612
|
+
---
|
|
613
|
+
|
|
614
|
+
## Layout Grid component
|
|
615
|
+
|
|
616
|
+
A CSS Grid container whose column count, gap, and per-cell styling are configured in the builder inspector.
|
|
617
|
+
|
|
618
|
+
| Prop | Type | Default | Description |
|
|
619
|
+
|---|---|---|---|
|
|
620
|
+
| `cols` | number | `2` | Number of equal-width columns |
|
|
621
|
+
| `gap` | number px | `8` | Column gap |
|
|
622
|
+
| `rowGap` | number px | same as `gap` | Row gap |
|
|
623
|
+
| `cellMinHeight` | number/string | — | Default min-height for every cell |
|
|
624
|
+
| `cellPadding` | number/string | — | Inner padding for every cell |
|
|
625
|
+
| `cellBackgroundColor` | color | — | Background color for every cell |
|
|
626
|
+
| `cellBorder` | string | — | CSS border shorthand for every cell |
|
|
627
|
+
| `cellBorderRadius` | number/string | — | Border radius for every cell |
|
|
628
|
+
| `cellBoxShadow` | string | — | Box-shadow for every cell |
|
|
629
|
+
| `cellJustifyContent` | string | — | Flexbox `justify-content` inside every cell |
|
|
630
|
+
| `cellAlignItems` | string | — | Flexbox `align-items` inside every cell |
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
## Breadcrumb component
|
|
169
635
|
|
|
170
|
-
|
|
636
|
+
Renders a MUI Breadcrumbs navigation trail.
|
|
171
637
|
|
|
172
638
|
```json
|
|
173
|
-
|
|
174
|
-
"
|
|
639
|
+
{
|
|
640
|
+
"type": "breadcrumb",
|
|
641
|
+
"props": {
|
|
642
|
+
"main": {
|
|
643
|
+
"items": {
|
|
644
|
+
"valueType": "value",
|
|
645
|
+
"value": [
|
|
646
|
+
{ "label": "Home", "href": "/" },
|
|
647
|
+
{ "label": "Reports", "href": "/reports" },
|
|
648
|
+
{ "label": "Q1 2025" }
|
|
649
|
+
]
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
---
|
|
657
|
+
|
|
658
|
+
## Print Layout Builder
|
|
659
|
+
|
|
660
|
+
> ⚠️ **Preview — needs more testing.** Functional but not production-ready.
|
|
661
|
+
|
|
662
|
+
Design reusable print layouts with configurable headers, footers, multi-page bodies, watermarks, and page numbering.
|
|
663
|
+
|
|
664
|
+
### Backend API endpoints required
|
|
665
|
+
|
|
666
|
+
| Method | URL | Description |
|
|
667
|
+
|---|---|---|
|
|
668
|
+
| `POST` | `UiBuilderModule/PrintLayout` | Create a new layout |
|
|
669
|
+
| `PUT` | `UiBuilderModule/PrintLayout` | Update an existing layout |
|
|
670
|
+
| `GET` | `UiBuilderModule/PrintLayout/GetAll` | List all layouts |
|
|
671
|
+
| `GET` | `UiBuilderModule/PrintLayout/GetById?id=<id>` | Fetch by ID |
|
|
672
|
+
| `DELETE` | `UiBuilderModule/PrintLayout?id=<id>` | Delete a layout |
|
|
673
|
+
|
|
674
|
+
### Triggering print from a view
|
|
675
|
+
|
|
676
|
+
```js
|
|
677
|
+
openPrintLayout('your-layout-id', {
|
|
678
|
+
invoiceNumber: data.invoiceNumber,
|
|
679
|
+
customerName: data.customer.name,
|
|
680
|
+
lines: data.lines,
|
|
681
|
+
})
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
### Page numbering format
|
|
685
|
+
|
|
686
|
+
Use `{page}` and `{pages}` tokens in the Format field:
|
|
687
|
+
|
|
688
|
+
```
|
|
689
|
+
Page {page} of {pages} → Page 1 of 4
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
---
|
|
693
|
+
|
|
694
|
+
## Calculation Scope Reference
|
|
695
|
+
|
|
696
|
+
Every Calculation function receives the same set of variables:
|
|
697
|
+
|
|
698
|
+
### Core state
|
|
699
|
+
|
|
700
|
+
| Variable | Description |
|
|
701
|
+
|---|---|
|
|
702
|
+
| `form` | Form field values (read-only snapshot) |
|
|
703
|
+
| `data` | Reactive page state |
|
|
704
|
+
| `setData` | Write page state — `setData(prev => ({ ...prev, key: value }))` |
|
|
705
|
+
| `dataRef` | Mutable non-reactive store |
|
|
706
|
+
| `reportRefs` | Map of `{ [key]: ref }` for every Data Grid / Excel Upload on the page |
|
|
707
|
+
|
|
708
|
+
### Dialog / layout
|
|
709
|
+
|
|
710
|
+
| Variable | Description |
|
|
711
|
+
|---|---|
|
|
712
|
+
| `openDialog(key, data?)` | Open a dialog, optionally seeding its isolated state |
|
|
713
|
+
| `closeDialog(key)` | Close a dialog |
|
|
714
|
+
| `openPrintLayout(layoutId, data?)` | Open the print preview |
|
|
715
|
+
| `closePrintLayout()` | Close the active print preview |
|
|
716
|
+
|
|
717
|
+
### Navigation & routing
|
|
718
|
+
|
|
719
|
+
| Variable | Description |
|
|
720
|
+
|---|---|
|
|
721
|
+
| `router` | Next.js router — `router.push('/path')`, `router.query`, etc. |
|
|
722
|
+
| `urlParams` | `{ query, pathname, asPath }` snapshot |
|
|
723
|
+
|
|
724
|
+
### Global store
|
|
725
|
+
|
|
726
|
+
| Variable | Description |
|
|
727
|
+
|---|---|
|
|
728
|
+
| `globalData` | Cross-route global state (read) |
|
|
729
|
+
| `setGlobalData(updater)` | Write global state — shallow-merges by default |
|
|
730
|
+
|
|
731
|
+
### Services
|
|
732
|
+
|
|
733
|
+
| Variable | Description |
|
|
734
|
+
|---|---|
|
|
735
|
+
| `GetService` | Authenticated GET |
|
|
736
|
+
| `PostService` | Authenticated POST |
|
|
737
|
+
| `UpdateService` | Authenticated PUT |
|
|
738
|
+
| `PatchService` | Authenticated PATCH |
|
|
739
|
+
| `DeleteService` | Authenticated DELETE |
|
|
740
|
+
| `fetchReportData` | Fetch report data by `pageId` |
|
|
741
|
+
|
|
742
|
+
### Helpers
|
|
743
|
+
|
|
744
|
+
| Variable | Description |
|
|
745
|
+
|---|---|
|
|
746
|
+
| `showToast(message, type?)` | `'success'` \| `'error'` \| `'warning'` \| `'info'` \| `'loading'` |
|
|
747
|
+
|
|
748
|
+
### Parent page scope (inside dialogs / embedded views)
|
|
749
|
+
|
|
750
|
+
| Variable | Description |
|
|
751
|
+
|---|---|
|
|
752
|
+
| `page.data` | Parent page's reactive state |
|
|
753
|
+
| `page.setData` | Write to the parent page's state |
|
|
754
|
+
| `page.dataRef` | Parent page's non-reactive store |
|
|
755
|
+
| `page.reportRefs` | Parent page's grid refs |
|
|
756
|
+
|
|
757
|
+
### Repeater-only
|
|
758
|
+
|
|
759
|
+
| Variable | Description |
|
|
760
|
+
|---|---|
|
|
761
|
+
| `dataItem` | The current repeated item |
|
|
762
|
+
| `itemIndex` | Zero-based iteration index |
|
|
763
|
+
|
|
764
|
+
---
|
|
765
|
+
|
|
766
|
+
## KPI Component Actions
|
|
767
|
+
|
|
768
|
+
KPI components support interaction events configured in the inspector Main tab → Actions section.
|
|
769
|
+
|
|
770
|
+
| Component | Event | Click-context variables |
|
|
771
|
+
|---|---|---|
|
|
772
|
+
| **Metric** | `onClick` | `clickedValue` |
|
|
773
|
+
| **Rating** | `onChange` | `newValue`, `clickedValue` |
|
|
774
|
+
| **Chart** | `onDataClick` | `clickedItem`, `clickedValue`, `clickedField`, `clickedLabel`, `clickedIndex` |
|
|
775
|
+
| **HeatmapGrid** | `onCellClick` | `clickedItem`, `clickedValue`, `clickedRow`, `clickedCol`, `clickedRowIndex`, `clickedColIndex` |
|
|
776
|
+
| **Timeline** | `onItemClick` | `clickedItem`, `clickedIndex`, `clickedLabel`, `clickedStatus`, `clickedValue` |
|
|
777
|
+
| **StepStage** | `onStepClick` | `clickedItem`, `clickedIndex`, `clickedId`, `clickedLabel`, `clickedStatus` |
|
|
778
|
+
| **TagList** | `onTagClick` | `clickedItem`, `clickedTag`, `clickedLabel`, `clickedValue`, `clickedIndex` |
|
|
779
|
+
|
|
780
|
+
---
|
|
781
|
+
|
|
782
|
+
## Global Data Store
|
|
783
|
+
|
|
784
|
+
A module-level reactive singleton that survives client-side navigations.
|
|
785
|
+
|
|
786
|
+
### In Calculation functions
|
|
787
|
+
|
|
788
|
+
```js
|
|
789
|
+
// Read
|
|
790
|
+
console.log(globalData.selectedUser)
|
|
791
|
+
|
|
792
|
+
// Write
|
|
793
|
+
setGlobalData(prev => ({ ...prev, selectedUser: clickedItem }))
|
|
794
|
+
|
|
795
|
+
// Navigate — globalData persists to the next page
|
|
796
|
+
router.push('/user-detail')
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
### In React components
|
|
800
|
+
|
|
801
|
+
```jsx
|
|
802
|
+
import { useGlobalStore } from 'robobyte-front-builder'
|
|
803
|
+
|
|
804
|
+
function MyComponent() {
|
|
805
|
+
const { globalData, setGlobalData } = useGlobalStore()
|
|
806
|
+
return <p>Selected: {globalData.selectedUser?.name}</p>
|
|
807
|
+
}
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
### Resetting on logout
|
|
811
|
+
|
|
812
|
+
```js
|
|
813
|
+
import { resetGlobalData } from 'robobyte-front-builder'
|
|
814
|
+
|
|
815
|
+
function handleLogout() {
|
|
816
|
+
resetGlobalData()
|
|
817
|
+
// ... your auth logout
|
|
818
|
+
}
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
### API
|
|
822
|
+
|
|
823
|
+
| Export | Description |
|
|
824
|
+
|---|---|
|
|
825
|
+
| `useGlobalStore()` | React hook — `{ globalData, setGlobalData }` |
|
|
826
|
+
| `getGlobalData()` | Synchronous read from non-React code |
|
|
827
|
+
| `setGlobalData(updater)` | Write from anywhere |
|
|
828
|
+
| `subscribeGlobal(fn)` | Subscribe to changes — returns unsubscribe function |
|
|
829
|
+
| `resetGlobalData()` | Reset to `{}` and notify all subscribers |
|
|
830
|
+
|
|
831
|
+
---
|
|
832
|
+
|
|
833
|
+
## Dark / Light theme
|
|
834
|
+
|
|
835
|
+
Both the UI Builder and Print Layout Builder support dark and light modes (default: dark). A toggle button (☀️ / 🌙) is available in each builder's toolbar. The choice is persisted in `localStorage` under `rbb:builderThemeMode`. The theme is scoped to the builder pages only and does not affect the rest of the host application.
|
|
836
|
+
|
|
837
|
+
---
|
|
838
|
+
|
|
839
|
+
## Syncing local changes
|
|
840
|
+
|
|
841
|
+
When using `file:` path, `node_modules/robobyte-front-builder` is a **copy**, not a symlink. After editing source files, sync manually:
|
|
842
|
+
|
|
843
|
+
```bash
|
|
844
|
+
SRC=RoboByteFrontBuilder/src
|
|
845
|
+
PKG=YourApp/node_modules/robobyte-front-builder/src
|
|
846
|
+
|
|
847
|
+
cp $SRC/lib/index.js $PKG/lib/index.js
|
|
848
|
+
cp $SRC/lib/providers/RoboByteFrontBuilderProvider.jsx $PKG/lib/providers/RoboByteFrontBuilderProvider.jsx
|
|
849
|
+
cp $SRC/services/reportData/fetchReportData.js $PKG/services/reportData/fetchReportData.js
|
|
850
|
+
# ... add other files as needed
|
|
175
851
|
```
|
|
176
852
|
|
|
177
|
-
|
|
853
|
+
Hot-reload picks up all file changes automatically. Only `next.config.js` changes require a dev server restart.
|
|
854
|
+
|
|
855
|
+
---
|
|
856
|
+
|
|
857
|
+
## Troubleshooting
|
|
858
|
+
|
|
859
|
+
**"Module not found: Can't resolve 'xlsx'"**
|
|
860
|
+
→ Install `xlsx` in the host app: `npm install xlsx --legacy-peer-deps`
|
|
861
|
+
|
|
862
|
+
**"Cannot find module 'services/...'"**
|
|
863
|
+
→ Ensure the `NormalModuleReplacementPlugin` is configured in `next.config.js`
|
|
864
|
+
|
|
865
|
+
**AG Grid table not showing / license warning**
|
|
866
|
+
→ Pass `agGridLicenseKey` to `RoboByteFrontBuilderProvider`. Do not call `LicenseManager` or `ModuleRegistry` in the host app.
|
|
867
|
+
|
|
868
|
+
**AG Grid error #200 — IntegratedChartsModule not registered**
|
|
869
|
+
→ The provider registers `IntegratedChartsModule.with(AgChartsEnterpriseModule)` automatically. Ensure `ag-charts-enterprise` is installed in the package.
|
|
870
|
+
|
|
871
|
+
**ReportViewer renders at half width**
|
|
872
|
+
→ The outer `Box` in `reportViewer/index.js` must use `display: 'block'`, not `display: 'flex'`.
|
|
873
|
+
|
|
874
|
+
**Static props (`getLayout`, `acl`) not picked up from package exports**
|
|
875
|
+
→ Use the explicit import + assignment pattern. Bare `export { X as default }` does not carry static properties across package boundaries.
|
|
876
|
+
|
|
877
|
+
**Duplicate React / MUI hook errors**
|
|
878
|
+
→ Pin `react`, `react-dom`, and `@mui/material` to the host app's copies via `config.resolve.alias` in `next.config.js`.
|
|
879
|
+
|
|
880
|
+
**Old routes returning 404**
|
|
881
|
+
→ Check that host-app pages exist under `/builders/...` and that old paths have `getServerSideProps = () => ({ notFound: true })` stubs.
|
|
178
882
|
|
|
179
883
|
---
|
|
180
884
|
|
|
181
885
|
## Publishing
|
|
182
886
|
|
|
183
887
|
```bash
|
|
184
|
-
npm
|
|
185
|
-
|
|
186
|
-
npm version
|
|
888
|
+
npm login # one-time setup
|
|
889
|
+
|
|
890
|
+
npm version patch # 1.0.x — bug fixes
|
|
891
|
+
npm version minor # 1.x.0 — new features
|
|
892
|
+
npm version major # x.0.0 — breaking changes
|
|
893
|
+
|
|
187
894
|
npm publish
|
|
188
895
|
```
|
|
189
896
|
|
|
897
|
+
Dry run (verify what will be published without actually publishing):
|
|
898
|
+
```bash
|
|
899
|
+
npm publish --dry-run
|
|
900
|
+
```
|
|
901
|
+
|
|
190
902
|
---
|
|
191
903
|
|
|
192
904
|
## Changelog
|
|
193
905
|
|
|
194
906
|
### 1.0.21
|
|
195
|
-
- Added Timer Engine — configurable auto-refresh timers per view
|
|
907
|
+
- Added Timer Engine — configurable auto-refresh timers per view
|
|
196
908
|
- Added full Undo / Redo history with keyboard shortcuts (Ctrl+Z / Ctrl+Y)
|
|
197
909
|
- Added Cut / Copy / Paste with system clipboard support (Ctrl+X / Ctrl+C / Ctrl+V)
|
|
198
910
|
- Added Undo / Redo buttons to the viewer toolbar
|
|
199
|
-
- Expanded KPI
|
|
200
|
-
- Print Layout designer: multi-zone canvas
|
|
911
|
+
- Expanded KPI suite: Gauge, BulletChart, ColorScale, Rating, Countdown, AvatarGroup, StepStage
|
|
912
|
+
- Print Layout designer: multi-zone canvas, `@page` CSS, print dialog
|
|
201
913
|
|
|
202
914
|
### 1.0.20
|
|
203
915
|
- KPI components: Metric, Trend, Badge, StatusDot, IconBox, Sparkline, MiniBarChart, Donut, Funnel, HeatmapGrid, TagList, Timeline, ComparisonBars
|
|
@@ -209,3 +921,8 @@ npm publish
|
|
|
209
921
|
- Navigation Extension API
|
|
210
922
|
- AG Grid and MUI data grid integration
|
|
211
923
|
- Drag-and-drop canvas with 50+ components
|
|
924
|
+
- Global Data Store
|
|
925
|
+
|
|
926
|
+
---
|
|
927
|
+
|
|
928
|
+
*Full user manual: [RoboByteBuilder_User_Manual.docx](./RoboByteBuilder_User_Manual.docx) (included in the package)*
|