195195 <f7-tab id =" code" :tab-active =" currentTab === 'code'" >
196196 <f7-icon v-if =" !editable" f7 =" lock" class =" float-right margin"
197197 style =" opacity :0.5 ; z-index : 4000 ; user-select : none ;" size =" 50" color =" gray" :tooltip =" notEditableMsg" />
198- <editor v-if =" ready" class =" thing-code-editor" mode =" application/vnd.openhab.thing+yaml " :value =" thingYaml "
198+ <editor v-if =" ready" class =" thing-code-editor" : mode =" editorMode " :value =" thingCode "
199199 :hint-context =" { thingType: thingType, channelTypes: channelTypes }" @input =" onEditorInput"
200200 :read-only =" !editable" />
201201 <!-- <pre class="yaml-message padding-horizontal" :class="[yamlError === 'OK' ? 'text-color-green' : 'text-color-red']">{{yamlError}}</pre> -->
202202 </f7-tab >
203203 </f7-tabs >
204+ <f7-toolbar bottom v-if =" currentTab === 'code'" >
205+ <f7-segmented tag =" div" >
206+ <f7-button outline small :active =" codeType === 'YAML'" class =" no-ripple" style =" width : 5em ;" @click =" switchCodeType('YAML')" >
207+ YAML
208+ </f7-button >
209+ <f7-button outline small :active =" codeType === 'DSL'" class =" no-ripple" style =" width : 5em ;" @click =" switchCodeType('DSL')" >
210+ DSL
211+ </f7-button >
212+ </f7-segmented >
213+ </f7-toolbar >
204214 </f7-page >
205215</template >
206216
@@ -252,7 +262,7 @@ p.action-description
252262 .thing-code-editor.vue-codemirror
253263 display block
254264 top calc (var (-- f7-navbar-height ) + var (-- f7-tabbar-height ))
255- height calc (100% - 2 * var (-- f7-navbar-height ))
265+ height calc (100% - 2 * var (-- f7-navbar-height ) - var ( -- f7-toolbar-height ) )
256266 width 100%
257267
258268 .item-title-content , .item-after-content
@@ -317,6 +327,9 @@ export default {
317327 ' editor ' : () => import (/* webpackChunkName: "script-editor" */ ' @/components/config/controls/script-editor.vue' )
318328 },
319329 props: [' thingId' ],
330+ created () {
331+ this .ThingMediaType = {YAML : this .MediaType .YAML , DSL : this .MediaType .THING_DSL }
332+ },
320333 data () {
321334 return {
322335 ready: false ,
@@ -339,7 +352,9 @@ export default {
339352 configActionsByGroup: [],
340353 thingEnabled: true ,
341354 eventSource: null ,
342- thingYaml: null ,
355+ codeType: localStorage .getItem (' openhab.ui:codeViewer.type' ) || ' YAML' ,
356+ thingCode: null ,
357+ originalCode: null ,
343358 notEditableMsg: ' This Thing is not editable because it has been provisioned from a file.' ,
344359 propertyTruncation: {}
345360 }
@@ -348,6 +363,12 @@ export default {
348363 editable () {
349364 return this .thing && this .thing .editable
350365 },
366+ editorMode () {
367+ if (this .codeType === ' DSL' ) {
368+ return ' text/x-java'
369+ }
370+ return ' application/vnd.openhab.thing+yaml'
371+ },
351372 pageTitle () {
352373 if (! this .ready ) return ' '
353374 return this .thing .label || this .thing .UID
@@ -422,19 +443,19 @@ export default {
422443 }
423444 },
424445 onEditorInput (value ) {
425- this .thingYaml = value
446+ this .thingCode = value
447+ this .dirty = this .configDirty || this .thingDirty || this .originalCode !== this .thingCode
426448 },
427449 switchTab (tab ) {
428450 if (this .currentTab === tab) return
429451 if (this .currentTab === ' code' ) {
430- const previousYaml = this .toYaml ()
431- if (this .thingYaml !== previousYaml && this .fromYaml ()) {
432- this .save ()
452+ if (this .originalCode !== this .thingCode ) {
453+ this .fromCode ()
433454 }
434455 }
435456 this .currentTab = tab
436457 if (this .currentTab === ' code' ) {
437- this .thingYaml = this .toYaml ()
458+ this .toCode ( this .codeType )
438459 }
439460 },
440461 /**
@@ -539,13 +560,12 @@ export default {
539560 }
540561 })
541562 },
542- save (saveThing ) {
563+ save (checkCode = true ) {
543564 if (! this .ready || ! this .editable ) return
544565
545- if (this .currentTab === ' code' ) {
546- if (! this .fromYaml ()) {
547- return
548- }
566+ if (checkCode && this .currentTab === ' code' ) {
567+ this .fromCode (() => this .save (false ))
568+ return
549569 }
550570
551571 let endpoint, payload, successMessage
@@ -771,7 +791,7 @@ export default {
771791 })
772792 },
773793 onChannelsUpdated (save ) {
774- if (save) this .save (true )
794+ if (save) this .save ()
775795 if (! this .eventSource ) this .startEventSource ()
776796 },
777797 unlinkAll (removeItems ) {
@@ -858,37 +878,69 @@ export default {
858878 this .$oh .sse .close (this .eventSource )
859879 this .eventSource = null
860880 },
861- toYaml () {
862- const editableThing = {
863- UID : this .thing .UID ,
864- label: this .thing .label ,
865- thingTypeUID: this .thing .thingTypeUID ,
866- configuration: this .thing .configuration
881+ switchCodeType (type ) {
882+ if (this .codeType === type) return
883+ if (this .editable ) {
884+ this .fromCode (() => {
885+ this .toCode (type, () => {
886+ localStorage .setItem (' openhab.ui:codeViewer.type' , type)
887+ this .codeType = type
888+ })
889+ })
890+ } else {
891+ this .toCode (type, () => {
892+ localStorage .setItem (' openhab.ui:codeViewer.type' , type)
893+ this .codeType = type
894+ })
867895 }
868-
869- if (this .thing .bridgeUID ) editableThing .bridgeUID = this .thing .bridgeUID
870- if (this .thing .location ) editableThing .location = this .thing .location
871-
872- const editableChannels = []
873-
874- for (const channel of this .thing .channels ) {
875- const editableChannel = {
876- id: channel .id ,
877- channelTypeUID: channel .channelTypeUID ,
878- label: channel .label ,
879- description: channel .description ,
880- configuration: channel .configuration
881- }
882- editableChannels .push (editableChannel)
896+ },
897+ toCode (codeType , successCallback ) {
898+ const mediaType = this .ThingMediaType [codeType]
899+ console .log (' toCode' , mediaType)
900+ const payload = { things: [this .thing ] }
901+ this .$oh .api .postPlain (' /rest/file-format/create' , JSON .stringify (payload), null , ' application/json' , { accept: mediaType })
902+ .then ((code ) => {
903+ if (codeType === ' YAML' ) {
904+ // skip version:, things: and UID: lines, and unindent lines
905+ code = code .split (' \n ' ).slice (3 ).map (line => line .replace (/ ^ \s {4} / , ' ' )).join (' \n ' )
906+ }
907+ this .thingCode = code
908+ this .originalCode = cloneDeep (code)
909+ if (successCallback) {
910+ successCallback ()
911+ }
912+ })
913+ .catch ((err ) => {
914+ this .$f7 .dialog .alert (` Error creating ${ codeType} : ${ err} ` ).open ()
915+ })
916+ },
917+ fromCode (successCallback ) {
918+ const mediaType = this .ThingMediaType [this .codeType ]
919+ let payload = null
920+ if (this .codeType === ' YAML' ) {
921+ const indentedCode = this .thingCode .split (' \n ' ).map (line => ' ' .repeat (4 ) + line).join (' \n ' )
922+ payload = ` version: 2\n things:\n ${ this .thing .UID } :\n ${ indentedCode} `
923+ } else {
924+ payload = this .thingCode
883925 }
884-
885- if (editableChannels .length > 0 ) editableThing .channels = editableChannels
886-
887- return YAML .stringify (editableThing)
926+ this .$oh .api .postPlain (' /rest/file-format/parse' , payload, null , mediaType, { accept: ' application/json' })
927+ .then ((data ) => {
928+ data = JSON .parse (data)
929+ if (data .things && data .things .length > 0 ) {
930+ const updatedThing = data .things [0 ]
931+ this .updateThing (updatedThing)
932+ if (successCallback) {
933+ successCallback ()
934+ }
935+ } else {
936+ this .$f7 .dialog .alert (' Error parsing ' + this .codeType + ' : no things found' ).open ()
937+ }
938+ })
939+ .catch ((err ) => {
940+ this .$f7 .dialog .alert (` Error parsing ${ this .codeType } : ${ err} ` ).open ()
941+ })
888942 },
889- fromYaml () {
890- const updatedThing = YAML .parse (this .thingYaml )
891-
943+ updateThing (updatedThing ) {
892944 const isExtensible = (channel , thingType ) => {
893945 if (! channel || ! channel .channelTypeUID ) return false
894946 const bindingId = thingType .UID .split (' :' )[0 ]
0 commit comments