Skip to content

Commit

Permalink
Add a new settings menu for persistence (#2229)
Browse files Browse the repository at this point in the history
Persistence policies can be configured from the UI. However, it is
difficult to find, and one needs to know where to look. Apart from a
documentation issue, I think persistence is core enough to merrit its
own entry in the settings, so it becomes more prominent.

See for example here:
https://community.openhab.org/t/after-reboot-string-values-are-empty/152064/16

This adds a persistence entry below transformations to the settings menu.

The new persistence config page allows to set the default persistence,
and links to defining the policies for each installed persistence add-on.
There also is a "add" list entry to install more persistence add-ons.
If none is installed, it will explain persistence and link to the docs and the add-on store.

The default persistence settings has been removed from the system
settings, and the link to the persistence policy config from the add-on
settings page has been converted to a button.

---------

Also-by: Florian Hotze <florianh_dev@icloud.com>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
  • Loading branch information
mherwege authored Dec 29, 2023
1 parent 0f35e0e commit 2fe6ae9
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,8 @@
"addons.text": "Add-ons add functionality to your openHAB system.<br><br>Install them with the button below.",

"page.unavailable.title": "Page Unavailable",
"page.unavailable.text": "You are not allowed to view this page because of visibility restrictions."
"page.unavailable.text": "You are not allowed to view this page because of visibility restrictions.",

"persistence.title": "No persistence add-on installed",
"persistence.text": "With persistence you can store Item states over time, no matter they are historic or future values. To configure persistence, you need at least one persistence add-on to be installed."
}
4 changes: 4 additions & 0 deletions bundles/org.openhab.ui/web/src/js/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const InboxListPage = () => import(/* webpackChunkName: "admin-config" */ '../pa
const TransformationsListPage = () => import(/* webpackChunkName: "admin-config" */ '../pages/settings/transformations/transformations-list.vue')
const TransformationsEditPage = () => import(/* webpackChunkName: "admin-rules" */ '../pages/settings/transformations/transformation-edit.vue')

const PersistenceSettingsPage = () => import(/* webpackChunkName: "admin-config" */ '../pages/settings/persistence/persistence-settings.vue')
const PersistenceEditPage = () => import(/* webpackChunkName: "admin-config" */ '../pages/settings/persistence/persistence-edit.vue')

const SemanticModelPage = () => import(/* webpackChunkName: "admin-config" */ '../pages/settings/model/model.vue')
Expand Down Expand Up @@ -279,6 +280,9 @@ export default [
},
{
path: 'persistence/',
beforeEnter: [enforceAdminForRoute],
beforeLeave: [checkDirtyBeforeLeave],
async: loadAsync(PersistenceSettingsPage),
routes: [
{
path: ':serviceId',
Expand Down
8 changes: 3 additions & 5 deletions bundles/org.openhab.ui/web/src/pages/addons/addon-config.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@
</f7-navbar>
<f7-block v-if="type === 'persistence'" class="service-config block-narrow">
<f7-col>
<f7-block-title medium>
<f7-link color="blue" :href="'/settings/persistence/' + name">
Persistence configuration
</f7-link>
</f7-block-title>
<f7-button large fill color="blue" :href="'/settings/persistence/' + name">
Configure Persistence Policies
</f7-button>
</f7-col>
</f7-block>
<f7-block form v-if="configDescription && config" class="service-config block-narrow">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@
:footer="objectsSubtitles.transform">
<f7-icon slot="media" f7="function" color="gray" />
</f7-list-item>
<f7-list-item
media-item
link="persistence/"
title="Persistence"
badge-color="blue"
:footer="objectsSubtitles.persistence">
<f7-icon slot="media" f7="tray-arrow-down" color="gray" />
</f7-list-item>
</f7-list>
<f7-block-title v-if="$store.getters.apiEndpoint('rules')">
Automation
Expand Down Expand Up @@ -157,6 +165,7 @@ export default {
addonsLoaded: false,
servicesLoaded: false,
addonsInstalled: [],
persistenceAddonsInstalled: [],
addonsServices: [],
systemServices: [],
objectsSubtitles: {
Expand All @@ -165,6 +174,7 @@ export default {
items: 'Manage the functional layer',
pages: 'Design displays for user control & monitoring',
transform: 'Make raw data human-readable',
persistence: 'Persist data for future use',
rules: 'Automate with triggers and actions',
scenes: 'Store a set of desired states as a scene',
scripts: 'Rules dedicated to running code',
Expand Down Expand Up @@ -219,15 +229,23 @@ export default {
// can be done in parallel!
servicesPromise.then((data) => {
this.systemServices = data.filter(s => s.category === 'system')
this.addonsServices = data.filter(s => s.category !== 'system')
this.systemServices = data
.filter(s => (s.category === 'system') && (s.id !== 'org.openhab.persistence'))
.sort((s1, s2) => this.sortByLabel(s1, s2))
this.addonsServices = data.filter(s => s.category !== 'system').sort((s1, s2) => this.sortByLabel(s1, s2))
this.servicesLoaded = true
})
addonsPromise.then((data) => {
this.addonsInstalled = data.filter(a => a.installed && !['application/vnd.openhab.ruletemplate', 'application/vnd.openhab.uicomponent;type=widget', 'application/vnd.openhab.uicomponent;type=blocks'].includes(a.contentType))
this.addonsInstalled = data
.filter(a => a.installed && !['application/vnd.openhab.ruletemplate', 'application/vnd.openhab.uicomponent;type=widget', 'application/vnd.openhab.uicomponent;type=blocks'].includes(a.contentType))
.sort((s1, s2) => this.sortByLabel(s1, s2))
this.persistenceAddonsInstalled = this.addonsInstalled.filter(a => a.installed && a.type === 'persistence')
this.addonsLoaded = true
})
},
sortByLabel (s1, s2) {
return s1.label.toLowerCase() > s2.label.toLowerCase() ? 1 : -1
},
loadCounters () {
if (!this.apiEndpoints) return
if (this.$store.getters.apiEndpoint('inbox')) this.$oh.api.get('/rest/inbox').then((data) => { this.inboxCount = data.filter((e) => e.flag === 'NEW').length.toString() })
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<template>
<f7-page @page:afterin="onPageAfterIn" @page:beforeout="onPageBeforeOut">
<f7-navbar title="Persistence Settings" back-link="Settings" back-link-url="/settings/" back-link-force>
<f7-nav-right v-if="persistenceList.length > 0">
<f7-link @click="save()" v-if="$theme.md" icon-md="material:save" icon-only />
<f7-link @click="save()" v-if="!$theme.md">
Save<span v-if="$device.desktop">&nbsp;(Ctrl-S)</span>
</f7-link>
</f7-nav-right>
</f7-navbar>

<f7-block form v-if="ready && persistenceList.length" class="block-narrow">
<f7-col>
<f7-block-title medium>
General Settings
</f7-block-title>
<config-sheet
:parameter-groups="configDescriptions.parameterGroups"
:parameters="configDescriptions.parameters"
:configuration="config"
:set-empty-config-as-null="true" />
</f7-col>
</f7-block>
<f7-block v-if="ready && persistenceList.length" class="block-narrow">
<f7-col>
<f7-block-title medium>
Configure Persistence Policies
</f7-block-title>
<f7-list style="margin-top: 15px">
<f7-list-item
v-for="persistence in persistenceList"
media-item
:key="persistence.id"
:link="persistence.id"
:title="persistence.label"
:footer="persistence.id" />
<f7-list-item link="/addons/other/" no-chevron media-item :color="($theme.dark) ? 'black' : 'white'" subtitle="Install more persistence add-ons">
<f7-icon slot="media" color="green" aurora="f7:plus_circle_fill" ios="f7:plus_circle_fill" md="material:control_point" />
</f7-list-item>
</f7-list>
</f7-col>
</f7-block>

<f7-block v-if="ready && !persistenceList.length" class="service-config block-narrow">
<empty-state-placeholder icon="tray-arrow-down" title="persistence.title" text="persistence.text" />
<f7-row class="display-flex justify-content-center">
<f7-button large fill color="blue" external :href="documentationLink" target="_blank" v-t="'home.overview.button.documentation'" />
<span style="width: 8px" />
<f7-button large fill color="blue" href="/addons/other/">
Install a persistence add-on
</f7-button>
</f7-row>
</f7-block>
</f7-page>
</template>

<script>
import DirtyMixin from '../dirty-mixin'
import ConfigSheet from '@/components/config/config-sheet.vue'
export default {
mixins: [DirtyMixin],
components: {
'empty-state-placeholder': () => import('@/components/empty-state-placeholder.vue'),
ConfigSheet
},
data () {
return {
loading: false,
ready: false,
serviceId: 'org.openhab.persistence',
persistenceList: [],
configDescriptions: null,
config: null
}
},
computed: {
documentationLink () {
return `https://${this.$store.state.runtimeInfo.buildString === 'Release Build' ? 'www' : 'next'}.openhab.org/link/persistence`
}
},
watch: {
config: {
handler: function () {
if (!this.loading) {
this.dirty = true
}
},
deep: true
}
},
methods: {
onPageAfterIn () {
if (window) {
window.addEventListener('keydown', this.keyDown)
}
this.load()
},
onPageBeforeOut () {
if (window) {
window.removeEventListener('keydown', this.keyDown)
}
},
load () {
if (this.loading) return
this.loading = true
this.$oh.api.get('/rest/persistence').then((data) => {
this.$set(this, 'persistenceList', data)
})
this.$oh.api.get('/rest/services/' + this.serviceId).then(data => {
if (data.configDescriptionURI) {
this.$oh.api.get('/rest/config-descriptions/' + data.configDescriptionURI).then(data2 => {
this.$set(this, 'configDescriptions', data2)
this.$oh.api.get('/rest/services/' + this.serviceId + '/config').then(data3 => {
this.$set(this, 'config', data3)
this.$nextTick(() => {
this.loading = false
this.ready = true
})
})
})
}
})
},
save () {
this.$oh.api.put('/rest/services/' + this.serviceId + '/config', this.config).then(() => {
this.$f7.toast.create({
text: 'Default persistence setting saved',
destroyOnClose: true,
closeTimeout: 2000
}).open()
})
this.dirty = false
},
keyDown (ev) {
if ((ev.ctrlKey || ev.metaKey) && !(ev.altKey || ev.shiftKey)) {
switch (ev.keyCode) {
case 83:
this.save()
ev.stopPropagation()
ev.preventDefault()
break
}
}
}
}
}
</script>

0 comments on commit 2fe6ae9

Please sign in to comment.