robobyte-front-builder 1.0.23 → 1.0.25
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/package.json
CHANGED
package/src/lib/index.js
CHANGED
|
@@ -98,3 +98,11 @@ export { SystemContext, SystemProvider } from '../context/SystemContext'
|
|
|
98
98
|
// RoboByteFrontBuilderProvider's user / accessToken props.
|
|
99
99
|
// There is no AuthProvider in this package; use your own host auth provider.
|
|
100
100
|
export { AuthContext } from '../context/AuthContext'
|
|
101
|
+
|
|
102
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
103
|
+
// fetchReportDataByPageId: pure data fetcher by report `pageId`, no AG Grid
|
|
104
|
+
// dependency. Host code can either import from this package surface (the
|
|
105
|
+
// recommended path) or via the bare alias 'services/reportData/fetchReportData'
|
|
106
|
+
// — both resolve to the same module thanks to the NormalModuleReplacementPlugin
|
|
107
|
+
// in next.config.js, so the in-memory builderModelCache is shared.
|
|
108
|
+
export { default as fetchReportDataByPageId } from '../services/reportData/fetchReportData'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, {useEffect, useState} from 'react'
|
|
2
|
-
import {Box, CircularProgress, Typography, Paper, IconButton, CardContent, Tooltip} from '@mui/material'
|
|
2
|
+
import {Box, CircularProgress, Typography, Paper, IconButton, CardContent, Tooltip, Popover, Chip} from '@mui/material'
|
|
3
3
|
import {useRouter} from 'next/router'
|
|
4
4
|
import SGrid from 'views/genericTable/SGrid'
|
|
5
5
|
import {Endpoints, Services} from 'services/Endpoints'
|
|
@@ -8,7 +8,7 @@ import CardHeader from "@mui/material/CardHeader";
|
|
|
8
8
|
import Grid from "@mui/material/Grid";
|
|
9
9
|
import {Plus} from "mdi-material-ui";
|
|
10
10
|
import TAGGrid from "views/genericTable/TAGGrid";
|
|
11
|
-
import {SettingsOutlined, AssessmentOutlined} from "@mui/icons-material";
|
|
11
|
+
import {SettingsOutlined, AssessmentOutlined, BugReportOutlined, ContentCopyOutlined} from "@mui/icons-material";
|
|
12
12
|
import UpdateReportPermissionDialog from "views/rolePermissions/UpdateReportPermissionDialog";
|
|
13
13
|
import {getReportSession} from 'src/services/helper/reportSessionHelper'
|
|
14
14
|
import BlankLayout from '../../../../lib/layouts/BlankLayout';
|
|
@@ -48,6 +48,12 @@ const ReportViewer = (params) => {
|
|
|
48
48
|
// Page-level toolbar buttons rendered after Filter / Refresh.
|
|
49
49
|
// Built by ReportViewerRenderer with bound onClick handlers.
|
|
50
50
|
viewerActions,
|
|
51
|
+
// Debug — when truthy, renders a small floating BugReport icon at the
|
|
52
|
+
// top-right corner of the report area. Clicking it opens a popover
|
|
53
|
+
// showing the resolved ids (pageId, id, builderMetadata.id) and other
|
|
54
|
+
// useful runtime info. Hidden entirely when `debug` is falsy, so
|
|
55
|
+
// production builds incur zero cost.
|
|
56
|
+
debug,
|
|
51
57
|
// nodeId / reportRefs are injected by the UI builder's ReportViewerRenderer.
|
|
52
58
|
// nodeId — the builder schema node ID for this ReportViewer instance
|
|
53
59
|
// reportRefs — the shared registry { [nodeId]: updateRef } for all reports on the page
|
|
@@ -64,6 +70,8 @@ const ReportViewer = (params) => {
|
|
|
64
70
|
const [builderMetadata, setBuilderMetadata] = useState(null)
|
|
65
71
|
const [sessionPayload, setSessionPayload] = useState(null)
|
|
66
72
|
const [payloadVersion, setPayloadVersion] = useState(0)
|
|
73
|
+
// Debug popover anchor — only used when `debug` prop is truthy.
|
|
74
|
+
const [debugAnchor, setDebugAnchor] = useState(null)
|
|
67
75
|
|
|
68
76
|
useEffect(() => {
|
|
69
77
|
// Prefer localStorage payload via sessionId (set by SGrid)
|
|
@@ -176,13 +184,137 @@ const ReportViewer = (params) => {
|
|
|
176
184
|
setPayloadVersion(v => v + 1);
|
|
177
185
|
}, [id, router.query?.id, pageId, router.query?.pageId, sessionPayload])
|
|
178
186
|
|
|
187
|
+
// ── Debug snapshot — gathered fresh on every render so the popover always
|
|
188
|
+
// reflects the current resolved state. Cheap to build (just reads
|
|
189
|
+
// existing state / props) so no memo needed.
|
|
190
|
+
const resolvedPageId = pageId ?? sessionPayload?.pageId ?? router.query?.pageId
|
|
191
|
+
const resolvedId = id ?? sessionPayload?.id ?? router.query?.id
|
|
192
|
+
const debugFields = debug ? [
|
|
193
|
+
{ label: 'pageId', value: resolvedPageId },
|
|
194
|
+
{ label: 'id (prop)', value: resolvedId },
|
|
195
|
+
{ label: 'builder model id', value: builderModel?.id },
|
|
196
|
+
{ label: 'report name', value: builderMetadata?.name },
|
|
197
|
+
{ label: 'nodeId', value: nodeId },
|
|
198
|
+
{ label: 'sessionId', value: sessionId },
|
|
199
|
+
{ label: 'payload version', value: payloadVersion },
|
|
200
|
+
{ label: 'session payload', value: sessionPayload ? '✓ loaded' : '—' },
|
|
201
|
+
{ label: 'isSingle', value: String(Boolean(isSingle)) },
|
|
202
|
+
{ label: 'dataAsObject', value: String(Boolean(dataAsObject)) },
|
|
203
|
+
{ label: 'isRerender', value: String(Boolean(isRerender)) },
|
|
204
|
+
{ label: 'externalTimer', value: externalTimer ?? '—' },
|
|
205
|
+
{ label: 'height', value: height ?? '85vh' },
|
|
206
|
+
{ label: 'globalParams', value: globalParams ? JSON.stringify(globalParams) : '—' },
|
|
207
|
+
] : []
|
|
208
|
+
|
|
209
|
+
const copyToClipboard = (value) => {
|
|
210
|
+
if (value == null) return
|
|
211
|
+
try { navigator.clipboard?.writeText(String(value)) } catch (_) {}
|
|
212
|
+
}
|
|
213
|
+
|
|
179
214
|
return (
|
|
180
215
|
<Box
|
|
181
216
|
sx={{
|
|
182
217
|
display: 'block',
|
|
183
218
|
width: '100%',
|
|
219
|
+
position: 'relative',
|
|
184
220
|
}}
|
|
185
221
|
>
|
|
222
|
+
{/* ── Debug floater ────────────────────────────────────────────────────
|
|
223
|
+
Renders only when the `debug` prop is truthy. A small icon button at
|
|
224
|
+
the top-right corner that opens a key/value popover. Useful when a
|
|
225
|
+
report appears broken — confirm pageId/id resolved correctly, the
|
|
226
|
+
builder model loaded, the right sessionPayload was picked, etc. */}
|
|
227
|
+
{debug && (
|
|
228
|
+
<>
|
|
229
|
+
<Tooltip title='Report debug info' placement='left'>
|
|
230
|
+
<IconButton
|
|
231
|
+
size='small'
|
|
232
|
+
onClick={(e) => setDebugAnchor(e.currentTarget)}
|
|
233
|
+
sx={{
|
|
234
|
+
position: 'absolute',
|
|
235
|
+
top: 4,
|
|
236
|
+
insetInlineEnd: 4,
|
|
237
|
+
zIndex: 10,
|
|
238
|
+
bgcolor: 'warning.light',
|
|
239
|
+
color: 'warning.contrastText',
|
|
240
|
+
opacity: 0.9,
|
|
241
|
+
'&:hover': { bgcolor: 'warning.main', opacity: 1 },
|
|
242
|
+
boxShadow: 1,
|
|
243
|
+
}}
|
|
244
|
+
>
|
|
245
|
+
<BugReportOutlined fontSize='small' />
|
|
246
|
+
</IconButton>
|
|
247
|
+
</Tooltip>
|
|
248
|
+
|
|
249
|
+
<Popover
|
|
250
|
+
open={Boolean(debugAnchor)}
|
|
251
|
+
anchorEl={debugAnchor}
|
|
252
|
+
onClose={() => setDebugAnchor(null)}
|
|
253
|
+
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
|
|
254
|
+
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
|
|
255
|
+
PaperProps={{ sx: { p: 0, minWidth: 320, maxWidth: 480 } }}
|
|
256
|
+
>
|
|
257
|
+
<Box sx={{ px: 2, py: 1, bgcolor: 'warning.light', display: 'flex', alignItems: 'center', gap: 1 }}>
|
|
258
|
+
<BugReportOutlined fontSize='small' sx={{ color: 'warning.contrastText' }} />
|
|
259
|
+
<Typography variant='subtitle2' sx={{ color: 'warning.contrastText', fontWeight: 700, flex: 1 }}>
|
|
260
|
+
Report Debug
|
|
261
|
+
</Typography>
|
|
262
|
+
<Chip
|
|
263
|
+
size='small'
|
|
264
|
+
label={isLoading ? 'loading' : builderModel ? 'ready' : 'idle'}
|
|
265
|
+
color={isLoading ? 'info' : builderModel ? 'success' : 'default'}
|
|
266
|
+
sx={{ height: 18, fontSize: 10 }}
|
|
267
|
+
/>
|
|
268
|
+
</Box>
|
|
269
|
+
<Box sx={{ p: 1.5, display: 'flex', flexDirection: 'column', gap: 0.5 }}>
|
|
270
|
+
{debugFields.map(({ label, value }) => (
|
|
271
|
+
<Box
|
|
272
|
+
key={label}
|
|
273
|
+
sx={{
|
|
274
|
+
display: 'grid',
|
|
275
|
+
gridTemplateColumns: '130px 1fr auto',
|
|
276
|
+
alignItems: 'center',
|
|
277
|
+
gap: 1,
|
|
278
|
+
px: 1,
|
|
279
|
+
py: 0.5,
|
|
280
|
+
borderRadius: 0.5,
|
|
281
|
+
'&:hover': { bgcolor: 'action.hover' },
|
|
282
|
+
}}
|
|
283
|
+
>
|
|
284
|
+
<Typography variant='caption' sx={{ color: 'text.secondary', fontFamily: 'monospace' }}>
|
|
285
|
+
{label}
|
|
286
|
+
</Typography>
|
|
287
|
+
<Typography
|
|
288
|
+
variant='body2'
|
|
289
|
+
sx={{
|
|
290
|
+
fontFamily: 'monospace',
|
|
291
|
+
fontSize: 12,
|
|
292
|
+
color: value == null || value === '—' ? 'text.disabled' : 'text.primary',
|
|
293
|
+
overflow: 'hidden',
|
|
294
|
+
textOverflow: 'ellipsis',
|
|
295
|
+
whiteSpace: 'nowrap',
|
|
296
|
+
}}
|
|
297
|
+
title={String(value ?? '')}
|
|
298
|
+
>
|
|
299
|
+
{value ?? '—'}
|
|
300
|
+
</Typography>
|
|
301
|
+
<Tooltip title='Copy' placement='left'>
|
|
302
|
+
<IconButton
|
|
303
|
+
size='small'
|
|
304
|
+
onClick={() => copyToClipboard(value)}
|
|
305
|
+
disabled={value == null || value === '—'}
|
|
306
|
+
sx={{ p: 0.25 }}
|
|
307
|
+
>
|
|
308
|
+
<ContentCopyOutlined sx={{ fontSize: 13 }} />
|
|
309
|
+
</IconButton>
|
|
310
|
+
</Tooltip>
|
|
311
|
+
</Box>
|
|
312
|
+
))}
|
|
313
|
+
</Box>
|
|
314
|
+
</Popover>
|
|
315
|
+
</>
|
|
316
|
+
)}
|
|
317
|
+
|
|
186
318
|
{isLoading ? (
|
|
187
319
|
<Box
|
|
188
320
|
sx={{
|
|
@@ -9,6 +9,11 @@ export const REPORT_VIEWER_MAIN_FIELDS = [
|
|
|
9
9
|
{ name: 'title', label: 'Title', type: 'expression' },
|
|
10
10
|
{ name: 'caption', label: 'Caption', type: 'expression' },
|
|
11
11
|
|
|
12
|
+
// Debug — when true, a small BugReport icon appears at the report's
|
|
13
|
+
// top-right corner; clicking it opens a popover listing the resolved
|
|
14
|
+
// pageId / id / builder model id / sessionId / and other runtime info.
|
|
15
|
+
// Hidden entirely when false / unset — zero cost in production schemas.
|
|
16
|
+
{ name: 'debug', label: 'Debug', type: 'boolean' },
|
|
12
17
|
{ name: 'minimized', label: 'Minimized', type: 'boolean' },
|
|
13
18
|
{ name: 'isRerender', label: 'Is Rerender', type: 'boolean' },
|
|
14
19
|
{ name: 'height', label: 'Height', type: 'expression' },
|