@@ -33,6 +33,7 @@ import { OnboardData } from "@/types/onboard-form";
3333import { Asset } from "@/types/asset-types" ;
3434import YAML from 'yaml' ;
3535import { getAssetById , getRawAssetById } from "@/utility/asset" ;
36+ import SpecEditor , { OpcUaSpec , MqttSpec , SpecItem } from "./spec-editor" ;
3637
3738type OnboardDataKey = keyof OnboardData ;
3839
@@ -161,6 +162,8 @@ const OnboardForm: React.FC<OnboardFormProps> = ({
161162} ) => {
162163 const [ assetData , setAssetData ] = useState < Asset | null > ( null ) ;
163164 const [ showSecondaryConfig , setShowSecondaryConfig ] = useState ( false ) ;
165+ const [ specItems , setSpecItems ] = useState < SpecItem [ ] > ( [ ] ) ;
166+ const [ secondarySpecItems , setSecondarySpecItems ] = useState < SpecItem [ ] > ( [ ] ) ;
164167
165168
166169
@@ -183,18 +186,14 @@ const OnboardForm: React.FC<OnboardFormProps> = ({
183186 const mqttSpecs = extractMqttSpecs ( rawAssetData ) ;
184187
185188 if ( protocol === "opc-ua" ) {
186- // Primary: OPC-UA binding points (with placeholder if none)
187- appConfig = buildOpcUaConfigTemplate ( opcUaSpecs ) ;
188- // Secondary: any parameters using MQTT-style binding points
189+ setSpecItems ( opcUaSpecs ) ;
189190 if ( mqttSpecs . length > 0 ) {
190- secondaryAppConfig = buildMqttConfigTemplate ( mqttSpecs ) ;
191+ setSecondarySpecItems ( mqttSpecs ) ;
191192 }
192193 } else {
193- // Primary: MQTT binding points (with placeholder if none)
194- appConfig = buildMqttConfigTemplate ( mqttSpecs ) ;
195- // Secondary: any parameters using OPC-UA-style binding points
194+ setSpecItems ( mqttSpecs ) ;
196195 if ( opcUaSpecs . length > 0 ) {
197- secondaryAppConfig = buildOpcUaConfigTemplate ( opcUaSpecs ) ;
196+ setSecondarySpecItems ( opcUaSpecs ) ;
198197 }
199198 }
200199 }
@@ -212,8 +211,6 @@ const OnboardForm: React.FC<OnboardFormProps> = ({
212211 pod_name : podName ,
213212 device_id : assetDataFromScorio ?. id ,
214213 gateway_id : assetDataFromScorio ?. id ,
215- app_config : appConfig ,
216- secondary_app_config : secondaryAppConfig
217214 } ) ) ;
218215 } catch ( error ) {
219216 console . error ( "Failed to fetch asset data:" , error ) ;
@@ -343,10 +340,10 @@ const OnboardForm: React.FC<OnboardFormProps> = ({
343340 }
344341 break ;
345342 case 1 : // Configuration
346- if ( ! onboardForm . app_config || ! onboardForm . pod_name ) {
343+ if ( specItems . length === 0 || ! onboardForm . pod_name ) {
347344 setValidateInput ( prev => ( {
348345 ...prev ,
349- app_config : ! onboardForm . app_config
346+ app_config : specItems . length === 0
350347 } ) ) ;
351348 isValid = false ;
352349 }
@@ -402,7 +399,6 @@ const OnboardForm: React.FC<OnboardFormProps> = ({
402399 const {
403400 ip_address,
404401 protocol,
405- app_config,
406402 pod_name,
407403 pdt_mqtt_hostname,
408404 pdt_mqtt_port,
@@ -425,7 +421,7 @@ const OnboardForm: React.FC<OnboardFormProps> = ({
425421
426422
427423 if ( ip_address === undefined || ip_address === "" ||
428- app_config === undefined || app_config === "" ||
424+ specItems . length === 0 ||
429425 protocol === undefined || protocol === "" ||
430426 pdt_mqtt_hostname === undefined || pdt_mqtt_hostname === "" ||
431427 pdt_mqtt_port === undefined || pdt_mqtt_port === 0 ||
@@ -439,27 +435,17 @@ const OnboardForm: React.FC<OnboardFormProps> = ({
439435 showToast ( 'error' , "Error" , "Please fill all required fields" )
440436 } else {
441437
442- // Check if app_config is not empty and is valid YAML
443- try {
444- parsedConfig = YAML . parse ( onboardForm . app_config ) ;
445- } catch ( error ) {
446- console . error ( "Invalid YAML in app_config" ) ;
447- showToast ( 'error' , 'Error' , 'Invalid YAML in app_config' ) ;
448- setValidateInput ( validate => ( { ...validate , app_config : true } ) )
449- }
438+ // Build config objects from spec editor items
439+ parsedConfig = onboardForm . protocol === "opc-ua"
440+ ? { fusionopcuadataservice : { specification : specItems } }
441+ : { fusionmqttdataservice : { specification : specItems } } ;
450442
451443 let parsedSecondaryConfig : Record < string , any > | undefined = undefined ;
452- if ( showSecondaryConfig && onboardForm . secondary_app_config ) {
453- try {
454- parsedSecondaryConfig = YAML . parse ( onboardForm . secondary_app_config ) ;
455- if ( typeof parsedSecondaryConfig !== "object" ) {
456- parsedSecondaryConfig = undefined ;
457- showToast ( 'error' , 'Error' , 'Invalid YAML in secondary configuration' ) ;
458- }
459- } catch ( error ) {
460- console . error ( "Invalid YAML in secondary_app_config" ) ;
461- showToast ( 'error' , 'Error' , 'Invalid YAML in secondary configuration' ) ;
462- }
444+ if ( showSecondaryConfig && secondarySpecItems . length > 0 ) {
445+ const secondaryProtocol = onboardForm . protocol === "opc-ua" ? "mqtt" : "opc-ua" ;
446+ parsedSecondaryConfig = secondaryProtocol === "opc-ua"
447+ ? { fusionopcuadataservice : { specification : secondarySpecItems } }
448+ : { fusionmqttdataservice : { specification : secondarySpecItems } } ;
463449 }
464450
465451 if ( typeof parsedConfig === "object" ) {
@@ -663,30 +649,17 @@ const OnboardForm: React.FC<OnboardFormProps> = ({
663649 { t ( "dashboard:app_config" ) } < span className = "text-red-500" > *</ span >
664650 </ label >
665651 < small className = "block mb-2 text-gray-600" >
666- YAML configuration mapping machine data points (OPC-UA nodes or MQTT topics) to digital twin properties
652+ Define how machine data points ({ onboardForm . protocol === "opc-ua" ? " OPC-UA nodes" : " MQTT topics" } ) map to digital twin properties
667653 </ small >
668- < InputTextarea
669- id = "app_config"
670- value = { onboardForm . app_config }
671- rows = { 12 }
672- cols = { 30 }
673- onChange = { ( e ) => handleInputTextAreaChange ( e , "app_config" ) }
674- className = { `w-full font-mono ${ validateInput ?. app_config ? 'p-invalid' : '' } ` }
654+ < SpecEditor
655+ protocol = { ( onboardForm . protocol === "opc-ua" || onboardForm . protocol === "mqtt" ) ? onboardForm . protocol : "opc-ua" }
656+ items = { specItems }
657+ onChange = { setSpecItems }
658+ hasError = { validateInput . app_config }
675659 />
676660 { validateInput ?. app_config && (
677- < small className = "p-error" > Valid YAML configuration is required</ small >
661+ < small className = "p-error" > At least one data mapping is required</ small >
678662 ) }
679- < div className = "mt-2" >
680- < Button
681- type = "button"
682- label = "Prettify YAML"
683- icon = "pi pi-sparkles"
684- onClick = { prettifyYAML }
685- size = "small"
686- outlined
687- className = "prettify-btn"
688- />
689- </ div >
690663 </ div >
691664
692665 { ! showSecondaryConfig ? (
@@ -717,14 +690,16 @@ const OnboardForm: React.FC<OnboardFormProps> = ({
717690 icon = "pi pi-times"
718691 onClick = { ( ) => {
719692 setShowSecondaryConfig ( false ) ;
720- setOnboardForm ( prev => ( { ...prev , secondary_app_config : "" , secondary_ip_address : "" , secondary_dataservice_image_config : "" } ) ) ;
693+ setSecondarySpecItems ( [ ] ) ;
694+ setOnboardForm ( prev => ( { ...prev , secondary_ip_address : "" , secondary_dataservice_image_config : "" } ) ) ;
721695 } }
722696 size = "small"
723697 text
724698 severity = "danger"
725699 tooltip = "Remove secondary configuration"
726700 />
727701 </ div >
702+ < hr />
728703 < div className = "field mb-3" >
729704 < label htmlFor = "secondary_ip_address" className = "font-semibold" >
730705 Secondary Connection URL
@@ -757,24 +732,15 @@ const OnboardForm: React.FC<OnboardFormProps> = ({
757732 className = "w-full"
758733 />
759734 </ div >
760- < InputTextarea
761- id = "secondary_app_config"
762- rows = { 8 }
763- cols = { 30 }
764- onChange = { ( e ) => handleInputTextAreaChange ( e , "secondary_app_config" ) }
765- className = "w-full font-mono"
735+ < label className = "font-semibold block mb-1" > Data Mappings</ label >
736+ < small className = "block mb-2 text-gray-600" >
737+ Define { onboardForm . protocol === "opc-ua" ? "MQTT" : "OPC-UA" } data mappings for the secondary configuration
738+ </ small >
739+ < SpecEditor
740+ protocol = { onboardForm . protocol === "opc-ua" ? "mqtt" : "opc-ua" }
741+ items = { secondarySpecItems }
742+ onChange = { setSecondarySpecItems }
766743 />
767- < div className = "mt-2" >
768- < Button
769- type = "button"
770- label = "Prettify YAML"
771- icon = "pi pi-sparkles"
772- onClick = { prettifySecondaryYAML }
773- size = "small"
774- outlined
775- className = "prettify-btn"
776- />
777- </ div >
778744 </ div >
779745 ) }
780746 </ div >
0 commit comments