diff --git a/src/components/TagItem.vue b/src/components/TagItem.vue
index 862771d9cf..8f00736972 100644
--- a/src/components/TagItem.vue
+++ b/src/components/TagItem.vue
@@ -30,7 +30,9 @@
@@ -70,7 +72,7 @@ import IconEdit from 'vue-material-design-icons/PencilOutline.vue'
import DeleteIcon from 'vue-material-design-icons/TrashCanOutline.vue'
import logger from '../logger.js'
import useMainStore from '../store/mainStore.js'
-import { translateTagDisplayName } from '../util/tag.js'
+import { translateTagDisplayName, validateTag } from '../util/tag.js'
export default {
name: 'TagItem',
@@ -106,8 +108,10 @@ export default {
tagLabel: true,
tagInput: false,
showSaving: false,
+ currentTagName: '',
renameTagLabel: true,
renameTagInput: false,
+ errorMessage: '',
}
},
@@ -115,6 +119,12 @@ export default {
...mapStores(useMainStore),
},
+ watch: {
+ currentTagName() {
+ this.errorMessage = ''
+ },
+ },
+
methods: {
translateTagDisplayName,
deleteTag() {
@@ -141,6 +151,7 @@ export default {
this.renameTagLabel = false
this.renameTagInput = true
this.showSaving = false
+ this.currentTagName = this.tag.displayName
this.editColor = this.tag.color
},
@@ -150,20 +161,30 @@ export default {
this.showSaving = false
},
+ hasError() {
+ return this.errorMessage !== ''
+ },
+
async renameTag(tag, event) {
- this.renameTagInput = false
+ this.currentTagName = this.currentTagName.trim()
+
+ const otherTags = this.mainStore.getTags
+ const valid = validateTag(tag.id, this.currentTagName, otherTags)
+ if (valid !== true) {
+ this.errorMessage = valid
+ return
+ }
+
this.showSaving = false
- const displayName = event.target.querySelector('input[type=text]').value
+ this.errorMessage = ''
try {
await this.mainStore.updateTag({
tag,
- displayName,
+ displayName: this.currentTagName,
color: this.tag.color,
})
- this.renameTagLabel = true
- this.renameTagInput = false
- this.showSaving = false
+ this.closeEditTag()
} catch (error) {
showInfo(t('mail', 'An error occurred, unable to rename the tag.'))
logger.error('could not rename tag', { error })
diff --git a/src/components/TagModal.vue b/src/components/TagModal.vue
index acd7f13eec..877c82fa52 100644
--- a/src/components/TagModal.vue
+++ b/src/components/TagModal.vue
@@ -61,6 +61,7 @@ import DeleteTagModal from './DeleteTagModal.vue'
import TagItem from './TagItem.vue'
import logger from '../logger.js'
import useMainStore from '../store/mainStore.js'
+import { validateTag } from '../util/tag.js'
import { hiddenTags } from './tags.js'
function randomColor() {
@@ -99,8 +100,6 @@ export default {
tagLabel: true,
tagInput: false,
showSaving: false,
- renameTagLabel: true,
- renameTagInput: false,
deleteTagModal: false,
tagToDelete: null,
color: randomColor(),
@@ -161,19 +160,14 @@ export default {
return
}
- const displayName = event.target.querySelector('input[type=text]').value
- if (displayName.toLowerCase() in hiddenTags) {
- showError(this.t('mail', 'Tag name is a hidden system tag'))
- return
- }
- if (this.mainStore.getTags.some((tag) => tag.displayName === displayName)) {
- showError(this.t('mail', 'Tag already exists'))
- return
- }
- if (displayName.trim() === '') {
- showError(this.t('mail', 'Tag name cannot be empty'))
+ const displayName = event.target.querySelector('input[type=text]').value.trim()
+ const otherTags = this.mainStore.getTags
+ const valid = validateTag(null, displayName, otherTags)
+ if (valid !== true) {
+ showError(valid)
return
}
+
try {
await this.mainStore.createTag({
displayName,
@@ -188,49 +182,6 @@ export default {
}
},
- convertHex(color, opacity) {
- if (color.length === 4) {
- const r = parseInt(color.substring(1, 2), 16)
- const g = parseInt(color.substring(2, 3), 16)
- const b = parseInt(color.substring(3, 4), 16)
- return `rgba(${r}, ${g}, ${b}, ${opacity})`
- } else {
- const r = parseInt(color.substring(1, 3), 16)
- const g = parseInt(color.substring(3, 5), 16)
- const b = parseInt(color.substring(5, 7), 16)
- return `rgba(${r}, ${g}, ${b}, ${opacity})`
- }
- },
-
- openEditTag() {
- this.renameTagLabel = false
- this.renameTagInput = true
- this.showSaving = false
- },
-
- async renameTag(tag, event) {
- this.renameTagInput = false
- this.showSaving = false
- const displayName = event.target.querySelector('input[type=text]').value
-
- try {
- await this.mainStore.updateTag({
- tag,
- displayName,
- color: tag.color,
- })
- this.renameTagLabel = true
- this.renameTagInput = false
- this.showSaving = false
- } catch (error) {
- showInfo(t('mail', 'An error occurred, unable to rename the tag.'))
- logger.error('could not rename tag', { error })
- this.renameTagLabel = false
- this.renameTagInput = false
- this.showSaving = true
- }
- },
-
deleteTag(tag) {
this.tagToDelete = tag
this.deleteTagModal = true
diff --git a/src/util/tag.js b/src/util/tag.js
index 3312f0ca16..ba36264857 100644
--- a/src/util/tag.js
+++ b/src/util/tag.js
@@ -4,6 +4,7 @@
*/
import { translate as t } from '@nextcloud/l10n'
+import { hiddenTags } from '../components/tags.js'
import { FOLLOW_UP_TAG_LABEL } from '../store/constants.js'
/**
@@ -19,3 +20,21 @@ export function translateTagDisplayName(tag) {
return tag.displayName
}
+
+export function validateTag(tagId, tagName, otherTags) {
+ const testableDisplayName = tagName.toLowerCase().trim()
+
+ if (testableDisplayName === '') {
+ return t('mail', 'Tag name cannot be empty')
+ }
+
+ if (Object.keys(hiddenTags).some((tag) => tag.toLowerCase() === testableDisplayName)) {
+ return t('mail', 'Tag name is a hidden system tag')
+ }
+
+ if (otherTags.some((tag) => tagId !== tag.id && tag.displayName.toLowerCase() === testableDisplayName)) {
+ return t('mail', 'Tag already exists')
+ }
+
+ return true
+}