Skip to content

Commit

Permalink
Allow model cards and model tabs outside of homepage (#2584)
Browse files Browse the repository at this point in the history
Fixes #2583. Fixes #1591.

This moves model loading code to a new Vuex store module named model.
Model loading is now done by app.vue on init and when an Item change event is received through SSE.

home.vue and home-edit.vue now get the model from the Vuex store instead of loading it.
Add tab components for locations-tab, equipment-tab and properties-tab for easy usage in tabbed pages.
Add card components for oh-.location-card, oh-equipment-card and oh-property-card to standard widget list.

---------

Also-by: Florian Hotze <florianh_dev@icloud.com>
Signed-off-by: Thomas Wunschel <4302898+wuschi@users.noreply.github.com>
  • Loading branch information
wuschi authored Aug 12, 2024
1 parent 3afef19 commit 94aa16a
Show file tree
Hide file tree
Showing 24 changed files with 409 additions and 204 deletions.
2 changes: 1 addition & 1 deletion bundles/org.openhab.ui/doc/components/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ source: https://github.com/openhab/openhab-webui/edit/main/bundles/org.openhab.u
| Component | Name | Description |
|--------|------|-------------|
| [`oh-location-card`](./oh-location-card.html) | [Location Card](./oh-location-card.html) | A card showing model items in a certain location |
| [`oh-equipment-card`](./oh-equipment-card.html) | [Equipment Class Card](./oh-equipment-card.html) | A card showing model items belonging to a certain equipment class |
| [`oh-equipment-card`](./oh-equipment-card.html) | [Equipment Card](./oh-equipment-card.html) | A card showing model items belonging to a certain equipment class |
| [`oh-property-card`](./oh-property-card.html) | [Property Card](./oh-property-card.html) | A card showing model items related to a certain property |


7 changes: 7 additions & 0 deletions bundles/org.openhab.ui/doc/components/oh-equipment-card.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ A card showing model items belonging to a certain equipment class
<div class="props">
<PropGroup name="card" label="Model Card">
General settings for this card
<PropBlock type="TEXT" name="item" label="Item">
<PropDescription>
Equipment class to display
</PropDescription>
<PropOptions>
</PropOptions>
</PropBlock>
<PropBlock type="TEXT" name="title" label="Title">
<PropDescription>
Title of the card
Expand Down
5 changes: 5 additions & 0 deletions bundles/org.openhab.ui/doc/components/oh-location-card.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ A card showing model items in a certain location
<div class="props">
<PropGroup name="card" label="Model Card">
General settings for this card
<PropBlock type="TEXT" name="item" label="Item" context="item">
<PropDescription>
Location to display
</PropDescription>
</PropBlock>
<PropBlock type="TEXT" name="title" label="Title">
<PropDescription>
Title of the card
Expand Down
7 changes: 7 additions & 0 deletions bundles/org.openhab.ui/doc/components/oh-property-card.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ A card showing model items related to a certain property
<div class="props">
<PropGroup name="card" label="Model Card">
General settings for this card
<PropBlock type="TEXT" name="item" label="Item">
<PropDescription>
Property to display
</PropDescription>
<PropOptions>
</PropOptions>
</PropBlock>
<PropBlock type="TEXT" name="title" label="Title">
<PropDescription>
Title of the card
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ const ModelCardParameters = () => [
]

export const OhLocationCardParameters = () => new WidgetDefinition('oh-location-card', 'Location Card', 'A card showing model items in a certain location')
.paramGroup(ModelCardParameterGroup(), ModelCardParameters())
.paramGroup(ModelCardParameterGroup(), [pi('item', 'Item', 'Location to display')].concat(ModelCardParameters()))
.paramGroup(pg('glance', 'Card at-a-glance badges'), [
pb('disableBadges', 'Disable badges', 'Do not examine items to display badges - can help with performance if you don\'t need them.'),
pt('badges', 'Enabled badges', 'Select the badges you wish to show in the header of the card. Display all if none are selected.')
Expand All @@ -120,8 +120,14 @@ export const OhLocationCardParameters = () => new WidgetDefinition('oh-location-
], true, true)
])

