1
1
// SceneConfigurationSection.tsx
2
+
2
3
import React , { useMemo } from 'react' ;
3
4
import { JsonForms } from '@jsonforms/react' ;
4
5
import {
8
9
import { Alert , AlertDescription } from '../ui/alert' ;
9
10
import { Scene , ValidationError } from '../../types' ;
10
11
12
+ // The schema for Scenes remains the same.
13
+ // It defines Scenes as an array of scene objects, each with a Layouts array.
11
14
const sceneConfigSchema = {
12
15
type : 'object' ,
13
16
properties : {
@@ -18,15 +21,8 @@ const sceneConfigSchema = {
18
21
type : 'object' ,
19
22
required : [ 'Id' , 'ProjectorMode' , 'Layouts' ] ,
20
23
properties : {
21
- Id : {
22
- type : 'string' ,
23
- title : 'Scene ID' ,
24
- description : 'Unique identifier for this scene' ,
25
- } ,
26
- Variant : {
27
- type : 'string' ,
28
- title : 'Scene Variant' ,
29
- } ,
24
+ Id : { type : 'string' , title : 'Scene ID' } ,
25
+ Variant : { type : 'string' , title : 'Scene Variant' } ,
30
26
ProjectorMode : {
31
27
type : 'string' ,
32
28
title : 'Projector Mode' ,
@@ -147,6 +143,7 @@ const sceneConfigSchema = {
147
143
required : [ 'Scenes' ] ,
148
144
} ;
149
145
146
+ // UI schema
150
147
const sceneConfigUiSchema = {
151
148
type : 'VerticalLayout' ,
152
149
elements : [
@@ -157,7 +154,6 @@ const sceneConfigUiSchema = {
157
154
detail : {
158
155
type : 'VerticalLayout' ,
159
156
elements : [
160
- // Scene Basic Info
161
157
{
162
158
type : 'Group' ,
163
159
label : 'Basic Scene Information' ,
@@ -167,11 +163,11 @@ const sceneConfigUiSchema = {
167
163
elements : [
168
164
{
169
165
type : 'Control' ,
170
- scope : '#/properties/Id' ,
166
+ scope : '#/properties/Id' , // Changed from #/items/properties/Id
171
167
} ,
172
168
{
173
169
type : 'Control' ,
174
- scope : '#/properties/ProjectorMode' ,
170
+ scope : '#/properties/ProjectorMode' , // Changed from #/items/properties/ProjectorMode
175
171
} ,
176
172
] ,
177
173
} ,
@@ -190,7 +186,6 @@ const sceneConfigUiSchema = {
190
186
} ,
191
187
] ,
192
188
} ,
193
- // Scene Features
194
189
{
195
190
type : 'Group' ,
196
191
label : 'Scene Features' ,
@@ -231,7 +226,6 @@ const sceneConfigUiSchema = {
231
226
} ,
232
227
] ,
233
228
} ,
234
- // Layouts
235
229
{
236
230
type : 'Control' ,
237
231
scope : '#/properties/Layouts' ,
@@ -279,20 +273,22 @@ const sceneConfigUiSchema = {
279
273
280
274
interface SceneConfigurationSectionProps {
281
275
data : Scene [ ] ;
282
- onChange : ( event : { data : Scene [ ] ; errors ?: ValidationError [ ] } ) => void ;
276
+ onChange : ( event : {
277
+ data : Scene [ ] ; // Changed from { Scenes: Scene[] }
278
+ errors ?: ValidationError [ ] ;
279
+ } ) => void ;
283
280
}
284
281
285
282
export const SceneConfigurationSection : React . FC <
286
283
SceneConfigurationSectionProps
287
284
> = ( { data, onChange } ) => {
288
- // Validation helper for unique IDs
285
+ // Validate unique IDs, root scene, layouts, etc.
289
286
const validateUniqueIds = ( scenes : Scene [ ] ) : ValidationError [ ] => {
290
287
const errors : ValidationError [ ] = [ ] ;
291
288
const sceneIds = new Set < string > ( ) ;
292
289
const layoutIds = new Set < string > ( ) ;
293
290
294
291
scenes . forEach ( ( scene , sceneIndex ) => {
295
- // Check scene ID uniqueness
296
292
if ( scene . Id ) {
297
293
if ( sceneIds . has ( scene . Id ) ) {
298
294
errors . push ( {
@@ -303,7 +299,6 @@ export const SceneConfigurationSection: React.FC<
303
299
sceneIds . add ( scene . Id ) ;
304
300
}
305
301
306
- // Check layout ID uniqueness within scene
307
302
scene . Layouts ?. forEach ( ( layout , layoutIndex ) => {
308
303
if ( layout . Id ) {
309
304
if ( layoutIds . has ( layout . Id ) ) {
@@ -320,15 +315,12 @@ export const SceneConfigurationSection: React.FC<
320
315
return errors ;
321
316
} ;
322
317
323
- // Custom validation
324
- const validate = ( scenes : Scene [ ] ) : ValidationError [ ] => {
318
+ const validateScenes = ( scenes : Scene [ ] ) : ValidationError [ ] => {
325
319
const errors : ValidationError [ ] = [ ] ;
326
-
327
- // Add unique ID validation
328
320
errors . push ( ...validateUniqueIds ( scenes ) ) ;
329
321
330
- // Check for root scene
331
- const rootScenes = scenes . filter ( scene => scene . IsRoot ) ;
322
+ // Exactly one root scene required
323
+ const rootScenes = scenes . filter ( s => s . IsRoot ) ;
332
324
if ( rootScenes . length === 0 ) {
333
325
errors . push ( {
334
326
path : 'Scenes' ,
@@ -341,9 +333,8 @@ export const SceneConfigurationSection: React.FC<
341
333
} ) ;
342
334
}
343
335
344
- // Validate each scene
336
+ // Each scene must have at least one layout
345
337
scenes . forEach ( ( scene , index ) => {
346
- // Validate required layouts
347
338
if ( ! scene . Layouts || scene . Layouts . length === 0 ) {
348
339
errors . push ( {
349
340
path : `Scenes[${ index } ].Layouts` ,
@@ -366,24 +357,16 @@ export const SceneConfigurationSection: React.FC<
366
357
return errors ;
367
358
} ;
368
359
369
- const handleChange = ( event : {
370
- data : { Scenes : Scene [ ] } ;
371
- errors : any [ ] ;
372
- } ) => {
373
- const customErrors = validate ( event . data . Scenes ) ;
374
-
360
+ const handleChange = ( event : { data : any ; errors : any [ ] } ) => {
361
+ const customErrors = validateScenes ( event . data . Scenes ) ;
375
362
onChange ( {
376
363
data : event . data . Scenes ,
377
364
errors : [ ...( event . errors || [ ] ) , ...customErrors ] ,
378
365
} ) ;
379
366
} ;
380
367
381
- const formData = useMemo (
382
- ( ) => ( {
383
- Scenes : data || [ ] ,
384
- } ) ,
385
- [ data ] ,
386
- ) ;
368
+ // Provide the formData as { Scenes: [...] } since schema expects Scenes to be a property of an object
369
+ const formData = useMemo ( ( ) => ( { Scenes : data || [ ] } ) , [ data ] ) ;
387
370
388
371
return (
389
372
< div className = "space-y-6" >
@@ -392,7 +375,6 @@ export const SceneConfigurationSection: React.FC<
392
375
Scene Configuration
393
376
</ h2 >
394
377
395
- { /* Quick summary */ }
396
378
< Alert className = "mb-4" >
397
379
< AlertDescription >
398
380
{ `Current configuration: ${ data . length } scene${ data . length !== 1 ? 's' : '' } ` }
@@ -401,6 +383,10 @@ export const SceneConfigurationSection: React.FC<
401
383
</ AlertDescription >
402
384
</ Alert >
403
385
386
+ { /*
387
+ By using the updated scopes (#/items/properties/...) in the uischema,
388
+ JsonForms knows how to render the Scenes array and its items properly.
389
+ */ }
404
390
< JsonForms
405
391
schema = { sceneConfigSchema }
406
392
uischema = { sceneConfigUiSchema }
@@ -411,7 +397,6 @@ export const SceneConfigurationSection: React.FC<
411
397
/>
412
398
</ div >
413
399
414
- { /* Help Section */ }
415
400
< div className = "bg-white rounded-lg shadow p-6" >
416
401
< h3 className = "font-medium text-gray-900 mb-2" >
417
402
Configuration Guidelines
@@ -424,7 +409,7 @@ export const SceneConfigurationSection: React.FC<
424
409
< li > Background transparency must be between 0 and 1</ li >
425
410
< li >
426
411
ProjectorMode determines how content is displayed:
427
- < ul className = "ml-6 mt-1" >
412
+ < ul className = "ml-6 mt-1 list-disc " >
428
413
< li > Meet: Standard meeting view</ li >
429
414
< li > Split: Divided screen layout</ li >
430
415
< li > Focus: Emphasized content view</ li >
0 commit comments