From 6f81c0a6c665008d9c9014772152828a5f4da853 Mon Sep 17 00:00:00 2001 From: Yannick Schaus Date: Tue, 8 Dec 2020 17:40:25 +0100 Subject: [PATCH] Add Items from Thing: Expert Mode (#603) This adds a new "expert mode" to the "Create Equipment from Thing"/"Add Equipment to Model"/ "Create Points from Thing"/"Add Points to Model" Instead of clicking through the channels and filling out items, a textual definition will be generated and put it the "Add Items from Textual Definition" page. That way, the expert user can add their items by editing text with the well-known syntax. Signed-off-by: Yannick Schaus --- .../web/src/components/thing/channel-list.vue | 2 +- .../items-add-from-textual-definition.vue | 3 +- .../pages/settings/model/add-from-thing.vue | 27 ++++++- .../model/generate-textual-definition.js | 74 +++++++++++++++++++ 4 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 bundles/org.openhab.ui/web/src/pages/settings/model/generate-textual-definition.js diff --git a/bundles/org.openhab.ui/web/src/components/thing/channel-list.vue b/bundles/org.openhab.ui/web/src/components/thing/channel-list.vue index de31f380a..b5ed1f980 100644 --- a/bundles/org.openhab.ui/web/src/components/thing/channel-list.vue +++ b/bundles/org.openhab.ui/web/src/components/thing/channel-list.vue @@ -93,7 +93,7 @@ import ChannelGroup from './channel-group.vue' import ChannelLink from './channel-link.vue' import ItemForm from '@/components/item/item-form.vue' -import Points from '@/assets/semantics' +import { Points } from '@/assets/semantics' export default { props: ['thingType', 'thing', 'channelTypes', 'pickerMode', 'multipleLinksMode', 'itemTypeFilter', 'newItemsPrefix', 'newItems', 'context'], diff --git a/bundles/org.openhab.ui/web/src/pages/settings/items/parser/items-add-from-textual-definition.vue b/bundles/org.openhab.ui/web/src/pages/settings/items/parser/items-add-from-textual-definition.vue index ac57b6dad..e3efe534d 100644 --- a/bundles/org.openhab.ui/web/src/pages/settings/items/parser/items-add-from-textual-definition.vue +++ b/bundles/org.openhab.ui/web/src/pages/settings/items/parser/items-add-from-textual-definition.vue @@ -112,9 +112,10 @@ export default { components: { 'editor': () => import('@/components/config/controls/script-editor.vue') }, + props: ['textualDefinition'], data () { return { - itemsDsl: '', + itemsDsl: this.textualDefinition || '', items: [], things: [], links: [], diff --git a/bundles/org.openhab.ui/web/src/pages/settings/model/add-from-thing.vue b/bundles/org.openhab.ui/web/src/pages/settings/model/add-from-thing.vue index 38e4975ed..eb6794012 100644 --- a/bundles/org.openhab.ui/web/src/pages/settings/model/add-from-thing.vue +++ b/bundles/org.openhab.ui/web/src/pages/settings/model/add-from-thing.vue @@ -62,6 +62,7 @@ You can alter the suggested names and labels as well as the semantic class and related property.

The newly created Points will be linked to their respective channels with the default profile (you will be able to configure the links individually later if needed). + Expert Mode { + const channelTypesMap = new Map(channelTypes.map(ct => [ct.UID, ct])) + + let def = '' + if (newEquipmentItem && newEquipmentItem.name) { + def += `// Equipment representing thing:\n// ${thing.UID}\n` + def += `// (${thing.label})\n\n` + + def += `Group ${newEquipmentItem.name} "${newEquipmentItem.label}" ` + if (newEquipmentItem.category) def += `<${newEquipmentItem.category}> ` + if (parentGroupsForEquipment.length) def += `(${parentGroupsForEquipment.join(', ')}) ` + if (newEquipmentItem.tags.length) def += `[${newEquipmentItem.tags.map((t) => `"${t}"`).join(', ')}] ` + def = def.trim() + '\n\n' + } + + let lines = [] + for (const channel of thing.channels) { + if (channel.kind !== 'STATE') continue + const channelType = channelTypesMap.get(channel.channelTypeUID) + let newItemName = (newEquipmentItem) ? newEquipmentItem.name : diacritic.clean(thing.label).replace(/[^0-9a-z]/gi, '') + newItemName += '_' + let suffix = channel.label || channel.id + if (thing.channels.filter((c) => c.label === suffix).length > 1) { + suffix = channel.id.replace('#', '_') + } + newItemName += diacritic.clean(suffix).replace(/[^0-9a-z_]/gi, '') + const defaultTags = (channel.defaultTags.length > 0) ? channel.defaultTags : channelType.tags + const newItem = { + channel: channel, + channelType: channelType, + name: newItemName, + label: channel.label || channelType.label, + groupNames: parentGroupsForPoints, + category: (channelType) ? channelType.category : '', + type: channel.itemType, + tags: (defaultTags.find((t) => Points.indexOf(t) >= 0)) ? defaultTags : [...defaultTags, 'Point'] + } + + let line = [] + line.push(newItem.type) + line.push(newItem.name) + line.push(`"${newItem.label}"`) + if (channelType.advanced) line[0] = '// ' + line[0] // comment the advanced channels by default + line.push((newItem.category) ? `<${newItem.category}>` : '') + line.push((newItem.groupNames.length) ? `(${newItem.groupNames.join(', ')})` : '') + line.push((newItem.tags.length) ? `[${newItem.tags.map((t) => `"${t}"`).join(', ')}] ` : '') + line.push(`{ channel="${channel.uid}" }`) + lines.push(line) + } + + if (!lines.length) return def + + let columnsWidths = [] + for (let c = 0; c < lines[0].length; c++) { + columnsWidths.push(Math.max(...lines.map((l) => l[c].length)) + 1) + } + + def += '// Points:\n\n' + lines.forEach((l) => { + for (let c = 0; c < l.length; c++) { + def += l[c] + ' '.repeat(columnsWidths[c] - l[c].length) + } + def += '\n' + }) + + return def +}