From 21b411d93c50c8ce8eb6f56973209bb78881bada Mon Sep 17 00:00:00 2001 From: Benjamin Braatz Date: Mon, 8 Mar 2021 19:37:11 +0100 Subject: [PATCH] Adapt to JSON schema in controlpi --- conf.json | 10 ++-- web/controlpi-debug.js | 133 ++++++++++++++++++++++++----------------- 2 files changed, 84 insertions(+), 59 deletions(-) diff --git a/conf.json b/conf.json index e635851..8e4c584 100644 --- 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", diff --git a/web/controlpi-debug.js b/web/controlpi-debug.js index 1105583..5ae170a 100644 --- a/web/controlpi-debug.js +++ b/web/controlpi-debug.js @@ -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('""')) { - // 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(/^$/g)) { - literal = false + literal = false + if ('const' in schema) { + literal = true } - if (value == '' || 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 == '' || - (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 == '' || value == '' || - typeof(value) == 'number') { + } else if (schema['type'] == 'integer' || + schema['type'] == 'number' || + typeof(schema['const']) == 'number') { input.setAttribute('type', 'number') - if (value == '') { + if (schema['type'] == 'integer') { input.setAttribute('step', '1') - } else if (value == '') { + } else if (schema['type'] == 'number') { input.setAttribute('step', 'any') } - } else if (value == '' || 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 == '' || - (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: -- 2.34.1