feat: port label store to pinia | pinia 1/9 (#2391)
Co-authored-by: Dominik Pschenitschni <mail@celement.de> Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/2391 Reviewed-by: konrad <k@knt.li> Co-authored-by: Dominik Pschenitschni <dpschen@noreply.kolaente.de> Co-committed-by: Dominik Pschenitschni <dpschen@noreply.kolaente.de>
This commit is contained in:

committed by
konrad

parent
e91b5fde02
commit
d67e5e386d
55
src/stores/labels.test.ts
Normal file
55
src/stores/labels.test.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import {setActivePinia, createPinia} from 'pinia'
|
||||
import {describe, it, expect, beforeEach} from 'vitest'
|
||||
|
||||
import {useLabelStore} from './labels'
|
||||
|
||||
import type { ILabel } from '@/modelTypes/ILabel'
|
||||
|
||||
const MOCK_LABELS = {
|
||||
1: {id: 1, title: 'label1'},
|
||||
2: {id: 2, title: 'label2'},
|
||||
3: {id: 3, title: 'label3'},
|
||||
4: {id: 4, title: 'label4'},
|
||||
5: {id: 5, title: 'label5'},
|
||||
6: {id: 6, title: 'label6'},
|
||||
7: {id: 7, title: 'label7'},
|
||||
8: {id: 8, title: 'label8'},
|
||||
9: {id: 9, title: 'label9'},
|
||||
}
|
||||
|
||||
function setupStore() {
|
||||
const store = useLabelStore()
|
||||
store.setLabels(Object.values(MOCK_LABELS) as ILabel[])
|
||||
return store
|
||||
}
|
||||
|
||||
describe('filter labels', () => {
|
||||
beforeEach(() => {
|
||||
// creates a fresh pinia and make it active so it's automatically picked
|
||||
// up by any useStore() call without having to pass it to it:
|
||||
// `useStore(pinia)`
|
||||
setActivePinia(createPinia())
|
||||
})
|
||||
|
||||
it('should return an empty array for an empty query', () => {
|
||||
const store = setupStore()
|
||||
const labels = store.filterLabelsByQuery([], '')
|
||||
|
||||
expect(labels).toHaveLength(0)
|
||||
})
|
||||
it('should return labels for a query', () => {
|
||||
const store = setupStore()
|
||||
const labels = store.filterLabelsByQuery([], 'label2')
|
||||
|
||||
expect(labels).toHaveLength(1)
|
||||
expect(labels[0].title).toBe('label2')
|
||||
})
|
||||
it('should not return found but hidden labels', () => {
|
||||
const store = setupStore()
|
||||
|
||||
const labelsToHide = [{id: 1, title: 'label1'}] as ILabel[]
|
||||
const labels = store.filterLabelsByQuery(labelsToHide, 'label1')
|
||||
|
||||
expect(labels).toHaveLength(0)
|
||||
})
|
||||
})
|
136
src/stores/labels.ts
Normal file
136
src/stores/labels.ts
Normal file
@ -0,0 +1,136 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
import LabelService from '@/services/label'
|
||||
import {success} from '@/message'
|
||||
import {i18n} from '@/i18n'
|
||||
import {createNewIndexer} from '@/indexes'
|
||||
import {setLoadingPinia} from '@/store/helper'
|
||||
import type {ILabel} from '@/modelTypes/ILabel'
|
||||
|
||||
const {add, remove, update, search} = createNewIndexer('labels', ['title', 'description'])
|
||||
|
||||
async function getAllLabels(page = 1): Promise<ILabel[]> {
|
||||
const labelService = new LabelService()
|
||||
const labels = await labelService.getAll({}, {}, page) as ILabel[]
|
||||
if (page < labelService.totalPages) {
|
||||
const nextLabels = await getAllLabels(page + 1)
|
||||
return labels.concat(nextLabels)
|
||||
} else {
|
||||
return labels
|
||||
}
|
||||
}
|
||||
|
||||
import type {LabelState} from '@/store/types'
|
||||
|
||||
export const useLabelStore = defineStore('label', {
|
||||
state: () : LabelState => ({
|
||||
// The labels are stored as an object which has the label ids as keys.
|
||||
labels: {},
|
||||
isLoading: false,
|
||||
}),
|
||||
|
||||
getters: {
|
||||
getLabelsByIds(state) {
|
||||
return (ids: ILabel['id'][]) => Object.values(state.labels).filter(({id}) => ids.includes(id))
|
||||
},
|
||||
// **
|
||||
// * Checks if a list of labels is available in the store and filters them then query
|
||||
// **
|
||||
filterLabelsByQuery(state) {
|
||||
return (labelsToHide: ILabel[], query: string) => {
|
||||
const labelIdsToHide: number[] = labelsToHide.map(({id}) => id)
|
||||
|
||||
return search(query)
|
||||
?.filter(value => !labelIdsToHide.includes(value))
|
||||
.map(id => state.labels[id])
|
||||
|| []
|
||||
}
|
||||
},
|
||||
getLabelsByExactTitles(state) {
|
||||
return (labelTitles: string[]) => Object
|
||||
.values(state.labels)
|
||||
.filter(({title}) => labelTitles.some(l => l.toLowerCase() === title.toLowerCase()))
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
setIsLoading(isLoading: boolean) {
|
||||
this.isLoading = isLoading
|
||||
},
|
||||
|
||||
setLabels(labels: ILabel[]) {
|
||||
labels.forEach(l => {
|
||||
this.labels[l.id] = l
|
||||
add(l)
|
||||
})
|
||||
},
|
||||
|
||||
setLabel(label: ILabel) {
|
||||
this.labels[label.id] = label
|
||||
update(label)
|
||||
},
|
||||
|
||||
removeLabelById(label: ILabel) {
|
||||
remove(label)
|
||||
delete this.labels[label.id]
|
||||
},
|
||||
|
||||
async loadAllLabels({forceLoad} : {forceLoad?: boolean} = {}) {
|
||||
if (this.isLoading && !forceLoad) {
|
||||
return
|
||||
}
|
||||
|
||||
const cancel = setLoadingPinia(useLabelStore)
|
||||
|
||||
try {
|
||||
const labels = await getAllLabels()
|
||||
this.setLabels(labels)
|
||||
this.setIsLoading(true)
|
||||
return labels
|
||||
} finally {
|
||||
cancel()
|
||||
}
|
||||
},
|
||||
|
||||
async deleteLabel(label: ILabel) {
|
||||
const cancel = setLoadingPinia(useLabelStore)
|
||||
const labelService = new LabelService()
|
||||
|
||||
try {
|
||||
const result = await labelService.delete(label)
|
||||
this.removeLabelById(label)
|
||||
success({message: i18n.global.t('label.deleteSuccess')})
|
||||
return result
|
||||
} finally {
|
||||
cancel()
|
||||
}
|
||||
},
|
||||
|
||||
async updateLabel(label: ILabel) {
|
||||
const cancel = setLoadingPinia(useLabelStore)
|
||||
const labelService = new LabelService()
|
||||
|
||||
try {
|
||||
const newLabel = await labelService.update(label)
|
||||
this.setLabel(newLabel)
|
||||
success({message: i18n.global.t('label.edit.success')})
|
||||
return newLabel
|
||||
} finally {
|
||||
cancel()
|
||||
}
|
||||
},
|
||||
|
||||
async createLabel(label: ILabel) {
|
||||
const cancel = setLoadingPinia(useLabelStore)
|
||||
const labelService = new LabelService()
|
||||
|
||||
try {
|
||||
const newLabel = await labelService.create(label)
|
||||
this.setLabel(newLabel)
|
||||
return newLabel
|
||||
} finally {
|
||||
cancel()
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
Reference in New Issue
Block a user