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.$oh.api.get('/rest/ui/components/ui:page'), this.$oh.api.get('/rest/ui/components/ui:widget')]
: [Promise.resolve([]), Promise.resolve([])],
dayjsLocalePromise
dayjsLocalePromise,
this.$store.dispatch('loadSemantics')
])
}).then((data) => {
// store the pages & widgets
@ -513,11 +514,9 @@ export default {
if (data[2]) dayjs.locale(data[2].key)
// load the Semantic tags
this.$store.dispatch('loadSemantics').then(() => {
this.ready = true
return Promise.resolve()
})
// finished with loading
this.ready = true
return Promise.resolve()
})
},
pageIsVisible (page) {
@ -705,7 +704,6 @@ export default {
if (refreshToken) {
this.refreshAccessToken().then(() => {
this.loggedIn = true
// this.loadData()
this.init = true
}).catch((err) => {
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 = {
loadSemantics () {
loadSemantics (context) {
console.debug('Loading semantic tags ...')
if (this.getters.apiEndpoint('tags')) {
return api.get('/rest/tags')
.then((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
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)
context.commit('setSemantics', { tags })
console.debug('Successfully loaded semantic tags.')
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 {
return Promise.resolve()
}
}
}
const mutations = {}
export default {
state,
getters,
actions,
mutations
mutations,
actions
}

View File

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

View File

@ -114,6 +114,8 @@ export default {
item.children.forEach(child => this.sortModel(child))
},
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')
.then((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.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
console.debug('Successfully loaded semantic model and build semantic homepages.')
})
.catch((err) => {
console.log('Error while loading model: ' + err)