export const OhEquipmentCardParameters = () => new WidgetDefinition('oh-equipment-card', 'Equipment Class Card', 'A card showing model items belonging to a certain equipment class')
.paramGroup(ModelCardParameterGroup(), ModelCardParameters())
export const OhEquipmentCardParameters = () => new WidgetDefinition('oh-equipment-card', 'Equipment Card', 'A card showing model items belonging to a certain equipment class')
.paramGroup(ModelCardParameterGroup(), [
pt('item', 'Item', 'Equipment class to display')
.o([]) // inject semantic equipment tags at runtime
].concat(ModelCardParameters()))

export const OhPropertyCardParameters = () => new WidgetDefinition('oh-property-card', 'Property Card', 'A card showing model items related to a certain property')
.paramGroup(ModelCardParameterGroup(), ModelCardParameters())
.paramGroup(ModelCardParameterGroup(), [
pt('item', 'Item', 'Property to display')
.o([]) // inject semantic property tags at runtime
].concat(ModelCardParameters()))
4 changes: 4 additions & 0 deletions bundles/org.openhab.ui/web/src/components/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,7 @@ export default {
dayjsLocalePromise = (dayjsLocale) ? import('dayjs/locale/' + dayjsLocale.key + '.js').then(() => Promise.resolve(dayjsLocale)) : Promise.resolve(null)
}
// load the pages & widgets, only if the 'ui' endpoint exists (or empty arrays otherwise)
// load the semantic tags
return Promise.all([
...this.$store.getters.apiEndpoint('ui')
? [this.$oh.api.get('/rest/ui/components/ui:page'), this.$oh.api.get('/rest/ui/components/ui:widget')]
Expand All @@ -499,6 +500,9 @@ export default {
if (data[2]) dayjs.locale(data[2].key)
// load & build the semantic model
return this.$store.dispatch('loadSemanticModel')
}).then(() => {
// finished with loading
this.ready = true
return Promise.resolve()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</model-card>
</template>

<style lang="stylus">
<style lang="stylus" scoped>
.equipment-card
height 150px
.equipment-stats
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
</model-card>
</template>

<style lang="stylus">
<style lang="stylus" scoped>
.location-card
height 200px
.location-stats
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
</model-card>
</template>

<style lang="stylus">
<style lang="stylus" scoped>
.property-card
height 150px
.property-stats
Expand Down
10 changes: 9 additions & 1 deletion bundles/org.openhab.ui/web/src/components/sse-events-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ export default {
},
methods: {
startEventSource () {
const topicItems = 'openhab/items/*/added,openhab/items/*/removed,openhab/items/*/updated'
const topicAudio = 'openhab/webaudio/playurl'
const commandItem = localStorage.getItem('openhab.ui:commandItem')
const topicCommand = `openhab/items/${commandItem || ''}/command`
let topics = null
let topics = topicItems
if (localStorage.getItem('openhab.ui:webaudio.enable') === 'enabled') {
topics = topicAudio
}
Expand All @@ -38,6 +39,13 @@ export default {
const payload = JSON.parse(event.payload)
this.handleCommand(payload.value)
break
default:
if (event.topic.startsWith('openhab/items/')) {
console.info('Item SSE event received, reloading semantic model ...')
this.$store.dispatch('loadSemanticModel')
break
}
console.warn('Unhandled SSE event: ' + JSON.stringify(event))
}
})
},
Expand Down
12 changes: 12 additions & 0 deletions bundles/org.openhab.ui/web/src/components/tabs/equipment-tab.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<template>
<model-tab type="equipment" :page="context" />
</template>

<script>
import ModelTab from '@/pages/home/model-tab.vue'
export default {
props: ['context'],
components: { ModelTab }
}
</script>
12 changes: 12 additions & 0 deletions bundles/org.openhab.ui/web/src/components/tabs/locations-tab.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<template>
<model-tab type="locations" :page="context" />
</template>

<script>
import ModelTab from '@/pages/home/model-tab.vue'
export default {
props: ['context'],
components: { ModelTab }
}
</script>
12 changes: 12 additions & 0 deletions bundles/org.openhab.ui/web/src/components/tabs/properties-tab.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<template>
<model-tab type="properties" :page="context" />
</template>

<script>
import ModelTab from '@/pages/home/model-tab.vue'
export default {
props: ['context'],
components: { ModelTab }
}
</script>
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
/* Add any new widget to this file - the name of the export should be "OhSomething" */

export { default as OhEquipmentCard } from './oh-equipment-card.vue'
export { default as OhLabelCard } from './oh-label-card.vue'
export { default as OhToggleCard } from './oh-toggle-card.vue'
export { default as OhRollershutterCard } from './oh-rollershutter-card.vue'
export { default as OhColorpickerCard } from './oh-colorpicker-card.vue'
export { default as OhGaugeCard } from './oh-gauge-card.vue'
export { default as OhKnobCard } from './oh-knob-card.vue'
export { default as OhLocationCard } from './oh-location-card.vue'
export { default as OhPropertyCard } from './oh-property-card.vue'
export { default as OhSliderCard } from './oh-slider-card.vue'
export { default as OhImageCard } from './oh-image-card.vue'
export { default as OhVideoCard } from './oh-video-card.vue'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<template>
<equipment-card :element="element" :context="context" :tab-context="config" />
</template>

<script>
import mixin from '../widget-mixin'
import store from '@/js/store'
import { OhEquipmentCardParameters } from '@/assets/definitions/widgets/home'
import EquipmentCard from '@/components/cards/equipment-card.vue'
export default {
components: { EquipmentCard },
mixins: [mixin],
computed: {
element () {
return this.$store.getters.semanticModelElement(this.config.item, 'equipment') ||
{ defaultTitle: 'Equipment Card', item: { equipment: [], metadata: { semantics: { value: '' } } }, equipment: [], properties: [] }
}
},
widget: () => {
const widget = OhEquipmentCardParameters()
widget.props.parameters.find(p => p.name === 'item').options = store.state.semantics.Equipment.map(p => { return { name: p, label: store.state.semantics.Labels[p] } })
return widget
}
}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<template>
<location-card :element="element" :context="context" :tab-context="config" :parent-location="parentLocationName" />
</template>

<script>
import LocationCard from '@/components/cards/location-card.vue'
import mixin from '../widget-mixin'
import { OhLocationCardParameters } from '@/assets/definitions/widgets/home'
export default {
components: { LocationCard },
mixins: [mixin],
computed: {
element () {
return this.$store.getters.semanticModelElement(this.config.item, 'location') ||
{ defaultTitle: 'Location Card', item: { equipment: [], metadata: { semantics: { value: '' } } }, equipment: [], properties: [] }
},
parentLocationName () {
return this.element && this.element.parent ? this.element.parent.label || this.element.parent.name : ''
}
},
widget: OhLocationCardParameters
}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<template>
<property-card :element="element" :context="context" :tab-context="config" />
</template>

<script>
import mixin from '../widget-mixin'
import store from '@/js/store'
import { OhPropertyCardParameters } from '@/assets/definitions/widgets/home'
import PropertyCard from '@/components/cards/property-card.vue'
export default {
components: { PropertyCard },
mixins: [mixin],
computed: {
element () {
return this.$store.getters.semanticModelElement(this.config.item, 'property') ||
{ defaultTitle: 'Property Card', item: { equipment: [], metadata: { semantics: { value: '' } } }, equipment: [], properties: [], points: [] }
}
},
widget: () => {
const widget = OhPropertyCardParameters()
widget.props.parameters.find(p => p.name === 'item').options = store.state.semantics.Properties.map(p => { return { name: p, label: store.state.semantics.Labels[p] } })
return widget
}
}
</script>
2 changes: 2 additions & 0 deletions bundles/org.openhab.ui/web/src/js/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Vue from 'vue'
import Vuex from 'vuex'

import components from './modules/components'
import model from './modules/model'
import states from './modules/states'
import semantics from './modules/semantics'
import user from './modules/user'
Expand All @@ -14,6 +15,7 @@ Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
components,
model,
semantics,
states,
user
Expand Down
Loading

0 comments on commit 94aa16a

Please sign in to comment.