Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update widget expression capabilities #1522

Merged
merged 19 commits into from
Oct 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
9287f87
Add advanced widget expression features
JustinGeorgi Oct 9, 2022
1770772
Resolve screen context conflict
JustinGeorgi Oct 9, 2022
e68ead8
Fix config sheet & parameter group padding (#1501)
ghys Oct 5, 2022
0108914
Monitor SSE Connection Health (#1499)
digitaldan Oct 7, 2022
36863fb
Add missing sitemap attributes (#1487)
mherwege Oct 8, 2022
76627c5
Thing "actions" config param handling made generic (#1498)
mbronk Oct 8, 2022
b61953e
Bump css-what from 2.1.2 to 2.1.3 in /bundles/org.openhab.ui/web (#1508)
dependabot[bot] Oct 8, 2022
807c5fc
Bump terser from 4.8.0 to 4.8.1 in /bundles/org.openhab.ui/web (#1457)
dependabot[bot] Oct 8, 2022
f7772f2
[MainUI] Evaluate expressions in configuration Arrays & Update `actio…
florian-h05 Oct 9, 2022
61e2ea9
Access screen info in expressions context (#1510)
florian-h05 Oct 9, 2022
f35320b
New Crowdin updates (#1442)
openhab-bot Oct 9, 2022
8cd6232
Merge branch 'main' into jgeorgi-widget-patch
JustinGeorgi Oct 9, 2022
ba7978e
Fix linting error
JustinGeorgi Oct 9, 2022
5023df2
Merge branch 'jgeorgi-widget-patch' of https://github.com/JustinGeorg…
JustinGeorgi Oct 9, 2022
f0fc942
Full user info in widget context and update "@" op
JustinGeorgi Oct 10, 2022
b05be44
Added ht- components to directly render html tags
JustinGeorgi Oct 10, 2022
99c1514
Remove ht tag prefix and add autocomplete for @Op
JustinGeorgi Oct 11, 2022
2ff5472
Fix linting errors
JustinGeorgi Oct 11, 2022
cb5eee7
Update bundles/org.openhab.ui/web/src/components/widgets/generic-widg…
JustinGeorgi Oct 11, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 96 additions & 24 deletions bundles/org.openhab.ui/web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion bundles/org.openhab.ui/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,21 @@
"dependencies": {
"@blockly/field-slider": "^2.1.10",
"@blockly/zoom-to-fit": "^2.0.24",
"@jsep-plugin/arrow": "^1.0.5",
"@jsep-plugin/object": "^1.2.1",
"@jsep-plugin/regex": "^1.0.3",
"@jsep-plugin/template": "^1.0.2",
"blockly": "^6.20210701.0",
"cronstrue": "^1.100.0",
"dayjs": "^1.9.6",
"dom7": "^2.1.5",
"echarts": "^5.1.2",
"event-source-polyfill": "^1.0.22",
"expression-eval": "^2.1.0",
"fast-deep-equal": "^3.1.3",
"framework7": "^5.7.12",
"framework7-icons": "^3.0.1",
"framework7-vue": "^5.7.12",
"jse-eval": "^1.5.1",
"jssip": "^3.9.1",
"leaflet": "^1.7.1",
"leaflet-providers": "^1.11.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

<script>
import { findEquipment, allEquipmentPoints, findPoints } from '../glance-helpers'
import expr from 'expression-eval'
import expr from 'jse-eval'

export default {
props: ['element', 'type', 'badgeOverrides', 'invertColor', 'store'],
Expand Down Expand Up @@ -187,7 +187,7 @@ export default {
reduce () {
const ast = this.overrideExpression()
if (ast) {
return this.map.filter((state) => expr.eval(ast, { state: state, Number: Number })).length
return this.map.filter((state) => expr.evaluate(ast, { state: state, Number: Number })).length
}
switch (this.type) {
case 'blinds':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,8 @@ export default {
'Ctrl-Space': 'autocomplete',
'\'.\'': autocomplete,
'\'=\'': autocomplete,
'Space': autocomplete
'Space': autocomplete,
'\'@\'': autocomplete
}
cm.state.$oh = this.$oh
cm.state.originalMode = this.mode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ function getWidgetDefinitions (cm) {
}
}

function hintItems (cm, line, replaceAfterColon, addStatePropertySuffix) {
function hintItems (cm, line, replaceAfterColon, addStatePropertySuffix, addQuotes) {
const cursor = cm.getCursor()
const promise = (itemsCache) ? Promise.resolve(itemsCache) : cm.state.$oh.api.get('/rest/items')
return promise.then((data) => {
if (!itemsCache) itemsCache = data
let ret = {
list: data.map((item) => {
return {
text: item.name + ((addStatePropertySuffix ? '.state' : '')),
text: (addQuotes ? '\'' : '') + item.name + ((addStatePropertySuffix ? '.state' : '')) + (addQuotes ? '\'' : ''),
displayText: item.name,
description: `${(item.label) ? item.label + ' ' : ''}(${item.type})<br />${item.state}`
}
Expand All @@ -69,6 +69,9 @@ function hintItems (cm, line, replaceAfterColon, addStatePropertySuffix) {
const colonPos = line.indexOf(':')
ret.from = { line: cursor.line, ch: colonPos + 2 }
ret.to = { line: cursor.line, ch: line.length }
} else if (addQuotes) {
const lastAtOp = line.substring(0, cursor.ch).replace(/@[A-Za-z0-9_-]*$/, '@')
ret.to = { line: cursor.line, ch: lastAtOp.length }
} else {
const lastDot = line.substring(0, cursor.ch).replace(/\.[A-Za-z0-9_-]*$/, '.')
ret.to = { line: cursor.line, ch: lastDot.length }
Expand Down Expand Up @@ -110,11 +113,16 @@ function hintExpression (cm, line) {
{ text: 'theme', displayText: 'theme', description: 'The current theme: aurora, ios, or md' },
{ text: 'themeOptions', displayText: 'themeOptions', description: 'Object with current theme options' },
{ text: 'device', displayText: 'device', description: 'Object with information about the current device & browser' },
{ text: 'user', displayText: 'user', description: 'Access the username and roles of the logged in user' },
{ text: 'screen', displayText: 'screen', description: 'Object with information about the screen and available view area' },
{ text: 'dayjs', displayText: 'dayjs', description: 'Access to the Day.js object for date manipulation & formatting' }
]
}
} else {
const lastAtOp = line.substring(0, cursor.ch).replace(/@[A-Za-z0-9_-]*$/, '@')
if (lastAtOp.endsWith('@')) {
return hintItems(cm, line, false, false, true)
}
const lastDot = line.substring(0, cursor.ch).replace(/\.[A-Za-z0-9_-]*$/, '.')
if (lastDot.endsWith('items.')) {
return hintItems(cm, line, false, true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export function remove (node) {
export function filterPartialCompletions (cm, line, completions, property = 'text') {
const cursor = cm.getCursor()
const lineBeforeCursor = line.substring(0, cursor.ch)
const completionBeginPos = Math.max(lineBeforeCursor.lastIndexOf(' '), lineBeforeCursor.lastIndexOf('.'))
const completionBeginPos = Math.max(lineBeforeCursor.lastIndexOf(' '), lineBeforeCursor.lastIndexOf('.'), lineBeforeCursor.lastIndexOf('@'))
const partialCompletion = lineBeforeCursor.substring(completionBeginPos + 1)
return completions.filter((c) => c[property] && c[property].toLowerCase().indexOf(partialCompletion.toLowerCase()) >= 0)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,21 @@
<div v-else-if="componentType && componentType === 'Label' && visible" :class="config.class" :style="config.style">
{{ config.text }}
</div>
<fragment v-else-if="componentType && componentType === 'Content'">
{{ config.text }}
</fragment>
<pre v-else-if="componentType && componentType === 'Error' && visible" class="text-color-red" style="white-space: pre-wrap">{{ config.error }}</pre>
<component v-else-if="visible" :is="componentType" v-bind="config">
{{ config.content }}
<template v-if="context.component.slots && context.component.slots.default">
<generic-widget-component :context="childContext(slotComponent)" v-for="(slotComponent, idx) in context.component.slots.default" :key="'default-' + idx" />
</template>
</component>
</template>

<script>
import { Fragment } from 'vue-fragment'

import mixin from './widget-mixin'

import * as SystemWidgets from './system/index'
Expand All @@ -28,6 +39,7 @@ import * as LayoutWidgets from './layout/index'
export default {
mixins: [mixin],
components: {
Fragment,
...SystemWidgets,
...StandardWidgets,
...StandardListWidgets,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Import into widget components as a mixin!

import expr from 'expression-eval'
import expr from 'jse-eval'
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
import calendar from 'dayjs/plugin/calendar'
Expand All @@ -10,6 +10,22 @@ import isToday from 'dayjs/plugin/isToday'
import isYesterday from 'dayjs/plugin/isYesterday'
import isTomorrow from 'dayjs/plugin/isTomorrow'
import scope from 'scope-css'
import store from '@/js/store'

import jsepRegex from '@jsep-plugin/regex'
import jsepArrow from '@jsep-plugin/arrow'
import jsepObject from '@jsep-plugin/object'
import jsepTemplate from '@jsep-plugin/template'
expr.jsep.plugins.register(jsepRegex, jsepArrow, jsepObject, jsepTemplate)

expr.addUnaryOp('@', (itemName) => {
const itemState = store.getters.trackedItems[itemName]
if (itemState.displayState === undefined) return itemState.state
return itemState.displayState
})
expr.addUnaryOp('@@', (itemName) => {
return store.getters.trackedItems[itemName].state
})

dayjs.extend(relativeTime)
dayjs.extend(calendar)
Expand All @@ -30,7 +46,7 @@ export default {
},
computed: {
componentType () {
return this.context.component.component
return this.evaluateExpression('type', this.context.component.component)
},
childWidgetComponentType () {
if (!this.componentType.startsWith('widget:')) return null
Expand Down Expand Up @@ -112,7 +128,7 @@ export default {
if (!this.exprAst[key] || ctx.editmode) {
this.exprAst[key] = expr.parse(value.substring(1))
}
return expr.eval(this.exprAst[key], {
return expr.evaluate(this.exprAst[key], {
items: ctx.store,
props: this.props,
vars: ctx.vars,
Expand All @@ -124,7 +140,8 @@ export default {
device: this.$device,
screen: this.getScreenInfo(),
JSON: JSON,
dayjs: dayjs
dayjs: dayjs,
user: this.$store.getters.user
})
} catch (e) {
return e
Expand Down