diff --git a/src/components/home/contentAuth.vue b/src/components/home/contentAuth.vue
index cee4fadb..576d77bf 100644
--- a/src/components/home/contentAuth.vue
+++ b/src/components/home/contentAuth.vue
@@ -55,6 +55,7 @@ export default {
},
created() {
this.renewTokenOnFocus()
+ this.loadLabels()
},
computed: mapState({
namespaces(state) {
@@ -126,6 +127,12 @@ export default {
showKeyboardShortcuts() {
this.$store.commit(KEYBOARD_SHORTCUTS_ACTIVE, true)
},
+ loadLabels() {
+ this.$store.dispatch('labels/loadAllLabels')
+ .catch(e => {
+ this.error(e, this)
+ })
+ },
},
}
diff --git a/src/components/list/partials/filters.vue b/src/components/list/partials/filters.vue
index 478c4f0b..a28f339e 100644
--- a/src/components/list/partials/filters.vue
+++ b/src/components/list/partials/filters.vue
@@ -131,7 +131,6 @@
({
- altFormat: 'j M Y H:i',
- altInput: true,
- dateFormat: 'Y-m-d H:i',
- enableTime: true,
- time_24hr: true,
- mode: 'range',
- locale: {
- firstDayOfWeek: state.auth.settings.weekStart,
- },
- })
- }),
+ computed: {
+ foundLabels() {
+ const labels = (Object.values(this.$store.state.labels.labels).filter(l => {
+ return l.title.toLowerCase().includes(this.labelQuery.toLowerCase())
+ }) ?? [])
+
+ return differenceWith(labels, this.labels, (first, second) => {
+ return first.id === second.id
+ })
+ },
+ ...mapState({
+ flatPickerConfig: state => ({
+ altFormat: 'j M Y H:i',
+ altInput: true,
+ dateFormat: 'Y-m-d H:i',
+ enableTime: true,
+ time_24hr: true,
+ mode: 'range',
+ locale: {
+ firstDayOfWeek: state.auth.settings.weekStart,
+ },
+ }),
+ }),
+ },
methods: {
change() {
this.$emit('input', this.params)
@@ -566,25 +573,8 @@ export default {
this.$set(this.filters, filterName, ids.join(','))
this.setSingleValueFilter(filterName, filterName, '', 'in')
},
- clearLabels() {
- this.$set(this, 'foundLabels', [])
- },
findLabels(query) {
-
- if (query === '') {
- this.clearLabels()
- }
-
- this.labelService.getAll({}, {s: query})
- .then(response => {
- // Filter the results to not include labels already selected
- this.$set(this, 'foundLabels', differenceWith(response, this.labels, (first, second) => {
- return first.id === second.id
- }))
- })
- .catch(e => {
- this.error(e, this)
- })
+ this.labelQuery = query
},
addLabel() {
this.$nextTick(() => {
diff --git a/src/components/tasks/partials/editLabels.vue b/src/components/tasks/partials/editLabels.vue
index daf3271b..a40f2113 100644
--- a/src/components/tasks/partials/editLabels.vue
+++ b/src/components/tasks/partials/editLabels.vue
@@ -1,6 +1,6 @@
import differenceWith from 'lodash/differenceWith'
-import LabelService from '../../../services/label'
import LabelModel from '../../../models/label'
import LabelTaskService from '../../../services/labelTask'
import Multiselect from '@/components/input/multiselect'
+import {LOADING, LOADING_MODULE} from '@/store/mutation-types'
export default {
name: 'edit-labels',
@@ -62,12 +62,10 @@ export default {
},
data() {
return {
- labelService: LabelService,
labelTaskService: LabelTaskService,
- foundLabels: [],
labelTimeout: null,
labels: [],
- searchQuery: '',
+ query: '',
}
},
components: {
@@ -79,38 +77,26 @@ export default {
},
},
created() {
- this.labelService = new LabelService()
this.labelTaskService = new LabelTaskService()
this.labels = this.value
},
+ computed: {
+ foundLabels() {
+ const labels = (Object.values(this.$store.state.labels.labels).filter(l => {
+ return l.title.toLowerCase().includes(this.query.toLowerCase())
+ }) ?? [])
+
+ return differenceWith(labels, this.labels, (first, second) => {
+ return first.id === second.id
+ })
+ },
+ loading() {
+ return this.labelTaskService.loading || (this.$store.state[LOADING] && this.$store.state[LOADING_MODULE] === 'labels')
+ },
+ },
methods: {
findLabel(query) {
- this.searchQuery = query
- if (query === '') {
- this.clearAllLabels()
- return
- }
-
- if (this.labelTimeout !== null) {
- clearTimeout(this.labelTimeout)
- }
-
- // Delay the search 300ms to not send a request on every keystroke
- this.labelTimeout = setTimeout(() => {
- this.labelService.getAll({}, {s: query})
- .then(response => {
- this.$set(this, 'foundLabels', differenceWith(response, this.labels, (first, second) => {
- return first.id === second.id
- }))
- this.labelTimeout = null
- })
- .catch(e => {
- this.error(e, this)
- })
- }, 300)
- },
- clearAllLabels() {
- this.$set(this, 'foundLabels', [])
+ this.query = query
},
addLabel(label, showNotification = true) {
this.$store.dispatch('tasks/addLabel', {label: label, taskId: this.taskId})
@@ -141,8 +127,8 @@ export default {
})
},
createAndAddLabel(title) {
- let newLabel = new LabelModel({title: title})
- this.labelService.create(newLabel)
+ const newLabel = new LabelModel({title: title})
+ this.$store.dispatch('labels/createLabel', newLabel)
.then(r => {
this.addLabel(r, false)
this.labels.push(r)
@@ -156,7 +142,3 @@ export default {
},
}
-
-
\ No newline at end of file
diff --git a/src/store/index.js b/src/store/index.js
index 260d0270..dbe86067 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -17,6 +17,7 @@ import kanban from './modules/kanban'
import tasks from './modules/tasks'
import lists from './modules/lists'
import attachments from './modules/attachments'
+import labels from './modules/labels'
import ListService from '../services/list'
import {setTitle} from '@/helpers/setTitle'
@@ -32,6 +33,7 @@ export const store = new Vuex.Store({
tasks,
lists,
attachments,
+ labels,
},
state: {
loading: false,
diff --git a/src/store/modules/labels.js b/src/store/modules/labels.js
new file mode 100644
index 00000000..f8dde656
--- /dev/null
+++ b/src/store/modules/labels.js
@@ -0,0 +1,100 @@
+import LabelService from '@/services/label'
+import Vue from 'vue'
+import {setLoading} from '@/store/helper'
+
+export default {
+ namespaced: true,
+ // The state is an object which has the label ids as keys.
+ state: () => ({
+ labels: {},
+ loaded: false,
+ }),
+ mutations: {
+ setLabels(state, labels) {
+ labels.forEach(l => {
+ Vue.set(state.labels, l.id, l)
+ })
+ },
+ setLabel(state, label) {
+ Vue.set(state.labels, label.id, label)
+ },
+ removeLabelById(state, label) {
+ Vue.delete(state.labels, label.id)
+ },
+ setLoaded(state, loaded) {
+ state.loaded = loaded
+ },
+ },
+ actions: {
+ loadAllLabels(ctx, {forceLoad} = {}) {
+ if (ctx.state.loaded && !forceLoad) {
+ return Promise.resolve()
+ }
+
+ const cancel = setLoading(ctx, 'labels')
+ const labelService = new LabelService()
+
+ const getAllLabels = (page = 1) => {
+ return labelService.getAll({}, {}, page)
+ .then(labels => {
+ if (page < labelService.totalPages) {
+ return getAllLabels(page + 1)
+ .then(nextLabels => {
+ return labels.concat(nextLabels)
+ })
+ } else {
+ return labels
+ }
+ })
+ .catch(e => {
+ return Promise.reject(e)
+ })
+ }
+
+ return getAllLabels()
+ .then(r => {
+ ctx.commit('setLabels', r)
+ ctx.commit('setLoaded', true)
+ return Promise.resolve(r)
+ })
+ .catch(e => Promise.reject(e))
+ .finally(() => cancel())
+ },
+ deleteLabel(ctx, label) {
+ const cancel = setLoading(ctx, 'labels')
+ const labelService = new LabelService()
+
+ return labelService.delete(label)
+ .then(r => {
+ ctx.commit('removeLabelById', label)
+ return Promise.resolve(r)
+ })
+ .catch(e => Promise.reject(e))
+ .finally(() => cancel())
+ },
+ updateLabel(ctx, label) {
+ const cancel = setLoading(ctx, 'labels')
+ const labelService = new LabelService()
+
+ return labelService.update(label)
+ .then(r => {
+ ctx.commit('setLabel', r)
+ return Promise.resolve(r)
+ })
+ .catch(e => Promise.reject(e))
+ .finally(() => cancel())
+ },
+ createLabel(ctx, label) {
+ const cancel = setLoading(ctx, 'labels')
+ const labelService = new LabelService()
+
+ return labelService.create(label)
+ .then(r => {
+ ctx.commit('setLabel', r)
+ return Promise.resolve(r)
+ })
+ .catch(e => Promise.reject(e))
+ .finally(() => cancel())
+ },
+ },
+}
diff --git a/src/views/labels/ListLabels.vue b/src/views/labels/ListLabels.vue
index 21a5f504..ddeeca4a 100644
--- a/src/views/labels/ListLabels.vue
+++ b/src/views/labels/ListLabels.vue
@@ -1,5 +1,5 @@
-