Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix UoM metadata not stored when Item created from link #2302

Merged
merged 3 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
info="Used internally, for persistence and external systems. It is independent from the state visualization in the UI, which is defined through the state description."
@input="item.unit = $event.target.value" clear-button />
<f7-list-input v-if="item.type && item.type.startsWith('Number:') && createMode" label="State Description Pattern" type="text" :value="item.stateDescriptionPattern"
info="Pattern or transformation applied to the state for display purposes."
info="Pattern or transformation applied to the state for display purposes. Only saved if you change the pre-filled default value."
@input="item.stateDescriptionPattern = $event.target.value" clear-button />
<f7-list-item key="function-picker-arithmetic" v-if="item.type === 'Group' && item.groupType && (['Dimmer', 'Rollershutter'].indexOf(item.groupType) >= 0 || item.groupType.indexOf('Number') === 0)" title="Aggregation Function" smart-select :smart-select-params="{openIn: 'popover', closeOnSelect: true}">
<select name="select-function" @change="setFunction($event.target.value)">
Expand Down
17 changes: 3 additions & 14 deletions bundles/org.openhab.ui/web/src/components/item/item-form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
info="Used internally, for persistence and external systems. It is independent from the state visualization in the UI, which is defined through the state description."
@input="item.unit = $event.target.value" clear-button />
<f7-list-input v-show="!hideType && item.type && item.type.startsWith('Number:') && createMode" label="State Description Pattern" type="text" :value="item.stateDescriptionPattern"
info="Pattern or transformation applied to the state for display purposes."
info="Pattern or transformation applied to the state for display purposes. Only saved if you change the pre-filled default value."
@input="item.stateDescriptionPattern = $event.target.value" clear-button />
<f7-list-input v-if="!hideCategory" ref="category" label="Category" autocomplete="off" type="text" placeholder="temperature, firstfloor..." :value="item.category"
@input="item.category = $event.target.value" clear-button>
Expand Down Expand Up @@ -118,26 +118,15 @@ export default {
},
onNameInput (event) {
this.item.name = event.target.value
this.validateName(this.item.name)
},
validateName (name) {
let oldError = this.nameErrorMessage
if (!/^[A-Za-z0-9_]+$/.test(name)) {
this.nameErrorMessage = 'Required. A-Z,a-z,0-9,_ only'
} else if (this.items.some(item => item.name === name)) {
this.nameErrorMessage = 'An Item with this name already exists'
} else {
this.nameErrorMessage = ''
}
if (oldError !== this.nameErrorMessage) this.$emit('valid', !this.nameErrorMessage)
this.$set(this, 'nameErrorMessage', this.validateItemName(this.item.name))
}
},
mounted () {
if (!this.item) return
if (!this.item.category) this.$set(this.item, 'category', '')
if (this.createMode) {
if (!this.items) this.items = []
this.validateName(this.item.name)
this.$set(this, 'nameErrorMessage', this.validateItemName(this.item.name))
}
const categoryControl = this.$refs.category
if (!categoryControl || !categoryControl.$el) return
Expand Down
38 changes: 28 additions & 10 deletions bundles/org.openhab.ui/web/src/components/item/item-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,29 @@ export default {
if (!item.tags) return []
return item.tags.filter((t) => !this.isSemanticTag(t))
},
doSave (item) {
console.log(item)

/**
* Validate the Item name against valid characters and (if existing Items are available on `this.items`) names of existing Items.
*
* @param {string} name Item name to validate
* @returns {string} The error message if the name is invalid, or an empty string if the name is valid.
*/
validateItemName (name) {
if (!/^[A-Za-z0-9_]+$/.test(name)) {
return 'Required. A-Z,a-z,0-9,_ only'
} else if (this.items && this.items.some(item => item.name === name)) {
return 'An Item with this name already exists'
}
return ''
},
/**
* Save an Item, i.e. add a new Item or update an existing Item.
*
* If a new Item is created (checks `this.createMode`), and it is an UoM Item, unit metadata and state description (if changed from the default) metadata are saved as well.
*
* @param item
* @returns {Promise}
*/
saveItem (item) {
if (item.groupType === 'None') delete item.groupType
if (item.function === 'None') delete item.groupType

Expand All @@ -41,17 +61,17 @@ export default {

// TODO: Add support for saving metadata
return this.$oh.api.put('/rest/items/' + item.name, item).then(() => {
let unitPromise = Promise.resolve()
// Save unit metadata if Item is an UoM Item
if (this.createMode && (item.type.startsWith('Number:') || item.groupType?.startsWith('Number:')) && unit) {
const metadata = {
value: unit,
config: {}
}
unitPromise = this.$oh.api.put('/rest/items/' + item.name + '/metadata/unit', metadata)
return this.$oh.api.put('/rest/items/' + item.name + '/metadata/unit', metadata)
}
return unitPromise
return Promise.resolve()
}).then(() => {
let stateDescriptionPromise = Promise.resolve()
// Save state description if Item is an UoM Item and if state description changed from the default value
if (this.createMode && (item.type.startsWith('Number:') || item.groupType?.startsWith('Number:')) && stateDescriptionPattern) {
if (stateDescriptionPattern !== `%.0f ${unit}`) {
const metadata = {
Expand All @@ -60,11 +80,9 @@ export default {
pattern: stateDescriptionPattern
}
}
stateDescriptionPromise = this.$oh.api.put('/rest/items/' + item.name + '/metadata/stateDescription', metadata)
return this.$oh.api.put('/rest/items/' + item.name + '/metadata/stateDescription', metadata)
}
}
return stateDescriptionPromise
}).then(() => {
return Promise.resolve()
}).catch((err) => {
return Promise.reject(err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export default {
},
save () {
this.editMode = false
this.doSave(this.editedItem).then(() => {
this.saveItem(this.editedItem).then(() => {
this.$f7.toast.create({
text: 'Item updated',
destroyOnClose: true,
Expand All @@ -121,7 +121,7 @@ export default {
// TODO properly validate item
if (!this.editedItem.name) return

this.doSave(this.editedItem).then(() => {
this.saveItem(this.editedItem).then(() => {
this.$f7.toast.create({
text: 'Item created',
destroyOnClose: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,10 @@ export default {
if (this.currentTab === 'code') {
if (!this.fromYaml()) return Promise.reject()
}
if (!this.item.name) return this.$f7.dialog.alert('Please give the Item a valid name').open() // user cannot change name
if (this.validateItemName(this.item.name) !== '') return this.$f7.dialog.alert('Please give the Item a valid name: ' + this.validateItemName(this.item.name)).open()
if (!this.item.type || !this.types.ItemTypes.includes(this.item.type.split(':')[0])) return this.$f7.dialog.alert('Please give Item a valid type').open()

this.doSave(this.item).then(() => {
this.saveItem(this.item).then(() => {
if (this.createMode) {
this.$f7.toast.create({
text: 'Item created',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@
<f7-col>
<f7-block-title>Item</f7-block-title>
<f7-list media-list>
<f7-list-item radio :checked="!createItem" value="false" @change="createItem = false" title="Use an existing Item" name="item-creation-choice" />
<f7-list-item radio :checked="createItem" value="true" @change="createItem = true" title="Create a new Item" name="item-creation-choice" />
<f7-list-item radio :checked="!createMode" value="false" @change="createMode = false" title="Use an existing Item" name="item-creation-choice" />
<f7-list-item radio :checked="createMode" value="true" @change="createMode = true" title="Create a new Item" name="item-creation-choice" />
</f7-list>
</f7-col>

<!-- Choose item to link -->
<f7-col v-if="!createItem">
<f7-col v-if="!createMode">
<f7-list>
<item-picker key="itemLink" title="Item to Link" name="item" :value="selectedItemName" :multiple="false" :items="items" :filterType="getCompatibleItemTypes()"
@input="(value) => selectedItemName = value" />
Expand All @@ -43,7 +43,7 @@

<!-- Create new item -->
<f7-col v-else>
<item-form :item="newItem" :items="items" :createMode="true" @valid="itemValid = $event" />
<item-form :item="newItem" :items="items" :createMode="true" />
<f7-list>
<item-picker key="newItem-groups" title="Parent Group(s)" name="parent-groups" :value="newItem.groupNames" :items="items" @input="(value) => newItem.groupNames = value" :multiple="true" filterType="Group" />
</f7-list>
Expand Down Expand Up @@ -133,8 +133,10 @@ import ItemForm from '@/components/item/item-form.vue'
import Item from '@/components/item/item.vue'

import * as Types from '@/assets/item-types.js'
import ItemMixin from '@/components/item/item-mixin'

export default {
mixins: [ItemMixin],
components: {
ConfigSheet,
ItemPicker,
Expand All @@ -147,9 +149,8 @@ export default {
data () {
return {
ready: true,
createItem: false,
createMode: false,
items: null,
itemValid: true,
link: {
itemName: null,
channelUID: null,
Expand Down Expand Up @@ -178,7 +179,7 @@ export default {
},
computed: {
currentItem () {
return this.item ? this.item : this.createItem ? this.newItem : this.items ? this.items.find(item => item.name === this.selectedItemName) : null
return this.item ? this.item : this.createMode ? this.newItem : this.items ? this.items.find(item => item.name === this.selectedItemName) : null
},
compatibleProfileTypes () {
let currentItemType = this.currentItem && this.currentItem.type ? this.currentItem.type : ''
Expand Down Expand Up @@ -259,8 +260,8 @@ export default {
}

// checks
if (this.createItem && !this.itemValid) {
this.$f7.dialog.alert('Please correct the item to link')
if (this.createMode && this.validateItemName(this.newItem.name) !== '') {
this.$f7.dialog.alert('Please correct the newly created item')
return
}
if (!link.itemName) {
Expand All @@ -287,8 +288,8 @@ export default {
}
}

if (this.createItem) {
this.$oh.api.put('/rest/items/' + this.newItem.name, this.newItem).then((data) => {
if (this.createMode) {
this.saveItem(this.newItem).then((data) => {
this.$oh.api.put('/rest/links/' + link.itemName + '/' + encodeURIComponent(link.channelUID), link).then((data) => {
this.$f7.toast.create({
text: 'Item and link created',
Expand Down