Ensure semantic model pages are built after tags are loaded (#2066)

Fixes #2006.

With the attempt in #2029 failing due to #2054, this finally fixes an
issue where the semantic model pages (Equipment, Properties) were
missing translations.
This was due to a race condition, where the semantic model pages were
built before the tags were loaded.

This PR fixes this by watching for semantic model updates (i.e.
subscripting to the underlying Vuex mutation) and loading/building the
model pages after such an update.

Futher improvements:
- Initial loading of semantic tags is put in parallel with other API
requests performed on app init.
- Vuex semantics: A mutation is used for setting the semantic tags from
the action.
- Debug logging is added to both the semantic tag and the semantic model
page loading.

---------

Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
pull/2053/head
Florian Hotze 2023-09-16 16:31:53 +02:00 committed by GitHub
parent 07aacc9ee5
commit f2c008befb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 42 additions and 26 deletions

View File

@ -498,7 +498,8 @@ export default {
...this.$store.getters.apiEndpoint('ui') ...this.$store.getters.apiEndpoint('ui')
? [this.$oh.api.get('/rest/ui/components/ui:page'), this.$oh.api.get('/rest/ui/components/ui:widget')] ? [this.$oh.api.get('/rest/ui/components/ui:page'), this.$oh.api.get('/rest/ui/components/ui:widget')]
: [Promise.resolve([]), Promise.resolve([])], : [Promise.resolve([]), Promise.resolve([])],
dayjsLocalePromise dayjsLocalePromise,
this.$store.dispatch('loadSemantics')
]) ])
}).then((data) => { }).then((data) => {
// store the pages & widgets // store the pages & widgets
@ -513,11 +514,9 @@ export default {
if (data[2]) dayjs.locale(data[2].key) if (data[2]) dayjs.locale(data[2].key)
// load the Semantic tags // finished with loading
this.$store.dispatch('loadSemantics').then(() => { this.ready = true
this.ready = true return Promise.resolve()
return Promise.resolve()
})
}) })
}, },
pageIsVisible (page) { pageIsVisible (page) {
@ -705,7 +704,6 @@ export default {
if (refreshToken) { if (refreshToken) {
this.refreshAccessToken().then(() => { this.refreshAccessToken().then(() => {
this.loggedIn = true this.loggedIn = true
// this.loadData()
this.init = true this.init = true
}).catch((err) => { }).catch((err) => {
console.warn('Error while using the stored refresh_token to get a new access_token: ' + err + '. Logging out & cleaning session.') console.warn('Error while using the stored refresh_token to get a new access_token: ' + err + '. Logging out & cleaning session.')

View File

@ -15,37 +15,47 @@ const getters = {
} }
} }
const mutations = {
setSemantics (state, { tags }) {
state.Locations = tags.filter(t => t.uid.startsWith('Location')).map(t => t.name)
state.Equipment = tags.filter(t => t.uid.startsWith('Equipment')).map(t => t.name)
state.Points = tags.filter(t => t.uid.startsWith('Point')).map(t => t.name)
state.Properties = tags.filter(t => t.uid.startsWith('Property')).map(t => t.name)
// Store i18n labels
state.Labels = {} // Clear existing labels
for (const i in tags) {
const t = tags[i]
state.Labels[t.name] = t.label || t.name
}
// Save as i18n messages
i18n.mergeLocaleMessage(i18n.locale, state.Labels)
}
}
const actions = { const actions = {
loadSemantics () { loadSemantics (context) {
console.debug('Loading semantic tags ...')
if (this.getters.apiEndpoint('tags')) { if (this.getters.apiEndpoint('tags')) {
return api.get('/rest/tags') return api.get('/rest/tags')
.then((tags) => { .then((tags) => {
state.Locations = tags.filter(t => t.uid.startsWith('Location')).map(t => t.name) context.commit('setSemantics', { tags })
state.Equipment = tags.filter(t => t.uid.startsWith('Equipment')).map(t => t.name) console.debug('Successfully loaded semantic tags.')
state.Points = tags.filter(t => t.uid.startsWith('Point')).map(t => t.name)
state.Properties = tags.filter(t => t.uid.startsWith('Property')).map(t => t.name)
// Store i18n labels
for (const i in tags) {
const t = tags[i]
state.Labels[t.name] = t.label || t.name
}
// Save as i18n messages
i18n.mergeLocaleMessage(i18n.locale, state.Labels)
return Promise.resolve() return Promise.resolve()
}) })
.catch((e) => Promise.reject(e)) .catch((e) => {
console.error('Failed to load semantic tags:')
console.error(e)
Promise.reject('Failed to load semantic tags: ' + e)
})
} else { } else {
return Promise.resolve() return Promise.resolve()
} }
} }
} }
const mutations = {}
export default { export default {
state, state,
getters, getters,
actions, mutations,
mutations actions
} }

View File

@ -156,7 +156,6 @@ export default {
watch: { watch: {
ready (val, oldVal) { ready (val, oldVal) {
if (val && !oldVal) { if (val && !oldVal) {
this.loadModel()
this.$store.dispatch('startTrackingStates') this.$store.dispatch('startTrackingStates')
} }
} }
@ -175,6 +174,12 @@ export default {
this.$store.dispatch('stopTrackingStates') this.$store.dispatch('stopTrackingStates')
}, },
onPageInit () { onPageInit () {
this.$store.subscribe((mutation, state) => {
if (mutation.type === 'setSemantics') {
this.loadModel()
}
})
if (window.OHApp) { if (window.OHApp) {
if (window.OHApp.pinToHome) this.showPinToHome = true if (window.OHApp.pinToHome) this.showPinToHome = true
if (window.OHApp.exitToApp) this.showExitToApp = true if (window.OHApp.exitToApp) this.showExitToApp = true

View File

@ -114,6 +114,8 @@ export default {
item.children.forEach(child => this.sortModel(child)) item.children.forEach(child => this.sortModel(child))
}, },
loadModel (page) { loadModel (page) {
this.modelReady = false
console.debug('Loading semantic model and building semantic homepages ...')
this.$oh.api.get('/rest/items?staticDataOnly=true&metadata=semantics,listWidget,widgetOrder') this.$oh.api.get('/rest/items?staticDataOnly=true&metadata=semantics,listWidget,widgetOrder')
.then((data) => { .then((data) => {
this.items = data this.items = data
@ -167,6 +169,7 @@ export default {
this.model.equipment = Object.keys(equipment).sort((a, b) => this.$t(a).localeCompare(this.$t(b))).map(k => this.buildModelCard('equipment', equipment[k], k, page)) this.model.equipment = Object.keys(equipment).sort((a, b) => this.$t(a).localeCompare(this.$t(b))).map(k => this.buildModelCard('equipment', equipment[k], k, page))
this.model.properties = Object.keys(properties).sort((a, b) => this.$t(a).localeCompare(this.$t(b))).map(k => this.buildModelCard('property', properties[k], k, page)) this.model.properties = Object.keys(properties).sort((a, b) => this.$t(a).localeCompare(this.$t(b))).map(k => this.buildModelCard('property', properties[k], k, page))
this.modelReady = true this.modelReady = true
console.debug('Successfully loaded semantic model and build semantic homepages.')
}) })
.catch((err) => { .catch((err) => {
console.log('Error while loading model: ' + err) console.log('Error while loading model: ' + err)