Adapt to JSON schema in controlpi
authorBenjamin Braatz <bb@bbraatz.eu>
Mon, 8 Mar 2021 18:37:11 +0000 (19:37 +0100)
committerBenjamin Braatz <bb@bbraatz.eu>
Mon, 8 Mar 2021 18:37:11 +0000 (19:37 +0100)
conf.json
web/controlpi-debug.js

index e63585135b5c38250f133388e2c7435f051d4088..8e4c584a7040b69798b47ccf0f74cda57e82041a 100644 (file)
--- a/conf.json
+++ b/conf.json
@@ -13,9 +13,9 @@
     "Delay Start after On": {
         "plugin": "Alias",
         "from": {
-            "sender": "Example State",
-            "event": "changed",
-            "state": true
+            "sender": { "const": "Example State" },
+            "event": { "const": "changed" },
+            "state": { "const": true }
         },
         "to": {
             "target": "Waiter",
@@ -27,8 +27,8 @@
     "State Off after Delay": {
         "plugin": "Alias",
         "from": {
-            "sender": "Waiter",
-            "id": "off delay"
+            "sender": { "const": "Waiter" },
+            "id": { "const": "off delay" }
         },
         "to": {
             "target": "Example State",
index 110558318e969388766f9bf09d6ebf7c3d705674..5ae170a89a276dcb6f9d4d2f15ba1a662117b156 100644 (file)
@@ -33,19 +33,11 @@ function createForClient(client) {
     return section
 }
 
-// Create div and table for template or message:
-function createForMessage(message, isMessage) {
+// Create div and table for template:
+function createForTemplate(template) {
     const div = document.createElement('div')
     div.setAttribute('class', 'message')
-    if (isMessage) {
-        // Current (receive) time as heading:
-        const time = new Date().toLocaleTimeString()
-        const h4 = document.createElement('h4')
-        const h4Content = document.createTextNode(time)
-        h4.appendChild(h4Content)
-        div.appendChild(h4)
-    }
-    if (Object.keys(message).length === 0) {
+    if (Object.keys(template).length === 0) {
         // Create span with '*' for empty templates:
         const span = document.createElement('span')
         const spanContent = document.createTextNode('*')
@@ -53,21 +45,7 @@ function createForMessage(message, isMessage) {
         div.appendChild(span)
     } else {
         const table = document.createElement('table')
-        for (const key in message) {
-            if (isMessage) {
-                if (key == 'sender') {
-                    // Ignore 'sender' for last received messages
-                    // (information redundantly present in client heading):
-                    continue
-                } else if (key == 'state') {
-                    // Set background according to state:
-                    if (message[key]) {
-                        div.classList.add('green')
-                    } else {
-                        div.classList.add('red')
-                    }
-                }
-            }
+        for (const key in template) {
             // Append table row for key-value pair:
             const tr = document.createElement('tr')
             const keyTd = document.createElement('td')
@@ -75,10 +53,12 @@ function createForMessage(message, isMessage) {
             keyTd.appendChild(keyTdContent)
             tr.appendChild(keyTd)
             const valueTd = document.createElement('td')
-            value = JSON.stringify(message[key])
-            if (value.startsWith('"<class') && value.endsWith('>"')) {
-                // Remove quotes if class type instead of literal value:
-                value = value.replace(/^"|"$/g, '')
+            schema = template[key]
+            value = ''
+            if ('const' in schema) {
+                value = JSON.stringify(schema['const'])
+            } else {
+                value = JSON.stringify(schema)
             }
             const valueTdContent = document.createTextNode(value)
             valueTd.appendChild(valueTdContent)
@@ -110,13 +90,14 @@ function resizeInput() {
 }
 
 // Create form input (or select) for key-value pairs in receive templates:
-function inputsForKeyValue(key, value) {
+function inputsForKeyValue(key, schema) {
     result = []
-    literal = true
-    if (value.match(/^<class '(str|int|float|bool)'>$/g)) {
-        literal = false
+    literal = false
+    if ('const' in schema) {
+        literal = true
     }
-    if (value == '<class \'bool\'>' || typeof(value) == 'boolean') {
+    if (schema['type'] == 'boolean' ||
+        (literal && typeof(schema['const']) == 'boolean')) {
         // Create select with true and false options for Boolean:
         const select = document.createElement('select')
         select.setAttribute('name', key)
@@ -132,7 +113,7 @@ function inputsForKeyValue(key, value) {
         if (literal) {
             // Select set value and disable other value
             // for literal Boolean:
-            if (value) {
+            if (schema['const']) {
                 optionTrue.setAttribute('selected', '')
                 optioniFalse.setAttribute('disabled', '')
             } else {
@@ -144,8 +125,9 @@ function inputsForKeyValue(key, value) {
         result.push(select)
     } else {
         // Create input for everything except Booleans:
-        if (value == '<class \'str\'>' ||
-            (literal && typeof(value) == 'string' && key != 'command')) {
+        if (schema['type'] == 'string' ||
+            (literal && typeof(schema['const']) == 'string' &&
+             key != 'command')) {
             // Quote strings:
             const openquote = document.createTextNode('"')
             result.push(openquote)
@@ -154,24 +136,26 @@ function inputsForKeyValue(key, value) {
         // Set type of input:
         if (key == 'command') {
             input.setAttribute('type', 'hidden')
-        } else if (value == '<class \'int\'>' || value == '<class \'float\'>' ||
-                   typeof(value) == 'number') {
+        } else if (schema['type'] == 'integer' ||
+                   schema['type'] == 'number' ||
+                   typeof(schema['const']) == 'number') {
             input.setAttribute('type', 'number')
-            if (value == '<class \'int\'>') {
+            if (schema['type'] == 'integer') {
                 input.setAttribute('step', '1')
-            } else if (value == '<class \'float\'>') {
+            } else if (schema['type'] == 'number') {
                 input.setAttribute('step', 'any')
             }
-        } else if (value == '<class \'str\'>' || typeof(value) == 'string') {
+        } else if (schema['type'] == 'string' ||
+                   typeof(schema['const']) == 'string') {
             input.setAttribute('type', 'text')
         }
         // Set key as name of input:
         input.setAttribute('name', key)
         // Set value of input, readonly or required:
         if (key == 'command') {
-            input.setAttribute('value', value)
+            input.setAttribute('value', schema['const'])
         } else if (literal) {
-            input.setAttribute('value', value)
+            input.setAttribute('value', schema['const'])
             input.setAttribute('readonly', '')
         } else {
             input.setAttribute('value', '')
@@ -183,8 +167,9 @@ function inputsForKeyValue(key, value) {
             resizeInput.call(input)
         }
         result.push(input)
-        if (value == '<class \'str\'>' ||
-            (literal && typeof(value) == 'string' && key != 'command')) {
+        if (schema['type'] == 'string' ||
+            (literal && typeof(schema['const']) == 'string' &&
+             key != 'command')) {
             // Quote strings:
             const closequote = document.createTextNode('"')
             result.push(closequote)
@@ -193,7 +178,7 @@ function inputsForKeyValue(key, value) {
             // Add submit button for 'command' key:
             const submit = document.createElement('input')
             submit.setAttribute('type', 'submit')
-            submit.setAttribute('value', value)
+            submit.setAttribute('value', schema['const'])
             result.push(submit)
         }
     }
@@ -250,7 +235,6 @@ function createForCommand(template) {
 // Remove (if unregistered) or create (if not existent) elements for
 // clients and update interface information:
 function processBusMessage(message) {
-    // When message is from bus:
     if (message['event'] == 'unregistered') {
         // On deregistration delete client element if it exists:
         const clientElement = document.getElementById(message['client'])
@@ -268,20 +252,61 @@ function processBusMessage(message) {
         // Crate message elements for receives interface:
         const receiveContainer = document.getElementById(message['client'] + ' Receives')
         receiveContainer.innerHTML = ''
-        for (const template of message.receives) {
+        for (const template of message['receives']) {
             if (template['command'] != null) {
                 receiveContainer.appendChild(createForCommand(template))
             } else {
-                receiveContainer.appendChild(createForMessage(template))
+                receiveContainer.appendChild(createForTemplate(template))
             }
         }
         // Create message elements for sends interface:
         const sendContainer = document.getElementById(message['client'] + ' Sends')
         sendContainer.innerHTML = ''
-        for (const template of message.sends) {
-            sendContainer.appendChild(createForMessage(template))
+        for (const template of message['sends']) {
+            sendContainer.appendChild(createForTemplate(template))
+        }
+    }
+}
+
+// Create div and table for message:
+function createForMessage(message) {
+    const div = document.createElement('div')
+    div.setAttribute('class', 'message')
+    // Current (receive) time as heading:
+    const time = new Date().toLocaleTimeString()
+    const h4 = document.createElement('h4')
+    const h4Content = document.createTextNode(time)
+    h4.appendChild(h4Content)
+    div.appendChild(h4)
+    const table = document.createElement('table')
+    for (const key in message) {
+        if (key == 'sender') {
+            // Ignore 'sender' for last received messages
+            // (information redundantly present in client heading):
+            continue
+        } else if (key == 'state') {
+            // Set background according to state:
+            if (message[key] === true) {
+                div.classList.add('green')
+            } else if (message[key] === false) {
+                div.classList.add('red')
+            }
         }
+        // Append table row for key-value pair:
+        const tr = document.createElement('tr')
+        const keyTd = document.createElement('td')
+        const keyTdContent = document.createTextNode(key + ':')
+        keyTd.appendChild(keyTdContent)
+        tr.appendChild(keyTd)
+        const valueTd = document.createElement('td')
+        value = JSON.stringify(message[key])
+        const valueTdContent = document.createTextNode(value)
+        valueTd.appendChild(valueTdContent)
+        tr.appendChild(valueTd)
+        table.appendChild(tr)
     }
+    div.appendChild(table)
+    return div
 }
 
 // Create element for client (if not existent)
@@ -296,7 +321,7 @@ function processClientMessage(message) {
     // Update last received message:
     const lastContainer = document.getElementById(message['sender'] + ' Last')
     lastContainer.innerHTML = ''
-    lastContainer.appendChild(createForMessage(message, true))
+    lastContainer.appendChild(createForMessage(message))
 }
 
 // Open Websocket back to ControlPi we were loaded from: