robobyte-front-builder 1.0.8 → 1.0.11
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
|
@@ -73,6 +73,9 @@ export { default as RoboByteFrontBuilderProvider } from './providers/RoboByteFro
|
|
|
73
73
|
export { default as UIBuilderPage } from '../pages/viewBuilder/index'
|
|
74
74
|
export { default as ReportBuilderPage } from '../pages/reportModule/reportBuilder/index'
|
|
75
75
|
export { default as NavigatorBuilderPage } from '../pages/navigatorBuilder/index'
|
|
76
|
+
// ViewerPage renders a saved UI Builder view (read-only production mode).
|
|
77
|
+
// Create a host page at e.g. pages/viewer/[id].jsx and re-export this component.
|
|
78
|
+
export { default as ViewerPage } from '../pages/viewer/[id]/index'
|
|
76
79
|
|
|
77
80
|
// ── Core Contexts & Hooks (advanced use) ─────────────────────────────────────
|
|
78
81
|
// Useful when you need to read or drive builder state from the host app.
|
|
@@ -1851,7 +1851,7 @@ const NavigatorBuilder = () => {
|
|
|
1851
1851
|
|
|
1852
1852
|
const jsonString = JSON.stringify(saveData)
|
|
1853
1853
|
|
|
1854
|
-
//
|
|
1854
|
+
// C# endpoint: [FromBody] NavigatorSettingForm form → expects { "value": "..." }
|
|
1855
1855
|
const result = await PostService(Endpoints.Navigator.Post.NavigatorSetting, true, {
|
|
1856
1856
|
value: jsonString
|
|
1857
1857
|
})
|
|
@@ -1,21 +1,43 @@
|
|
|
1
1
|
import { useRouter } from 'next/router'
|
|
2
|
-
import { useEffect, useState, useContext } from 'react'
|
|
3
|
-
import { Box, Typography, CircularProgress, Grid } from '@mui/material'
|
|
2
|
+
import { useEffect, useState, useContext, useMemo } from 'react'
|
|
3
|
+
import { Box, Typography, CircularProgress, Grid, Tab, Tabs } from '@mui/material'
|
|
4
4
|
import { SystemContext } from 'context/SystemContext'
|
|
5
5
|
import { Endpoints, Services } from 'services/Endpoints'
|
|
6
6
|
import ProductionViewer from 'views/builder/viewer/ProductionViewer'
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Finds the parent group of a viewId in the navigator config items tree.
|
|
10
|
+
* Returns the array of siblings (all dynamic children of that parent).
|
|
11
|
+
*
|
|
12
|
+
* nav.config.items shape:
|
|
13
|
+
* [ { title, children: [ { title, type, viewId }, ... ] }, ... ]
|
|
14
|
+
*/
|
|
15
|
+
function findSiblings(navConfig, viewId) {
|
|
16
|
+
if (!navConfig?.items || viewId == null) return []
|
|
17
|
+
for (const group of navConfig.items) {
|
|
18
|
+
const children = group.children || []
|
|
19
|
+
const dynamicChildren = children.filter(c => c.type === 'dynamic' && c.viewId != null)
|
|
20
|
+
const found = dynamicChildren.find(c => Number(c.viewId) === Number(viewId))
|
|
21
|
+
if (found) return dynamicChildren
|
|
22
|
+
}
|
|
23
|
+
return []
|
|
24
|
+
}
|
|
25
|
+
|
|
8
26
|
export default function ViewPage() {
|
|
9
27
|
const router = useRouter()
|
|
10
28
|
const { id } = router.query
|
|
11
29
|
const systemContext = useContext(SystemContext)
|
|
12
30
|
const viewRegistry = systemContext.nav?.registry || {}
|
|
31
|
+
const navConfig = systemContext.nav?.config
|
|
13
32
|
|
|
14
33
|
const [schema, setSchema] = useState({})
|
|
15
34
|
const [viewMetaData, setViewMetaData] = useState({})
|
|
16
35
|
const [loading, setLoading] = useState(true)
|
|
17
36
|
const [error, setError] = useState(null)
|
|
18
37
|
|
|
38
|
+
// Sibling pages under the same root section — used for horizontal sub-nav tabs
|
|
39
|
+
const siblings = useMemo(() => findSiblings(navConfig, id), [navConfig, id])
|
|
40
|
+
|
|
19
41
|
const handleGetView = async (viewId) => {
|
|
20
42
|
try {
|
|
21
43
|
setLoading(true)
|
|
@@ -51,7 +73,6 @@ export default function ViewPage() {
|
|
|
51
73
|
}
|
|
52
74
|
}, [id])
|
|
53
75
|
|
|
54
|
-
// Loading state
|
|
55
76
|
if (!id) return null
|
|
56
77
|
|
|
57
78
|
if (loading) {
|
|
@@ -68,21 +89,73 @@ export default function ViewPage() {
|
|
|
68
89
|
const view = viewRegistry[viewId]
|
|
69
90
|
|
|
70
91
|
return (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
92
|
+
<>
|
|
93
|
+
{siblings.length > 1 && (
|
|
94
|
+
<HorizontalSubNav siblings={siblings} currentId={viewId} router={router} />
|
|
95
|
+
)}
|
|
96
|
+
<Box sx={{ p: 6, textAlign: 'center' }}>
|
|
97
|
+
<Typography variant="h4">Coming soon 🚧</Typography>
|
|
98
|
+
<Typography variant="body2" sx={{ mt: 2 }}>
|
|
99
|
+
View #{viewId} {view ? `(${view.name})` : ''} has not been created yet.
|
|
100
|
+
</Typography>
|
|
101
|
+
</Box>
|
|
102
|
+
</>
|
|
77
103
|
)
|
|
78
104
|
}
|
|
79
105
|
|
|
80
|
-
// Success state
|
|
106
|
+
// Success state
|
|
81
107
|
return (
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
<
|
|
108
|
+
<Box>
|
|
109
|
+
{siblings.length > 1 && (
|
|
110
|
+
<HorizontalSubNav siblings={siblings} currentId={Number(id)} router={router} />
|
|
111
|
+
)}
|
|
112
|
+
<Grid container>
|
|
113
|
+
<Grid item size={12}>
|
|
114
|
+
<ProductionViewer schema={schema} />
|
|
115
|
+
</Grid>
|
|
85
116
|
</Grid>
|
|
86
|
-
</
|
|
117
|
+
</Box>
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Horizontal sub-navigation tabs shown at the top of the viewer page
|
|
123
|
+
* when the current view has sibling pages under the same root section.
|
|
124
|
+
*/
|
|
125
|
+
function HorizontalSubNav({ siblings, currentId, router }) {
|
|
126
|
+
const currentIndex = siblings.findIndex(s => Number(s.viewId) === Number(currentId))
|
|
127
|
+
const activeTab = currentIndex >= 0 ? currentIndex : 0
|
|
128
|
+
|
|
129
|
+
const handleChange = (_, newIndex) => {
|
|
130
|
+
const target = siblings[newIndex]
|
|
131
|
+
if (target?.viewId != null) {
|
|
132
|
+
router.push(`/viewer/${target.viewId}`)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return (
|
|
137
|
+
<Box
|
|
138
|
+
sx={{
|
|
139
|
+
borderBottom: 1,
|
|
140
|
+
borderColor: 'divider',
|
|
141
|
+
mb: 2,
|
|
142
|
+
backgroundColor: 'background.paper',
|
|
143
|
+
px: 2,
|
|
144
|
+
}}
|
|
145
|
+
>
|
|
146
|
+
<Tabs
|
|
147
|
+
value={activeTab}
|
|
148
|
+
onChange={handleChange}
|
|
149
|
+
variant="scrollable"
|
|
150
|
+
scrollButtons="auto"
|
|
151
|
+
>
|
|
152
|
+
{siblings.map((sibling) => (
|
|
153
|
+
<Tab
|
|
154
|
+
key={sibling.viewId}
|
|
155
|
+
label={sibling.title}
|
|
156
|
+
/>
|
|
157
|
+
))}
|
|
158
|
+
</Tabs>
|
|
159
|
+
</Box>
|
|
87
160
|
)
|
|
88
161
|
}
|