feat: port namespace store to pinia

This commit is contained in:
Dominik Pschenitschni 2022-09-02 11:15:29 +02:00
parent 9474240cb9
commit 093ab766d4
No known key found for this signature in database
GPG key ID: B257AC0149F43A77
21 changed files with 214 additions and 166 deletions

View file

@ -160,6 +160,7 @@ import type {IList} from '@/modelTypes/IList'
import type {INamespace} from '@/modelTypes/INamespace' import type {INamespace} from '@/modelTypes/INamespace'
import ColorBubble from '@/components/misc/colorBubble.vue' import ColorBubble from '@/components/misc/colorBubble.vue'
import {useListStore} from '@/stores/lists' import {useListStore} from '@/stores/lists'
import {useNamespaceStore} from '@/stores/namespaces'
const drag = ref(false) const drag = ref(false)
const dragOptions = { const dragOptions = {
@ -168,13 +169,14 @@ const dragOptions = {
} }
const store = useStore() const store = useStore()
const namespaceStore = useNamespaceStore()
const currentList = computed(() => store.state.currentList) const currentList = computed(() => store.state.currentList)
const menuActive = computed(() => store.state.menuActive) const menuActive = computed(() => store.state.menuActive)
const loading = computed(() => store.state.loading && store.state.loadingModule === 'namespaces') const loading = computed(() => namespaceStore.isLoading)
const namespaces = computed(() => { const namespaces = computed(() => {
return (store.state.namespaces.namespaces as INamespace[]).filter(n => !n.isArchived) return namespaceStore.namespaces.filter(n => !n.isArchived)
}) })
const activeLists = computed(() => { const activeLists = computed(() => {
return namespaces.value.map(({lists}) => { return namespaces.value.map(({lists}) => {
@ -210,7 +212,7 @@ function toggleLists(namespaceId: INamespace['id']) {
const listsVisible = ref<{ [id: INamespace['id']]: boolean }>({}) const listsVisible = ref<{ [id: INamespace['id']]: boolean }>({})
// FIXME: async action will be unfinished when component mounts // FIXME: async action will be unfinished when component mounts
onBeforeMount(async () => { onBeforeMount(async () => {
const namespaces = await store.dispatch('namespaces/loadNamespaces') as INamespace[] const namespaces = await namespaceStore.loadNamespaces()
namespaces.forEach(n => { namespaces.forEach(n => {
if (typeof listsVisible.value[n.id] === 'undefined') { if (typeof listsVisible.value[n.id] === 'undefined') {
listsVisible.value[n.id] = true listsVisible.value[n.id] = true
@ -229,7 +231,7 @@ function updateActiveLists(namespace: INamespace, activeLists: IList[]) {
...namespace.lists.filter(l => l.isArchived), ...namespace.lists.filter(l => l.isArchived),
] ]
store.commit('namespaces/setNamespaceById', { namespaceStore.setNamespaceById({
...namespace, ...namespace,
lists, lists,
}) })

View file

@ -19,12 +19,12 @@
<script lang="ts" setup> <script lang="ts" setup>
import {reactive, ref, watch} from 'vue' import {reactive, ref, watch} from 'vue'
import type {PropType} from 'vue' import type {PropType} from 'vue'
import {useStore} from '@/store'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import ListModel from '@/models/list' import ListModel from '@/models/list'
import type {IList} from '@/modelTypes/IList' import type {IList} from '@/modelTypes/IList'
import Multiselect from '@/components/input/multiselect.vue' import Multiselect from '@/components/input/multiselect.vue'
import {useListStore} from '@/stores/lists' import {useListStore} from '@/stores/lists'
import {useNamespaceStore} from '@/stores/namespaces'
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
@ -34,8 +34,6 @@ const props = defineProps({
}) })
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const store = useStore()
const listStore = useListStore()
const {t} = useI18n({useScope: 'global'}) const {t} = useI18n({useScope: 'global'})
const list: IList = reactive(new ListModel()) const list: IList = reactive(new ListModel())
@ -49,6 +47,8 @@ watch(
}, },
) )
const listStore = useListStore()
const namespaceStore = useNamespaceStore()
const foundLists = ref<IList[]>([]) const foundLists = ref<IList[]>([])
function findLists(query: string) { function findLists(query: string) {
if (query === '') { if (query === '') {
@ -66,7 +66,7 @@ function select(l: IList | null) {
} }
function namespace(namespaceId: number) { function namespace(namespaceId: number) {
const namespace = store.getters['namespaces/getNamespaceById'](namespaceId) const namespace = namespaceStore.getNamespaceById(namespaceId)
return namespace !== null return namespace !== null
? namespace.title ? namespace.title
: t('list.shared') : t('list.shared')

View file

@ -164,6 +164,8 @@ import BaseButton from '@/components/base/BaseButton.vue'
import Multiselect from '@/components/input/multiselect.vue' import Multiselect from '@/components/input/multiselect.vue'
import Fancycheckbox from '@/components/input/fancycheckbox.vue' import Fancycheckbox from '@/components/input/fancycheckbox.vue'
import {useNamespaceStore} from '@/stores/namespaces'
import {error, success} from '@/message' import {error, success} from '@/message'
const props = defineProps({ const props = defineProps({
@ -189,6 +191,7 @@ const props = defineProps({
}) })
const store = useStore() const store = useStore()
const namespaceStore = useNamespaceStore()
const route = useRoute() const route = useRoute()
const {t} = useI18n({useScope: 'global'}) const {t} = useI18n({useScope: 'global'})
@ -222,7 +225,7 @@ async function findTasks(newQuery: string) {
foundTasks.value = await taskService.getAll({}, {s: newQuery}) foundTasks.value = await taskService.getAll({}, {s: newQuery})
} }
const getListAndNamespaceById = (listId: number) => store.getters['namespaces/getListAndNamespaceById'](listId, true) const getListAndNamespaceById = (listId: number) => namespaceStore.getListAndNamespaceById(listId, true)
const namespace = computed(() => getListAndNamespaceById(props.listId)?.namespace) const namespace = computed(() => getListAndNamespaceById(props.listId)?.namespace)

View file

@ -118,6 +118,7 @@ import ChecklistSummary from './checklist-summary.vue'
import {formatDateSince, formatISO, formatDateLong} from '@/helpers/time/formatDate' import {formatDateSince, formatISO, formatDateLong} from '@/helpers/time/formatDate'
import ColorBubble from '@/components/misc/colorBubble.vue' import ColorBubble from '@/components/misc/colorBubble.vue'
import {useListStore} from '@/stores/lists' import {useListStore} from '@/stores/lists'
import {useNamespaceStore} from '@/stores/namespaces'
export default defineComponent({ export default defineComponent({
name: 'singleTaskInList', name: 'singleTaskInList',
@ -236,7 +237,8 @@ export default defineComponent({
this.task.isFavorite = !this.task.isFavorite this.task.isFavorite = !this.task.isFavorite
this.task = await this.taskService.update(this.task) this.task = await this.taskService.update(this.task)
this.$emit('task-updated', this.task) this.$emit('task-updated', this.task)
this.$store.dispatch('namespaces/loadNamespacesIfFavoritesDontExist') const namespaceStore = useNamespaceStore()
namespaceStore.loadNamespacesIfFavoritesDontExist()
}, },
hideDeferDueDatePopup(e) { hideDeferDueDatePopup(e) {
if (!this.showDefer) { if (!this.showDefer) {

View file

@ -1,11 +1,11 @@
import {ref, computed} from 'vue' import {ref, computed} from 'vue'
import {useStore} from '@/store' import {useNamespaceStore} from '@/stores/namespaces'
export function useNameSpaceSearch() { export function useNamespaceSearch() {
const query = ref('') const query = ref('')
const store = useStore() const namespaceStore = useNamespaceStore()
const namespaces = computed(() => store.getters['namespaces/searchNamespace'](query.value)) const namespaces = computed(() => namespaceStore.searchNamespace(query.value))
function findNamespaces(newQuery: string) { function findNamespaces(newQuery: string) {
query.value = newQuery query.value = newQuery

View file

@ -22,7 +22,7 @@ export default class SavedFilterModel extends AbstractModel<ISavedFilter> implem
created: Date = null created: Date = null
updated: Date = null updated: Date = null
constructor(data: Partial<ISavedFilter>) { constructor(data: Partial<ISavedFilter> = {}) {
super() super()
this.assignData(data) this.assignData(data)

View file

@ -103,6 +103,7 @@ export interface ListState {
export interface NamespaceState { export interface NamespaceState {
namespaces: INamespace[] namespaces: INamespace[]
isLoading: boolean,
} }
export interface TaskState {} export interface TaskState {}

View file

@ -6,7 +6,7 @@ import ListService from '@/services/list'
import {setLoadingPinia} from '@/store/helper' import {setLoadingPinia} from '@/store/helper'
import {removeListFromHistory} from '@/modules/listHistory' import {removeListFromHistory} from '@/modules/listHistory'
import {createNewIndexer} from '@/indexes' import {createNewIndexer} from '@/indexes'
import {store as vuexStore} from '@/store' // for gradual conversion, see fullUserDetails import {useNamespaceStore} from './namespaces'
import type {ListState} from '@/store/types' import type {ListState} from '@/store/types'
import type {IList} from '@/modelTypes/IList' import type {IList} from '@/modelTypes/IList'
@ -93,7 +93,8 @@ export const useListStore = defineStore('list', {
try { try {
const createdList = await listService.create(list) const createdList = await listService.create(list)
createdList.namespaceId = list.namespaceId createdList.namespaceId = list.namespaceId
vuexStore.commit('namespaces/addListToNamespace', createdList, {root: true}) const namespaceStore = useNamespaceStore()
namespaceStore.addListToNamespace(createdList)
this.setList(createdList) this.setList(createdList)
return createdList return createdList
} finally { } finally {
@ -108,7 +109,8 @@ export const useListStore = defineStore('list', {
try { try {
await listService.update(list) await listService.update(list)
this.setList(list) this.setList(list)
vuexStore.commit('namespaces/setListInNamespaceById', list, {root: true}) const namespaceStore = useNamespaceStore()
namespaceStore.setListInNamespaceById(list)
// the returned list from listService.update is the same! // the returned list from listService.update is the same!
// in order to not validate vuex mutations we have to create a new copy // in order to not validate vuex mutations we have to create a new copy
@ -117,12 +119,12 @@ export const useListStore = defineStore('list', {
namespaceId: FavoriteListsNamespace, namespaceId: FavoriteListsNamespace,
} }
if (list.isFavorite) { if (list.isFavorite) {
vuexStore.commit('namespaces/addListToNamespace', newList, {root: true}) namespaceStore.addListToNamespace(newList)
} else { } else {
vuexStore.commit('namespaces/removeListFromNamespaceById', newList, {root: true}) namespaceStore.removeListFromNamespaceById(newList)
} }
vuexStore.dispatch('namespaces/loadNamespacesIfFavoritesDontExist', null, {root: true}) namespaceStore.loadNamespacesIfFavoritesDontExist(null)
vuexStore.dispatch('namespaces/removeFavoritesNamespaceIfEmpty', null, {root: true}) namespaceStore.removeFavoritesNamespaceIfEmpty(null)
return newList return newList
} catch (e) { } catch (e) {
// Reset the list state to the initial one to avoid confusion for the user // Reset the list state to the initial one to avoid confusion for the user
@ -143,7 +145,8 @@ export const useListStore = defineStore('list', {
try { try {
const response = await listService.delete(list) const response = await listService.delete(list)
this.removeListById(list) this.removeListById(list)
vuexStore.commit('namespaces/removeListFromNamespaceById', list, {root: true}) const namespaceStore = useNamespaceStore()
namespaceStore.removeListFromNamespaceById(list)
removeListFromHistory({id: list.id}) removeListFromHistory({id: list.id})
return response return response
} finally { } finally {

View file

@ -1,93 +1,21 @@
import type { Module } from 'vuex' import {defineStore, acceptHMRUpdate} from 'pinia'
import NamespaceService from '../services/namespace' import NamespaceService from '../services/namespace'
import {setLoading} from '@/store/helper' import {setLoadingPinia} from '@/store/helper'
import {createNewIndexer} from '@/indexes' import {createNewIndexer} from '@/indexes'
import type {NamespaceState, RootStoreState} from '@/store/types' import type {NamespaceState} from '@/store/types'
import type {INamespace} from '@/modelTypes/INamespace' import type {INamespace} from '@/modelTypes/INamespace'
import type {IList} from '@/modelTypes/IList' import type {IList} from '@/modelTypes/IList'
import {useListStore} from '@/stores/lists' import {useListStore} from '@/stores/lists'
const {add, remove, search, update} = createNewIndexer('namespaces', ['title', 'description']) const {add, remove, search, update} = createNewIndexer('namespaces', ['title', 'description'])
const namespacesStore : Module<NamespaceState, RootStoreState> = { export const useNamespaceStore = defineStore('namespace', {
namespaced: true, state: (): NamespaceState => ({
state: () => ({ isLoading: false,
// FIXME: should be object with id as key
namespaces: [], namespaces: [],
}), }),
mutations: {
namespaces(state, namespaces: INamespace[]) {
state.namespaces = namespaces
namespaces.forEach(n => {
add(n)
})
},
setNamespaceById(state, namespace: INamespace) {
const namespaceIndex = state.namespaces.findIndex(n => n.id === namespace.id)
if (namespaceIndex === -1) {
return
}
if (!namespace.lists || namespace.lists.length === 0) {
namespace.lists = state.namespaces[namespaceIndex].lists
}
state.namespaces[namespaceIndex] = namespace
update(namespace)
},
setListInNamespaceById(state, list: IList) {
for (const n in state.namespaces) {
// We don't have the namespace id on the list which means we need to loop over all lists until we find it.
// FIXME: Not ideal at all - we should fix that at the api level.
if (state.namespaces[n].id === list.namespaceId) {
for (const l in state.namespaces[n].lists) {
if (state.namespaces[n].lists[l].id === list.id) {
const namespace = state.namespaces[n]
namespace.lists[l] = list
state.namespaces[n] = namespace
return
}
}
}
}
},
addNamespace(state, namespace: INamespace) {
state.namespaces.push(namespace)
add(namespace)
},
removeNamespaceById(state, namespaceId: INamespace['id']) {
for (const n in state.namespaces) {
if (state.namespaces[n].id === namespaceId) {
remove(state.namespaces[n])
state.namespaces.splice(n, 1)
return
}
}
},
addListToNamespace(state, list: IList) {
for (const n in state.namespaces) {
if (state.namespaces[n].id === list.namespaceId) {
state.namespaces[n].lists.push(list)
return
}
}
},
removeListFromNamespaceById(state, list: IList) {
for (const n in state.namespaces) {
// We don't have the namespace id on the list which means we need to loop over all lists until we find it.
// FIXME: Not ideal at all - we should fix that at the api level.
if (state.namespaces[n].id === list.namespaceId) {
for (const l in state.namespaces[n].lists) {
if (state.namespaces[n].lists[l].id === list.id) {
state.namespaces[n].lists.splice(l, 1)
return
}
}
}
}
},
},
getters: { getters: {
getListAndNamespaceById: (state) => (listId: IList['id'], ignorePseudoNamespaces = false) => { getListAndNamespaceById: (state) => (listId: IList['id'], ignorePseudoNamespaces = false) => {
for (const n in state.namespaces) { for (const n in state.namespaces) {
@ -107,26 +35,113 @@ const namespacesStore : Module<NamespaceState, RootStoreState> = {
} }
return null return null
}, },
getNamespaceById: (state) => (namespaceId: INamespace['id']) => {
getNamespaceById: state => (namespaceId: INamespace['id']) => {
return state.namespaces.find(({id}) => id == namespaceId) || null return state.namespaces.find(({id}) => id == namespaceId) || null
}, },
searchNamespace: (state, getters) => (query: string) => {
return search(query) searchNamespace() {
return (query: string) => (
search(query)
?.filter(value => value > 0) ?.filter(value => value > 0)
.map(getters.getNamespaceById) .map(this.getNamespaceById)
.filter(n => n !== null) .filter(n => n !== null)
|| [] || []
)
}, },
}, },
actions: { actions: {
async loadNamespaces(ctx) { setIsLoading(isLoading: boolean) {
const cancel = setLoading(ctx, 'namespaces') this.isLoading = isLoading
},
setNamespaces(namespaces: INamespace[]) {
this.namespaces = namespaces
namespaces.forEach(n => {
add(n)
})
},
setNamespaceById(namespace: INamespace) {
const namespaceIndex = this.namespaces.findIndex(n => n.id === namespace.id)
if (namespaceIndex === -1) {
return
}
if (!namespace.lists || namespace.lists.length === 0) {
namespace.lists = this.namespaces[namespaceIndex].lists
}
this.namespaces[namespaceIndex] = namespace
update(namespace)
},
setListInNamespaceById(list: IList) {
for (const n in this.namespaces) {
// We don't have the namespace id on the list which means we need to loop over all lists until we find it.
// FIXME: Not ideal at all - we should fix that at the api level.
if (this.namespaces[n].id === list.namespaceId) {
for (const l in this.namespaces[n].lists) {
if (this.namespaces[n].lists[l].id === list.id) {
const namespace = this.namespaces[n]
namespace.lists[l] = list
this.namespaces[n] = namespace
return
}
}
}
}
},
addNamespace(namespace: INamespace) {
this.namespaces.push(namespace)
add(namespace)
},
removeNamespaceById(namespaceId: INamespace['id']) {
for (const n in this.namespaces) {
if (this.namespaces[n].id === namespaceId) {
remove(this.namespaces[n])
this.namespaces.splice(n, 1)
return
}
}
},
addListToNamespace(list: IList) {
for (const n in this.namespaces) {
if (this.namespaces[n].id === list.namespaceId) {
this.namespaces[n].lists.push(list)
return
}
}
},
removeListFromNamespaceById(list: IList) {
for (const n in this.namespaces) {
// We don't have the namespace id on the list which means we need to loop over all lists until we find it.
// FIXME: Not ideal at all - we should fix that at the api level.
if (this.namespaces[n].id === list.namespaceId) {
for (const l in this.namespaces[n].lists) {
if (this.namespaces[n].lists[l].id === list.id) {
this.namespaces[n].lists.splice(l, 1)
return
}
}
}
}
},
async loadNamespaces() {
const cancel = setLoadingPinia(this)
const namespaceService = new NamespaceService() const namespaceService = new NamespaceService()
try { try {
// We always load all namespaces and filter them on the frontend // We always load all namespaces and filter them on the frontend
const namespaces = await namespaceService.getAll({}, {is_archived: true}) const namespaces = await namespaceService.getAll({}, {is_archived: true}) as INamespace[]
ctx.commit('namespaces', namespaces) this.setNamespaces(namespaces)
// Put all lists in the list state // Put all lists in the list state
const lists = namespaces.flatMap(({lists}) => lists) const lists = namespaces.flatMap(({lists}) => lists)
@ -140,45 +155,49 @@ const namespacesStore : Module<NamespaceState, RootStoreState> = {
} }
}, },
loadNamespacesIfFavoritesDontExist(ctx) { loadNamespacesIfFavoritesDontExist() {
// The first or second namespace should be the one holding all favorites // The first or second namespace should be the one holding all favorites
if (ctx.state.namespaces[0].id !== -2 && ctx.state.namespaces[1]?.id !== -2) { if (this.namespaces[0].id === -2 || this.namespaces[1]?.id === -2) {
return ctx.dispatch('loadNamespaces') return
}
return this.loadNamespaces()
},
removeFavoritesNamespaceIfEmpty() {
if (this.namespaces[0].id === -2 && this.namespaces[0].lists.length === 0) {
this.namespaces.splice(0, 1)
} }
}, },
removeFavoritesNamespaceIfEmpty(ctx) { async deleteNamespace(namespace: INamespace) {
if (ctx.state.namespaces[0].id === -2 && ctx.state.namespaces[0].lists.length === 0) { const cancel = setLoadingPinia(this)
ctx.state.namespaces.splice(0, 1)
}
},
async deleteNamespace(ctx, namespace: INamespace) {
const cancel = setLoading(ctx, 'namespaces')
const namespaceService = new NamespaceService() const namespaceService = new NamespaceService()
try { try {
const response = await namespaceService.delete(namespace) const response = await namespaceService.delete(namespace)
ctx.commit('removeNamespaceById', namespace.id) this.removeNamespaceById(namespace.id)
return response return response
} finally { } finally {
cancel() cancel()
} }
}, },
async createNamespace(ctx, namespace: INamespace) { async createNamespace(namespace: INamespace) {
const cancel = setLoading(ctx, 'namespaces') const cancel = setLoadingPinia(this)
const namespaceService = new NamespaceService() const namespaceService = new NamespaceService()
try { try {
const createdNamespace = await namespaceService.create(namespace) const createdNamespace = await namespaceService.create(namespace)
ctx.commit('addNamespace', createdNamespace) this.addNamespace(createdNamespace)
return createdNamespace return createdNamespace
} finally { } finally {
cancel() cancel()
} }
}, },
}, },
} })
export default namespacesStore // support hot reloading
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useNamespaceStore, import.meta.hot))
}

View file

@ -72,10 +72,12 @@ import {parseDateOrNull} from '@/helpers/parseDateOrNull'
import {formatDateShort, formatDateSince} from '@/helpers/time/formatDate' import {formatDateShort, formatDateSince} from '@/helpers/time/formatDate'
import {useDateTimeSalutation} from '@/composables/useDateTimeSalutation' import {useDateTimeSalutation} from '@/composables/useDateTimeSalutation'
import {useListStore} from '@/stores/lists' import {useListStore} from '@/stores/lists'
import {useNamespaceStore} from '@/stores/namespaces'
const welcome = useDateTimeSalutation() const welcome = useDateTimeSalutation()
const store = useStore() const store = useStore()
const namespaceStore = useNamespaceStore()
const listStore = useListStore() const listStore = useListStore()
const listHistory = computed(() => { const listHistory = computed(() => {
// If we don't check this, it tries to load the list background right after logging out // If we don't check this, it tries to load the list background right after logging out
@ -92,8 +94,8 @@ const migratorsEnabled = computed(() => store.state.config.availableMigrators?.l
const userInfo = computed(() => store.state.auth.info) const userInfo = computed(() => store.state.auth.info)
const hasTasks = computed(() => store.state.hasTasks) const hasTasks = computed(() => store.state.hasTasks)
const defaultListId = computed(() => store.state.auth.settings.defaultListId) const defaultListId = computed(() => store.state.auth.settings.defaultListId)
const defaultNamespaceId = computed(() => store.state.namespaces.namespaces?.[0]?.id || 0) const defaultNamespaceId = computed(() => namespaceStore.namespaces?.[0]?.id || 0)
const hasLists = computed(() => store.state.namespaces.namespaces?.[0]?.lists.length > 0) const hasLists = computed(() => namespaceStore.namespaces?.[0]?.lists.length > 0)
const loading = computed(() => store.state.loading && store.state.loadingModule === 'tasks') const loading = computed(() => store.state.loading && store.state.loadingModule === 'tasks')
const deletionScheduledAt = computed(() => parseDateOrNull(store.state.auth.info?.deletionScheduledAt)) const deletionScheduledAt = computed(() => parseDateOrNull(store.state.auth.info?.deletionScheduledAt))

View file

@ -12,7 +12,6 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { store } from '@/store'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import {success} from '@/message' import {success} from '@/message'
@ -20,10 +19,12 @@ import {success} from '@/message'
import SavedFilterModel from '@/models/savedFilter' import SavedFilterModel from '@/models/savedFilter'
import SavedFilterService from '@/services/savedFilter' import SavedFilterService from '@/services/savedFilter'
import {getSavedFilterIdFromListId} from '@/helpers/savedFilter' import {getSavedFilterIdFromListId} from '@/helpers/savedFilter'
import {useNamespaceStore} from '@/stores/namespaces'
const { t } = useI18n({useScope: 'global'}) const { t } = useI18n({useScope: 'global'})
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
const namespaceStore = useNamespaceStore()
async function deleteSavedFilter() { async function deleteSavedFilter() {
// We assume the listId in the route is the pseudolist // We assume the listId in the route is the pseudolist
@ -33,7 +34,7 @@ async function deleteSavedFilter() {
const filter = new SavedFilterModel({id: savedFilterId}) const filter = new SavedFilterModel({id: savedFilterId})
await filterService.delete(filter) await filterService.delete(filter)
await store.dispatch('namespaces/loadNamespaces') await namespaceStore.loadNamespaces()
success({message: t('filters.delete.success')}) success({message: t('filters.delete.success')})
router.push({name: 'namespaces.index'}) router.push({name: 'namespaces.index'})
} }

View file

@ -54,7 +54,6 @@
<script setup lang="ts"> <script setup lang="ts">
import {ref, shallowRef, computed, watch, unref } from 'vue' import {ref, shallowRef, computed, watch, unref } from 'vue'
import {useRouter, useRoute} from 'vue-router' import {useRouter, useRoute} from 'vue-router'
import {store} from '@/store'
import {success} from '@/message' import {success} from '@/message'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import type {MaybeRef} from '@vueuse/core' import type {MaybeRef} from '@vueuse/core'
@ -69,8 +68,10 @@ import SavedFilterService from '@/services/savedFilter'
import {objectToSnakeCase} from '@/helpers/case' import {objectToSnakeCase} from '@/helpers/case'
import {getSavedFilterIdFromListId} from '@/helpers/savedFilter' import {getSavedFilterIdFromListId} from '@/helpers/savedFilter'
import type {IList} from '@/modelTypes/IList' import type {IList} from '@/modelTypes/IList'
import {useNamespaceStore} from '@/stores/namespaces'
const {t} = useI18n({useScope: 'global'}) const {t} = useI18n({useScope: 'global'})
const namespaceStore = useNamespaceStore()
function useSavedFilter(listId: MaybeRef<IList['id']>) { function useSavedFilter(listId: MaybeRef<IList['id']>) {
const filterService = shallowRef(new SavedFilterService()) const filterService = shallowRef(new SavedFilterService())
@ -97,7 +98,7 @@ function useSavedFilter(listId: MaybeRef<IList['id']>) {
async function save() { async function save() {
filter.value.filters = filters.value filter.value.filters = filters.value
const response = await filterService.value.update(filter.value) const response = await filterService.value.update(filter.value)
await store.dispatch('namespaces/loadNamespaces') await namespaceStore.loadNamespaces()
success({message: t('filters.edit.success')}) success({message: t('filters.edit.success')})
response.filters = objectToSnakeCase(response.filters) response.filters = objectToSnakeCase(response.filters)
filter.value = response filter.value = response

View file

@ -65,7 +65,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, shallowRef, computed } from 'vue' import { ref, shallowRef, computed } from 'vue'
import { store } from '@/store'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import {default as Editor} from '@/components/input/AsyncEditor' import {default as Editor} from '@/components/input/AsyncEditor'
@ -73,6 +72,9 @@ import Filters from '@/components/list/partials/filters.vue'
import SavedFilterService from '@/services/savedFilter' import SavedFilterService from '@/services/savedFilter'
import SavedFilterModel from '@/models/savedFilter' import SavedFilterModel from '@/models/savedFilter'
import {useNamespaceStore} from '@/stores/namespaces'
const namespaceStore = useNamespaceStore()
const savedFilterService = shallowRef(new SavedFilterService()) const savedFilterService = shallowRef(new SavedFilterService())
@ -85,7 +87,7 @@ const filters = computed({
const router = useRouter() const router = useRouter()
async function create() { async function create() {
savedFilter.value = await savedFilterService.value.create(savedFilter.value) savedFilter.value = await savedFilterService.value.create(savedFilter.value)
await store.dispatch('namespaces/loadNamespaces') await namespaceStore.loadNamespaces()
router.push({name: 'list.index', params: {listId: savedFilter.value.getListId()}}) router.push({name: 'list.index', params: {listId: savedFilter.value.getListId()}})
} }
</script> </script>

View file

@ -22,7 +22,6 @@
<script setup lang="ts"> <script setup lang="ts">
import {ref, shallowReactive} from 'vue' import {ref, shallowReactive} from 'vue'
import {useRoute, useRouter} from 'vue-router' import {useRoute, useRouter} from 'vue-router'
import {useStore} from '@/store'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import ListDuplicateService from '@/services/listDuplicateService' import ListDuplicateService from '@/services/listDuplicateService'
@ -34,8 +33,9 @@ import type {INamespace} from '@/modelTypes/INamespace'
import {success} from '@/message' import {success} from '@/message'
import {useTitle} from '@/composables/useTitle' import {useTitle} from '@/composables/useTitle'
import {useNameSpaceSearch} from '@/composables/useNamespaceSearch' import {useNamespaceSearch} from '@/composables/useNamespaceSearch'
import {useListStore} from '@/stores/lists' import {useListStore} from '@/stores/lists'
import {useNamespaceStore} from '@/stores/namespaces'
const {t} = useI18n({useScope: 'global'}) const {t} = useI18n({useScope: 'global'})
useTitle(() => t('list.duplicate.title')) useTitle(() => t('list.duplicate.title'))
@ -43,7 +43,7 @@ useTitle(() => t('list.duplicate.title'))
const { const {
namespaces, namespaces,
findNamespaces, findNamespaces,
} = useNameSpaceSearch() } = useNamespaceSearch()
const selectedNamespace = ref<INamespace>() const selectedNamespace = ref<INamespace>()
@ -53,8 +53,8 @@ function selectNamespace(namespace: INamespace) {
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const store = useStore()
const listStore = useListStore() const listStore = useListStore()
const namespaceStore = useNamespaceStore()
const listDuplicateService = shallowReactive(new ListDuplicateService()) const listDuplicateService = shallowReactive(new ListDuplicateService())
@ -67,7 +67,7 @@ async function duplicateList() {
const duplicate = await listDuplicateService.create(listDuplicate) const duplicate = await listDuplicateService.create(listDuplicate)
store.commit('namespaces/addListToNamespace', duplicate.list) namespaceStore.addListToNamespace(duplicate.list)
listStore.setList(duplicate.list) listStore.setList(duplicate.list)
success({message: t('list.duplicate.success')}) success({message: t('list.duplicate.success')})
router.push({name: 'list.index', params: {listId: duplicate.list.id}}) router.push({name: 'list.index', params: {listId: duplicate.list.id}})

View file

@ -77,6 +77,7 @@ import { setTitle } from '@/helpers/setTitle'
import {formatDateLong} from '@/helpers/time/formatDate' import {formatDateLong} from '@/helpers/time/formatDate'
import {MIGRATORS} from './migrators' import {MIGRATORS} from './migrators'
import { useNamespaceStore } from '@/stores/namespaces'
const PROGRESS_DOTS_COUNT = 8 const PROGRESS_DOTS_COUNT = 8
@ -171,7 +172,8 @@ export default defineComponent({
try { try {
const {message} = await this.migrationService.migrate(migrationConfig) const {message} = await this.migrationService.migrate(migrationConfig)
this.message = message this.message = message
return this.$store.dispatch('namespaces/loadNamespaces') const namespaceStore = useNamespaceStore()
return namespaceStore.loadNamespaces()
} finally { } finally {
this.isMigrating = false this.isMigrating = false
} }

View file

@ -79,17 +79,19 @@ import ListCard from '@/components/list/partials/list-card.vue'
import {getNamespaceTitle} from '@/helpers/getNamespaceTitle' import {getNamespaceTitle} from '@/helpers/getNamespaceTitle'
import {useTitle} from '@/composables/useTitle' import {useTitle} from '@/composables/useTitle'
import {useStorage} from '@vueuse/core' import {useStorage} from '@vueuse/core'
import {useNamespaceStore} from '@/stores/namespaces'
const {t} = useI18n() const {t} = useI18n()
const store = useStore() const store = useStore()
const namespaceStore = useNamespaceStore()
useTitle(() => t('namespace.title')) useTitle(() => t('namespace.title'))
const showArchived = useStorage('showArchived', false) const showArchived = useStorage('showArchived', false)
const loading = computed(() => store.state.loading) const loading = computed(() => store.state.loading)
const namespaces = computed(() => { const namespaces = computed(() => {
return store.state.namespaces.namespaces.filter(n => showArchived.value ? true : !n.isArchived) return namespaceStore.namespaces.filter(n => showArchived.value ? true : !n.isArchived)
// return store.state.namespaces.namespaces.filter(n => showArchived.value ? true : !n.isArchived).map(n => { // return namespaceStore.namespaces.filter(n => showArchived.value ? true : !n.isArchived).map(n => {
// n.lists = n.lists.filter(l => !l.isArchived) // n.lists = n.lists.filter(l => !l.isArchived)
// return n // return n
// }) // })

View file

@ -49,6 +49,7 @@ import NamespaceService from '../../services/namespace'
import CreateEdit from '@/components/misc/create-edit.vue' import CreateEdit from '@/components/misc/create-edit.vue'
import ColorPicker from '../../components/input/colorPicker.vue' import ColorPicker from '../../components/input/colorPicker.vue'
import { setTitle } from '@/helpers/setTitle' import { setTitle } from '@/helpers/setTitle'
import {useNamespaceStore} from '@/stores/namespaces'
export default defineComponent({ export default defineComponent({
name: 'NewNamespace', name: 'NewNamespace',
@ -76,7 +77,8 @@ export default defineComponent({
this.showError = false this.showError = false
const namespace = await this.namespaceService.create(this.namespace) const namespace = await this.namespaceService.create(this.namespace)
this.$store.commit('namespaces/addNamespace', namespace) const namespaceStore = useNamespaceStore()
namespaceStore.addNamespace(namespace)
this.$message.success({message: this.$t('namespace.create.success')}) this.$message.success({message: this.$t('namespace.create.success')})
this.$router.back() this.$router.back()
}, },

View file

@ -22,35 +22,36 @@ export default { name: 'namespace-setting-archive' }
</script> </script>
<script setup lang="ts"> <script setup lang="ts">
import {watch, ref, computed, shallowReactive} from 'vue' import {watch, ref, computed, shallowReactive, type PropType} from 'vue'
import {useRouter} from 'vue-router' import {useRouter} from 'vue-router'
import {useStore} from '@/store'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import {success} from '@/message' import {success} from '@/message'
import {useTitle} from '@/composables/useTitle' import {useTitle} from '@/composables/useTitle'
import {useNamespaceStore} from '@/stores/namespaces'
import NamespaceService from '@/services/namespace' import NamespaceService from '@/services/namespace'
import NamespaceModel from '@/models/namespace' import NamespaceModel from '@/models/namespace'
import type {INamespace} from '@/modelTypes/INamespace'
const props = defineProps({ const props = defineProps({
namespaceId: { namespaceId: {
type: Number, type: Number as PropType<INamespace['id']>,
required: true, required: true,
}, },
}) })
const store = useStore()
const router = useRouter() const router = useRouter()
const {t} = useI18n({useScope: 'global'}) const {t} = useI18n({useScope: 'global'})
const namespaceStore = useNamespaceStore()
const namespaceService = shallowReactive(new NamespaceService()) const namespaceService = shallowReactive(new NamespaceService())
const namespace = ref(new NamespaceModel()) const namespace = ref<INamespace>(new NamespaceModel())
watch( watch(
() => props.namespaceId, () => props.namespaceId,
async () => { async () => {
namespace.value = store.getters['namespaces/getNamespaceById'](props.namespaceId) namespace.value = namespaceStore.getNamespaceById(props.namespaceId) || new NamespaceModel()
// FIXME: ressouce should be loaded in store // FIXME: ressouce should be loaded in store
namespace.value = await namespaceService.get({id: props.namespaceId}) namespace.value = await namespaceService.get({id: props.namespaceId})
@ -75,7 +76,7 @@ async function archiveNamespace() {
...namespace.value, ...namespace.value,
isArchived, isArchived,
}) })
store.commit('namespaces/setNamespaceById', archivedNamespace) namespaceStore.setNamespaceById(archivedNamespace)
success({ success({
message: isArchived message: isArchived
? t('namespace.archive.success') ? t('namespace.archive.success')

View file

@ -21,11 +21,12 @@ import {ref, computed, watch, shallowReactive} from 'vue'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import {useRouter} from 'vue-router' import {useRouter} from 'vue-router'
import {useStore} from '@/store'
import {useTitle} from '@/composables/useTitle' import {useTitle} from '@/composables/useTitle'
import {success} from '@/message' import {success} from '@/message'
import {useNamespaceStore} from '@/stores/namespaces'
import NamespaceModel from '@/models/namespace' import NamespaceModel from '@/models/namespace'
import NamespaceService from '@/services/namespace' import NamespaceService from '@/services/namespace'
import type { INamespace } from '@/modelTypes/INamespace'
const props = defineProps({ const props = defineProps({
namespaceId: { namespaceId: {
@ -34,17 +35,17 @@ const props = defineProps({
}, },
}) })
const store = useStore()
const router = useRouter()
const {t} = useI18n({useScope: 'global'}) const {t} = useI18n({useScope: 'global'})
const router = useRouter()
const namespaceStore = useNamespaceStore()
const namespaceService = shallowReactive(new NamespaceService()) const namespaceService = shallowReactive(new NamespaceService())
const namespace = ref(new NamespaceModel()) const namespace = ref<INamespace>(new NamespaceModel())
watch( watch(
() => props.namespaceId, () => props.namespaceId,
async () => { async () => {
namespace.value = store.getters['namespaces/getNamespaceById'](props.namespaceId) namespace.value = namespaceStore.getNamespaceById(props.namespaceId) || new NamespaceModel()
// FIXME: ressouce should be loaded in store // FIXME: ressouce should be loaded in store
namespace.value = await namespaceService.get({id: props.namespaceId}) namespace.value = await namespaceService.get({id: props.namespaceId})
@ -61,7 +62,7 @@ const title = computed(() => {
useTitle(title) useTitle(title)
async function deleteNamespace() { async function deleteNamespace() {
await store.dispatch('namespaces/deleteNamespace', namespace.value) await namespaceStore.deleteNamespace(namespace.value)
success({message: t('namespace.delete.success')}) success({message: t('namespace.delete.success')})
router.push({name: 'home'}) router.push({name: 'home'})
} }

View file

@ -57,7 +57,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import {nextTick, ref, watch} from 'vue' import {nextTick, ref, watch} from 'vue'
import {useStore} from '@/store'
import {success} from '@/message' import {success} from '@/message'
import router from '@/router' import router from '@/router'
@ -70,9 +69,10 @@ import NamespaceService from '@/services/namespace'
import NamespaceModel from '@/models/namespace' import NamespaceModel from '@/models/namespace'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import {useTitle} from '@/composables/useTitle' import {useTitle} from '@/composables/useTitle'
import {useNamespaceStore} from '@/stores/namespaces'
const {t} = useI18n({useScope: 'global'}) const {t} = useI18n({useScope: 'global'})
const store = useStore() const namespaceStore = useNamespaceStore()
const namespaceService = ref(new NamespaceService()) const namespaceService = ref(new NamespaceService())
const namespace = ref(new NamespaceModel()) const namespace = ref(new NamespaceModel())
@ -111,7 +111,7 @@ async function loadNamespace() {
async function save() { async function save() {
const updatedNamespace = await namespaceService.value.update(namespace.value) const updatedNamespace = await namespaceService.value.update(namespace.value)
// Update the namespace in the parent // Update the namespace in the parent
store.commit('namespaces/setNamespaceById', updatedNamespace) namespaceStore.setNamespaceById(updatedNamespace)
success({message: t('namespace.edit.success')}) success({message: t('namespace.edit.success')})
router.back() router.back()
} }

View file

@ -460,8 +460,9 @@ import CreatedUpdated from '@/components/tasks/partials/createdUpdated.vue'
import { setTitle } from '@/helpers/setTitle' import { setTitle } from '@/helpers/setTitle'
import {getNamespaceTitle} from '@/helpers/getNamespaceTitle' import {getNamespaceTitle} from '@/helpers/getNamespaceTitle'
import {getListTitle} from '@/helpers/getListTitle' import {getListTitle} from '@/helpers/getListTitle'
import type { IList } from '@/modelTypes/IList' import type {IList} from '@/modelTypes/IList'
import {colorIsDark} from '@/helpers/color/colorIsDark' import {colorIsDark} from '@/helpers/color/colorIsDark'
import {useNamespaceStore} from '@/stores/namespaces'
function scrollIntoView(el) { function scrollIntoView(el) {
if (!el) { if (!el) {
@ -582,11 +583,13 @@ export default defineComponent({
} }
} }
if (!this.$store.getters['namespaces/getListAndNamespaceById']) { const namespaceStore = useNamespaceStore()
if (!namespaceStore.getListAndNamespaceById) {
return null return null
} }
return this.$store.getters['namespaces/getListAndNamespaceById'](this.task.listId) return namespaceStore.getListAndNamespaceById(this.task.listId)
}, },
canWrite() { canWrite() {
return typeof this.task !== 'undefined' && typeof this.task.maxRight !== 'undefined' && this.task.maxRight > rights.READ return typeof this.task !== 'undefined' && typeof this.task.maxRight !== 'undefined' && this.task.maxRight > rights.READ
@ -752,7 +755,8 @@ export default defineComponent({
async toggleFavorite() { async toggleFavorite() {
this.task.isFavorite = !this.task.isFavorite this.task.isFavorite = !this.task.isFavorite
this.task = await this.taskService.update(this.task) this.task = await this.taskService.update(this.task)
this.$store.dispatch('namespaces/loadNamespacesIfFavoritesDontExist') const namespaceStore = useNamespaceStore()
await namespaceStore.loadNamespacesIfFavoritesDontExist()
}, },
colorIsDark, colorIsDark,