From dbf9fd54becb4671d1e86803160f81b405fb3d42 Mon Sep 17 00:00:00 2001 From: Keith Holliday Date: Sat, 30 Sep 2017 21:49:00 -0500 Subject: [PATCH] Tasks tags (#9112) * Added auto apply and exit * Add challenge tag editing * Fixed lint --- website/client/components/tasks/user.vue | 50 +++++++++++++++-------- website/client/store/actions/user.js | 2 +- website/server/controllers/api-v3/user.js | 5 +-- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/website/client/components/tasks/user.vue b/website/client/components/tasks/user.vue index b5fdb8a257..a4d802386e 100644 --- a/website/client/components/tasks/user.vue +++ b/website/client/components/tasks/user.vue @@ -11,25 +11,25 @@ .col-4.offset-4 .input-group input.form-control.input-search(type="text", :placeholder="$t('search')", v-model="searchText") - .filter-panel(v-if="isFilterPanelOpen") + .filter-panel(v-if="isFilterPanelOpen", v-on:mouseleave="checkMouseOver") .tags-category.d-flex( - v-for="tagsType in tagsByType", + v-for="tagsType in tagsByType", v-if="tagsType.tags.length > 0 || tagsType.key === 'tags'", :key="tagsType.key" ) .tags-header strong(v-once) {{ $t(tagsType.key) }} - a.d-block(v-if="tagsType.key === 'tags' && !editingTags", @click="editTags()") {{ $t('editTags2') }} + a.d-block(v-if="tagsType.key !== 'groups' && !editingTags", @click="editTags(tagsType.key)") {{ $t('editTags2') }} .tags-list.container .row(:class="{'no-gutters': !editingTags}") - template(v-if="editingTags && tagsType.key === 'tags'") - .col-6(v-for="(tag, tagIndex) in tagsSnap") + template(v-if="editingTags && tagsType.key !== 'groups'") + .col-6(v-for="(tag, tagIndex) in tagsSnap[tagsType.key]") .inline-edit-input-group.tag-edit-item.input-group input.tag-edit-input.inline-edit-input.form-control(type="text", v-model="tag.name") - span.input-group-btn(@click="removeTag(tagIndex)") + span.input-group-btn(@click="removeTag(tagIndex, tagsType.key)") .svg-icon.destroy-icon(v-html="icons.destroy") - .col-6 - input.new-tag-item.edit-tag-item.inline-edit-input.form-control(type="text", :placeholder="$t('newTag')", @keydown.enter="addTag($event)", v-model="newTag") + .col-6(v-if="tagsType.key === 'tags'") + input.new-tag-item.edit-tag-item.inline-edit-input.form-control(type="text", :placeholder="$t('newTag')", @keydown.enter="addTag($event, tagsType.key)", v-model="newTag") template(v-else) .col-6(v-for="(tag, tagIndex) in tagsType.tags") label.custom-control.custom-checkbox @@ -50,7 +50,6 @@ .float-left a.btn-filters-danger(@click="resetFilters()", v-once) {{ $t('resetFilters') }} .float-right - a.mr-3.btn-filters-primary(@click="applyFilters()", v-once) {{ $t('applyFilters') }} a.btn-filters-secondary(@click="closeFilterPanel()", v-once) {{ $t('cancel') }} span.input-group-btn button.btn.btn-secondary.filter-button( @@ -322,7 +321,10 @@ export default { }), selectedTags: [], temporarilySelectedTags: [], - tagsSnap: null, // tags snapshot when being edited + tagsSnap: { + tags: [], + challenges: [], + }, // tags snapshot when being edited editingTags: false, newTag: null, editingTask: null, @@ -368,26 +370,37 @@ export default { }, methods: { ...mapActions({setUser: 'user:set'}), + checkMouseOver: throttle(function throttleSearch () { + this.closeFilterPanel(); + }, 250), editTags () { // clone the arrays being edited so that we can revert if needed - this.tagsSnap = this.tagsByType.user.tags.slice(); + this.tagsSnap.tags = this.tagsByType.user.tags.slice(); + this.tagsSnap.challenges = this.tagsByType.challenges.tags.slice(); this.editingTags = true; }, - addTag () { - this.tagsSnap.push({id: uuid.v4(), name: this.newTag}); + addTag (eventObj, key) { + this.tagsSnap[key].push({id: uuid.v4(), name: this.newTag}); this.newTag = null; }, - removeTag (index) { - this.tagsSnap.splice(index, 1); + removeTag (index, key) { + this.$delete(this.tagsSnap[key], index); }, saveTags () { if (this.newTag) this.addTag(); - this.setUser({tags: this.tagsSnap}); + + this.tagsByType.user.tags = this.tagsSnap.tags; + this.tagsByType.challenges.tags = this.tagsSnap.challenges; + + this.setUser({tags: this.tagsSnap.tags.concat(this.tagsSnap.challenges)}); this.cancelTagsEditing(); }, cancelTagsEditing () { this.editingTags = false; - this.tagsSnap = null; + this.tagsSnap = { + tags: [], + challenges: [], + }; this.newTag = null; }, editTask (task) { @@ -430,7 +443,6 @@ export default { applyFilters () { const temporarilySelectedTags = this.temporarilySelectedTags; this.selectedTags = temporarilySelectedTags.slice(); - this.closeFilterPanel(); }, toggleTag (tag) { const temporarilySelectedTags = this.temporarilySelectedTags; @@ -440,6 +452,8 @@ export default { } else { temporarilySelectedTags.splice(tagI, 1); } + + this.applyFilters(); }, isTagSelected (tag) { const tagId = tag.id; diff --git a/website/client/store/actions/user.js b/website/client/store/actions/user.js index ebcd3d05b6..8b0c7400c6 100644 --- a/website/client/store/actions/user.js +++ b/website/client/store/actions/user.js @@ -26,7 +26,7 @@ export async function set (store, changes) { if (key === 'tags') { // Keep challenge and group tags const oldTags = user.tags.filter(t => { - return t.group || t.challenge; + return t.group; }); user.tags = changes[key].concat(oldTags); diff --git a/website/server/controllers/api-v3/user.js b/website/server/controllers/api-v3/user.js index fab451ea38..f5fe843277 100644 --- a/website/server/controllers/api-v3/user.js +++ b/website/server/controllers/api-v3/user.js @@ -20,7 +20,6 @@ import { } from '../../libs/email'; import nconf from 'nconf'; import get from 'lodash/get'; -import { model as Tag } from '../../models/tag'; const TECH_ASSISTANCE_EMAIL = nconf.get('EMAILS:TECH_ASSISTANCE_EMAIL'); const DELETE_CONFIRMATION = 'DELETE'; @@ -305,7 +304,7 @@ api.updateUser = { // Keep challenge and group tags user.tags.forEach(t => { - if (t.group || t.challenge) { + if (t.group) { oldTags.push(t); } else { removedTagsIds.push(t.id); @@ -320,7 +319,7 @@ api.updateUser = { removedTagsIds.splice(oldI, 1); } - user.tags.push(Tag.sanitize(t)); + user.tags.push(t); }); // Remove from all the tasks