Skip to content

Commit 82f2934

Browse files
authored
Some improvements to rule editing, misc fixes (openhab#232)
Remove the ability to close script editors with the ESC key Save the code being edited when saving the rule (for instance with Ctrl-S/Cmd-S) Add Ctrl-R/Cmd-R keyboard shortcut to run the rule Fix player controls & add oh-player-card as default for Player items Don't display the title/track part of the player card until items are set; otherwise only display the playback controls Add the ability (unstable/not documented for now) to use standard widgets in modals Fix modal config not being considered in popover Fix default slider control min/max bounds using stateDescription auth: check the token validity when the app becomes visible again and renew it if necessary Remove test card widget Fix rule module reordering Signed-off-by: Yannick Schaus <[email protected]>
1 parent aefda74 commit 82f2934

File tree

14 files changed

+93
-88
lines changed

14 files changed

+93
-88
lines changed

bundles/org.openhab.ui/web/src/components/config/controls/script-editor-popup.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<f7-popup :id="popupId" class="editor-popup" close-on-escape :tablet-fullscreen="fullscreen" @popup:opened="() => showEditor = true" @popup:closed="popupClosed" :opened="opened">
2+
<f7-popup :id="popupId" class="editor-popup" :tablet-fullscreen="fullscreen" @popup:opened="() => showEditor = true" @popup:closed="popupClosed" :opened="opened">
33
<f7-page class="code-editor-content">
44
<f7-navbar :title="title">
55
<f7-nav-right>

bundles/org.openhab.ui/web/src/components/item/item-standalone-control.vue

+11-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ export default {
3333
scale: true,
3434
label: true,
3535
scaleSubSteps: 5,
36-
min: stateDescription.min,
37-
max: stateDescription.max,
36+
min: stateDescription.minimum,
37+
max: stateDescription.maximum,
3838
step: stateDescription.step
3939
}
4040
}
@@ -58,6 +58,15 @@ export default {
5858
}
5959
}
6060
}
61+
62+
if (this.item.type === 'Player' && !stateDescription.readOnly) {
63+
ctx.component = {
64+
component: 'oh-player-card',
65+
config: {
66+
vertical: true
67+
}
68+
}
69+
}
6170
}
6271
6372
if (!ctx.component) {

bundles/org.openhab.ui/web/src/components/thing/channel-link.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
:title="(link.item.label) ? link.item.label : link.item.name"
2828
:footer="(link.item.label) ? link.item.name : '\xa0'"
2929
:subtitle="getItemTypeAndMetaLabel(link.item)"
30-
:after="context.store[link.item.name].displayState || context.store[link.item.name].state"
30+
:after="context.store[link.item.name] ? context.store[link.item.name].displayState || context.store[link.item.name].state : link.item.state"
3131
>
3232
<oh-icon v-if="link.item.category" slot="media" :icon="link.item.category" height="32" width="32" />
3333
<span v-else slot="media" class="item-initial">{{link.item.name[0]}}</span>

bundles/org.openhab.ui/web/src/components/widgets/modals/oh-popover.vue

+7-5
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,9 @@ export default {
2727
computed: {
2828
context () {
2929
return {
30-
component: this.page || this.widget,
30+
component: Object.assign({}, this.page || this.widget || this.standard, { config: this.modalParams }),
3131
store: this.$store.getters.trackedItems,
32-
props: this.modalParams,
33-
config: this.modalParams
32+
props: this.modalParams
3433
}
3534
},
3635
page () {
@@ -39,13 +38,16 @@ export default {
3938
widget () {
4039
return (this.uid.indexOf('widget:') === 0) ? this.$store.getters.widget(this.uid.substring(7)) : null
4140
},
41+
standard () {
42+
return (this.uid.indexOf('oh-') === 0) ? { component: this.uid } : null
43+
},
4244
ready () {
43-
return this.page || this.widget
45+
return this.page || this.widget || this.standard
4446
},
4547
componentType () {
4648
if (this.page) {
4749
return this.page.component
48-
} else if (this.widget) {
50+
} else if (this.widget || this.standard) {
4951
return 'generic-widget-component'
5052
}
5153
return null

bundles/org.openhab.ui/web/src/components/widgets/modals/oh-popup.vue

+6-3
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export default {
4343
computed: {
4444
context () {
4545
return {
46-
component: this.page || this.widget,
46+
component: Object.assign({}, this.page || this.widget || this.standard, { config: this.modalParams }),
4747
store: this.$store.getters.trackedItems,
4848
config: this.modalParams
4949
}
@@ -54,13 +54,16 @@ export default {
5454
widget () {
5555
return (this.uid.indexOf('widget:') === 0) ? this.$store.getters.widget(this.uid.substring(7)) : null
5656
},
57+
standard () {
58+
return (this.uid.indexOf('oh-') === 0) ? { component: this.uid } : null
59+
},
5760
ready () {
58-
return this.page || this.widget
61+
return this.page || this.widget || this.standard
5962
},
6063
componentType () {
6164
if (this.page) {
6265
return this.page.component
63-
} else if (this.widget) {
66+
} else if (this.widget || this.standard) {
6467
return 'generic-widget-component'
6568
}
6669
return null

bundles/org.openhab.ui/web/src/components/widgets/modals/oh-sheet.vue

+6-3
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export default {
3232
computed: {
3333
context () {
3434
return {
35-
component: this.page || this.widget,
35+
component: Object.assign({}, this.page || this.widget || this.standard, { config: this.modalParams }),
3636
store: this.$store.getters.trackedItems,
3737
config: this.modalParams
3838
}
@@ -43,13 +43,16 @@ export default {
4343
widget () {
4444
return (this.uid.indexOf('widget:') === 0) ? this.$store.getters.widget(this.uid.substring(7)) : null
4545
},
46+
standard () {
47+
return (this.uid.indexOf('oh-') === 0) ? { component: this.uid } : null
48+
},
4649
ready () {
47-
return this.page || this.widget
50+
return this.page || this.widget || this.standard
4851
},
4952
componentType () {
5053
if (this.page) {
5154
return this.page.component
52-
} else if (this.widget) {
55+
} else if (this.widget || this.standard) {
5356
return 'generic-widget-component'
5457
}
5558
return null

bundles/org.openhab.ui/web/src/components/widgets/standard/index.js

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/* Add any new widget to this file - the name of the export should be "OhSomething" */
22

3-
export { default as OhTestCard } from './oh-test-card.vue'
43
export { default as OhLabelCard } from './oh-label-card.vue'
54
export { default as OhToggleCard } from './oh-toggle-card.vue'
65
export { default as OhRollershutterCard } from './oh-rollershutter-card.vue'

bundles/org.openhab.ui/web/src/components/widgets/standard/oh-label-card.vue

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
.item-content
3333
flex-direction column
3434
padding-left 0
35+
padding-right 0
3536
.item-inner
3637
padding 0 !important
3738
justify-content center !important

bundles/org.openhab.ui/web/src/components/widgets/standard/oh-player-card.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<f7-card-header v-if="config.title">
44
<div>{{config.title}}</div>
55
</f7-card-header>
6-
<f7-card-content>
6+
<f7-card-content v-if="config.artistItem && config.trackItem">
77
<f7-list>
88
<f7-list-item>
99
<div class="display-block">

bundles/org.openhab.ui/web/src/components/widgets/standard/oh-test-card.vue

-51
This file was deleted.

bundles/org.openhab.ui/web/src/components/widgets/system/oh-player-controls.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export default {
2626
},
2727
computed: {
2828
isPlaying () {
29-
const value = this.context.store[this.config.item]
29+
const value = this.context.store[this.config.item].state
3030
return value === 'PLAY'
3131
}
3232
},

bundles/org.openhab.ui/web/src/components/widgets/widget-actions.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ export const actionsMixin = {
191191
case 'sheet':
192192
const actionModal = this.config[prefix + 'actionModal']
193193
const actionModalConfig = this.config[prefix + 'actionModalConfig']
194-
if (actionModal.indexOf('page:') !== 0 && actionModal.indexOf('widget:') !== 0) {
194+
if (actionModal.indexOf('page:') !== 0 && actionModal.indexOf('widget:') !== 0 && actionModal.indexOf('oh-') !== 0) {
195195
console.log('Action target is not of the format page:uid or widget:uid')
196196
return
197197
}

bundles/org.openhab.ui/web/src/js/openhab/auth.js

+18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { Utils } from 'framework7'
22

33
export default {
4+
data () {
5+
return {
6+
currentTokenExpireTime: null
7+
}
8+
},
49
methods: {
510
getRefreshToken () {
611
return localStorage.getItem('openhab.ui:refreshToken') || null
@@ -38,6 +43,8 @@ export default {
3843
'code': queryParams.code,
3944
'code_verifier': codeVerifier
4045
})
46+
47+
this.$oh.setAccessToken(null)
4148
this.$oh.api.postPlain('/rest/auth/token?useCookie=true', payload, 'application/json', 'application/x-www-form-urlencoded').then((data) => {
4249
const resp = JSON.parse(data)
4350
localStorage.setItem('openhab.ui:refreshToken', resp.refresh_token)
@@ -64,11 +71,16 @@ export default {
6471
'redirect_uri': window.location.origin,
6572
'refresh_token': refreshToken
6673
})
74+
75+
this.$oh.setAccessToken(null)
6776
this.$oh.api.postPlain('/rest/auth/token', payload, 'application/json', 'application/x-www-form-urlencoded').then((data) => {
6877
const resp = JSON.parse(data)
6978
this.$oh.setAccessToken(resp.access_token)
7079
// schedule the next token refresh when 95% of this token's lifetime has elapsed, i.e. 3 minutes before a 1-hour token is due to expire
7180
setTimeout(this.refreshAccessToken, resp.expires_in * 950)
81+
// also make sure to check the token and renew it when the app becomes visible again
82+
this.currentTokenExpireTime = new Date().getTime() + resp.expires_in * 950
83+
document.addEventListener('visibilitychange', this.checkTokenAfterVisibilityChange)
7284
this.$store.commit('setUser', { user: resp.user })
7385
resolve(resp.user)
7486
}).catch((err) => {
@@ -77,6 +89,12 @@ export default {
7789
})
7890
})
7991
},
92+
checkTokenAfterVisibilityChange (evt) {
93+
if (!document.hidden && this.currentTokenExpireTime && this.currentTokenExpireTime < new Date().getTime()) {
94+
console.log('Refreshing expired token')
95+
this.refreshAccessToken()
96+
}
97+
},
8098
cleanSession () {
8199
return new Promise((resolve, reject) => {
82100
const refreshToken = this.getRefreshToken()

bundles/org.openhab.ui/web/src/pages/settings/rules/rule-edit.vue

+39-18
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<div class="float-right align-items-flex-start align-items-center">
1818
<!-- <f7-toggle class="enable-toggle"></f7-toggle> -->
1919
<f7-link :icon-color="(rule.status.statusDetail === 'DISABLED') ? 'orange' : 'gray'" icon-ios="f7:pause_circle" icon-md="f7:pause_circle" icon-aurora="f7:pause_circle" icon-size="32" color="orange" @click="toggleDisabled"></f7-link>
20-
<f7-link icon-ios="f7:play_round" icon-md="f7:play_round" icon-aurora="f7:play_round" icon-size="32" color="blue" @click="runNow"></f7-link>
20+
<f7-link :tooltip="'Run Now' + (($device.desktop) ? ' (Ctrl-R)' : '')" icon-ios="f7:play_round" icon-md="f7:play_round" icon-aurora="f7:play_round" icon-size="32" color="blue" @click="runNow"></f7-link>
2121
</div>
2222
Status:
2323
<f7-chip class="margin-left"
@@ -161,7 +161,7 @@
161161
</f7-page>
162162
</f7-popup>
163163

164-
<script-editor-popup v-if="currentModule" title="Edit Script" popup-id="edit-rule-script-direct-popup" :value="scriptCode" :fullscreen="false" :opened="codeEditorOpened" @closed="codePopupClosed"></script-editor-popup>
164+
<script-editor-popup v-if="currentModule" title="Edit Script" ref="codePopup" popup-id="edit-rule-script-direct-popup" :value="scriptCode" :fullscreen="false" :opened="codeEditorOpened" @closed="codePopupClosed"></script-editor-popup>
165165
<cron-editor popup-id="edit-rule-cron-popup" :value="cronExpression" :opened="cronPopupOpened" @closed="cronPopupOpened = false" @input="(value) => updateCronExpression(value)" />
166166
</f7-page>
167167
</template>
@@ -310,9 +310,20 @@ export default {
310310
return
311311
}
312312
}
313-
// TODO properly validate rule
314-
if (!this.rule.uid) return
315-
if (!this.rule.name) return
313+
if (!this.rule.uid) {
314+
this.$f7.dialog.alert('Please give an ID to the rule')
315+
return
316+
}
317+
if (!this.rule.name) {
318+
this.$f7.dialog.alert('Please give a name to the rule')
319+
return
320+
}
321+
if (this.codeEditorOpened) {
322+
// save the code currently being edited if the dialog is open
323+
// this allows to hit ctrl-S to save (and ctrl-R to run the rule) while editing the code
324+
// without closing the window
325+
this.currentModule.configuration.script = this.$refs.codePopup.code
326+
}
316327
const promise = (this.createMode)
317328
? this.$oh.api.postPlain('/rest/rules', JSON.stringify(this.rule), 'text/plain', 'application/json')
318329
: this.$oh.api.put('/rest/rules/' + this.rule.uid, this.rule)
@@ -360,13 +371,12 @@ export default {
360371
runNow () {
361372
if (this.createMode) return
362373
if (this.rule.status === 'RUNNING') return
363-
this.$oh.api.postPlain('/rest/rules/' + this.rule.uid + '/runnow', '').then((data) => {
364-
this.$f7.toast.create({
365-
text: 'Running rule',
366-
destroyOnClose: true,
367-
closeTimeout: 2000
368-
}).open()
369-
}).catch((err) => {
374+
this.$f7.toast.create({
375+
text: 'Running rule',
376+
destroyOnClose: true,
377+
closeTimeout: 2000
378+
}).open()
379+
this.$oh.api.postPlain('/rest/rules/' + this.rule.uid + '/runnow', '').catch((err) => {
370380
this.$f7.toast.create({
371381
text: 'Error while running rule: ' + err,
372382
destroyOnClose: true,
@@ -375,7 +385,7 @@ export default {
375385
})
376386
},
377387
startEventSource () {
378-
this.eventSource = this.$oh.sse.connect('/rest/events?topics=smarthome/rules/*/*', null, (event) => {
388+
this.eventSource = this.$oh.sse.connect('/rest/events?topics=smarthome/rules/' + this.ruleId + '/*', null, (event) => {
379389
console.log(event)
380390
const topicParts = event.topic.split('/')
381391
switch (topicParts[3]) {
@@ -390,10 +400,19 @@ export default {
390400
this.eventSource = null
391401
},
392402
keyDown (ev) {
393-
if (ev.keyCode === 83 && (ev.ctrlKey || ev.metaKey)) {
394-
this.save(!this.createMode)
395-
ev.stopPropagation()
396-
ev.preventDefault()
403+
if (ev.ctrlKey || ev.metakKey) {
404+
switch (ev.keyCode) {
405+
case 82:
406+
this.runNow()
407+
ev.stopPropagation()
408+
ev.preventDefault()
409+
break
410+
case 83:
411+
this.save(!this.createMode)
412+
ev.stopPropagation()
413+
ev.preventDefault()
414+
break
415+
}
397416
}
398417
},
399418
toggleModuleControls () {
@@ -453,7 +472,9 @@ export default {
453472
this.$refs.modulePopup.f7Popup.open()
454473
},
455474
reorderModule (ev, section) {
456-
this.rule[section].splice(ev.detail.to, 0, this.rule[section].splice(ev.detail.from, 1)[0])
475+
const newSection = [...this.rule[section]]
476+
newSection.splice(ev.to, 0, newSection.splice(ev.from, 1)[0])
477+
this.$set(this.rule, section, newSection)
457478
},
458479
saveModule () {
459480
if (!this.currentModule.type) return

0 commit comments

Comments
 (0)