feat: port tasks store to pina (#2409)

Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/2409
This commit is contained in:
konrad 2022-09-30 11:17:19 +00:00
commit 8c394d8024
20 changed files with 158 additions and 131 deletions

View file

@ -73,6 +73,7 @@ import {PREFIXES} from '@/modules/parseTaskText'
import {useListStore} from '@/stores/lists'
import {useNamespaceStore} from '@/stores/namespaces'
import {useLabelStore} from '@/stores/labels'
import {useTaskStore} from '@/stores/tasks'
const TYPE_LIST = 'list'
const TYPE_TASK = 'task'
@ -412,7 +413,8 @@ export default defineComponent({
return
}
const task = await this.$store.dispatch('tasks/createNewTask', {
const taskStore = useTaskStore()
const task = await taskStore.createNewTask({
title: this.query,
listId: this.currentList.id,
})

View file

@ -43,12 +43,11 @@
<script setup lang="ts">
import {ref, watch, unref, computed} from 'vue'
import {useI18n} from 'vue-i18n'
import {useStore} from '@/store'
import {tryOnMounted, debouncedWatch, useWindowSize, type MaybeRef} from '@vueuse/core'
import QuickAddMagic from '@/components/tasks/partials/quick-add-magic.vue'
import {LOADING, LOADING_MODULE} from '@/store/mutation-types'
import {useAuthStore} from '@/stores/auth'
import {useTaskStore} from '@/stores/tasks'
function cleanupTitle(title: string) {
return title.replace(/^((\* |\+ |- )(\[ \] )?)/g, '')
@ -135,8 +134,8 @@ const newTaskTitle = ref('')
const newTaskInput = useAutoHeightTextarea(newTaskTitle)
const {t} = useI18n({useScope: 'global'})
const store = useStore()
const authStore = useAuthStore()
const taskStore = useTaskStore()
const errorMessage = ref('')
@ -149,7 +148,7 @@ function resetEmptyTitleError(e) {
}
}
const loading = computed(() => store.state[LOADING] && store.state[LOADING_MODULE] === 'tasks')
const loading = computed(() => taskStore.isLoading)
async function addTask() {
if (newTaskTitle.value === '') {
errorMessage.value = t('list.create.addTitleRequired')
@ -168,7 +167,7 @@ async function addTask() {
return
}
const task = await store.dispatch('tasks/createNewTask', {
const task = await taskStore.createNewTask({
title,
listId: authStore.settings.defaultListId,
position: props.defaultPosition,

View file

@ -32,11 +32,12 @@
<script setup lang="ts">
import {ref,computed, watch, type PropType} from 'vue'
import {useStore} from '@/store'
import Editor from '@/components/input/AsyncEditor'
import type {ITask} from '@/modelTypes/ITask'
import {useTaskStore} from '@/stores/tasks'
import TaskModel from '@/models/task'
const props = defineProps({
@ -55,14 +56,14 @@ const props = defineProps({
const emit = defineEmits(['update:modelValue'])
const task = ref<ITask>({description: ''})
const task = ref<ITask>(new TaskModel())
const saved = ref(false)
// Since loading is global state, this variable ensures we're only showing the saving icon when saving the description.
const saving = ref(false)
const store = useStore()
const loading = computed(() => store.state.loading)
const taskStore = useTaskStore()
const loading = computed(() => taskStore.isLoading)
watch(
() => props.modelValue,
@ -77,7 +78,7 @@ async function save() {
try {
// FIXME: don't update state from internal.
task.value = await store.dispatch('tasks/update', task.value)
task.value = await taskStore.update(task.value)
emit('update:modelValue', task.value)
saved.value = true

View file

@ -29,7 +29,6 @@
<script setup lang="ts">
import {ref, shallowReactive, watch, type PropType} from 'vue'
import {useStore} from '@/store'
import {useI18n} from 'vue-i18n'
import User from '@/components/misc/user.vue'
@ -39,6 +38,8 @@ import BaseButton from '@/components/base/BaseButton.vue'
import {includesById} from '@/helpers/utils'
import ListUserService from '@/services/listUsers'
import {success} from '@/message'
import {useTaskStore} from '@/stores/tasks'
import type {IUser} from '@/modelTypes/IUser'
const props = defineProps({
@ -60,7 +61,7 @@ const props = defineProps({
})
const emit = defineEmits(['update:modelValue'])
const store = useStore()
const taskStore = useTaskStore()
const {t} = useI18n({useScope: 'global'})
const listUserService = shallowReactive(new ListUserService())
@ -79,13 +80,13 @@ watch(
)
async function addAssignee(user: IUser) {
await store.dispatch('tasks/addAssignee', {user: user, taskId: props.taskId})
await taskStore.addAssignee({user: user, taskId: props.taskId})
emit('update:modelValue', assignees.value)
success({message: t('task.assignee.assignSuccess')})
}
async function removeAssignee(user: IUser) {
await store.dispatch('tasks/removeAssignee', {user: user, taskId: props.taskId})
await taskStore.removeAssignee({user: user, taskId: props.taskId})
// Remove the assignee from the list
for (const a in assignees.value) {

View file

@ -40,7 +40,6 @@
<script setup lang="ts">
import {type PropType, ref, computed, shallowReactive, watch} from 'vue'
import {useStore} from '@/store'
import {useI18n} from 'vue-i18n'
import LabelModel from '@/models/label'
@ -51,6 +50,7 @@ import BaseButton from '@/components/base/BaseButton.vue'
import Multiselect from '@/components/input/multiselect.vue'
import type {ILabel} from '@/modelTypes/ILabel'
import {useLabelStore} from '@/stores/labels'
import {useTaskStore} from '@/stores/tasks'
const props = defineProps({
modelValue: {
@ -69,7 +69,6 @@ const props = defineProps({
const emit = defineEmits(['update:modelValue'])
const store = useStore()
const {t} = useI18n({useScope: 'global'})
const labelTaskService = shallowReactive(new LabelTaskService())
@ -87,6 +86,7 @@ watch(
},
)
const taskStore = useTaskStore()
const labelStore = useLabelStore()
const foundLabels = computed(() => labelStore.filterLabelsByQuery(labels.value, query.value))
@ -97,17 +97,13 @@ function findLabel(newQuery: string) {
}
async function addLabel(label: ILabel, showNotification = true) {
const bubble = () => {
emit('update:modelValue', labels.value)
}
if (props.taskId === 0) {
bubble()
emit('update:modelValue', labels.value)
return
}
await store.dispatch('tasks/addLabel', {label, taskId: props.taskId})
bubble()
await taskStore.addLabel({label, taskId: props.taskId})
emit('update:modelValue', labels.value)
if (showNotification) {
success({message: t('task.label.addSuccess')})
}
@ -115,7 +111,7 @@ async function addLabel(label: ILabel, showNotification = true) {
async function removeLabel(label: ILabel) {
if (props.taskId !== 0) {
await store.dispatch('tasks/removeLabel', {label, taskId: props.taskId})
await taskStore.removeLabel({label, taskId: props.taskId})
}
for (const l in labels.value) {

View file

@ -38,7 +38,6 @@
<script setup lang="ts">
import {ref, computed, type PropType} from 'vue'
import {useStore} from '@/store'
import {useRouter} from 'vue-router'
import BaseButton from '@/components/base/BaseButton.vue'
@ -48,6 +47,7 @@ import {useCopyToClipboard} from '@/composables/useCopyToClipboard'
import type {ITask} from '@/modelTypes/ITask'
import ColorBubble from '@/components/misc/colorBubble.vue'
import {useTaskStore} from '@/stores/tasks'
const props = defineProps({
task: {
@ -72,8 +72,8 @@ async function copyUrl() {
await copy(absoluteURL)
}
const store = useStore()
const loading = computed(() => store.state.loading)
const taskStore = useTaskStore()
const loading = computed(() => taskStore.isLoading)
const textIdentifier = computed(() => props.task?.getTextIdentifier() || '')
@ -93,7 +93,7 @@ async function save(title: string) {
try {
saving.value = true
const newTask = await store.dispatch('tasks/update', {
const newTask = await taskStore.update({
...props.task,
title,
})

View file

@ -78,6 +78,7 @@ import type {ITask} from '@/modelTypes/ITask'
import {formatDateLong, formatISO, formatDateSince} from '@/helpers/time/formatDate'
import {colorIsDark} from '@/helpers/color/colorIsDark'
import {useTaskStore} from '@/stores/tasks'
export default defineComponent({
name: 'kanban-card',
@ -121,7 +122,7 @@ export default defineComponent({
this.loadingInternal = true
try {
const done = !task.done
await this.$store.dispatch('tasks/update', {
await useTaskStore().update({
...task,
done,
})

View file

@ -149,7 +149,6 @@
import {ref, reactive, shallowReactive, watch, computed, type PropType} from 'vue'
import {useI18n} from 'vue-i18n'
import {useRoute} from 'vue-router'
import {useStore} from '@/store'
import TaskService from '@/services/task'
import TaskModel from '@/models/task'
@ -167,6 +166,7 @@ import Fancycheckbox from '@/components/input/fancycheckbox.vue'
import {useNamespaceStore} from '@/stores/namespaces'
import {error, success} from '@/message'
import {useTaskStore} from '@/stores/tasks'
const props = defineProps({
taskId: {
@ -190,7 +190,7 @@ const props = defineProps({
},
})
const store = useStore()
const taskStore = useTaskStore()
const namespaceStore = useNamespaceStore()
const route = useRoute()
const {t} = useI18n({useScope: 'global'})
@ -344,7 +344,7 @@ async function createAndRelateTask(title: string) {
}
async function toggleTaskDone(task: ITask) {
await store.dispatch('tasks/update', task)
await taskStore.update(task)
// Find the task in the list and update it so that it is correctly strike through
Object.entries(relatedTasks.value).some(([kind, tasks]) => {

View file

@ -119,6 +119,7 @@ import {formatDateSince, formatISO, formatDateLong} from '@/helpers/time/formatD
import ColorBubble from '@/components/misc/colorBubble.vue'
import {useListStore} from '@/stores/lists'
import {useNamespaceStore} from '@/stores/namespaces'
import {useTaskStore} from '@/stores/tasks'
export default defineComponent({
name: 'singleTaskInList',
@ -208,7 +209,7 @@ export default defineComponent({
async markAsDone(checked: boolean) {
const updateFunc = async () => {
const task = await this.$store.dispatch('tasks/update', this.task)
const task = await useTaskStore().update(this.task)
this.task = task
this.$emit('task-updated', task)
this.$message.success({

View file

@ -2,7 +2,7 @@ import AttachmentModel from '@/models/attachment'
import type {IAttachment} from '@/modelTypes/IAttachment'
import AttachmentService from '@/services/attachment'
import { store } from '@/store'
import {useTaskStore} from '@/stores/tasks'
export function uploadFile(taskId: number, file: File, onSuccess: (url: string) => void) {
const attachmentService = new AttachmentService()
@ -22,7 +22,7 @@ export async function uploadFiles(
console.debug(`Uploaded attachments for task ${taskId}, response was`, response)
response.success?.map((attachment: IAttachment) => {
store.dispatch('tasks/addTaskAttachment', {
useTaskStore().addTaskAttachment({
taskId,
attachment,
})

View file

@ -1,8 +1,8 @@
import {createApp} from 'vue'
import App from './App.vue'
import pinia from './pinia'
import router from './router'
import { createPinia } from 'pinia'
import App from './App.vue'
import {error, success} from './message'
@ -105,7 +105,6 @@ if (window.SENTRY_ENABLED) {
import('./sentry').then(sentry => sentry.default(app, router))
}
const pinia = createPinia()
app.use(pinia)
app.use(store, key) // pass the injection key

5
src/pinia.ts Normal file
View file

@ -0,0 +1,5 @@
import {createPinia} from 'pinia'
const pinia = createPinia()
export default pinia

View file

@ -14,7 +14,6 @@ import {
QUICK_ACTIONS_ACTIVE,
} from './mutation-types'
import kanban from './modules/kanban'
import tasks from './modules/tasks'
import ListModel from '@/models/list'
@ -22,6 +21,7 @@ import ListService from '../services/list'
import {checkAndSetApiUrl} from '@/helpers/checkAndSetApiUrl'
import type { RootStoreState, StoreState } from './types'
import pinia from '@/pinia'
import {useAuthStore} from '@/stores/auth'
export const key: InjectionKey<Store<StoreState>> = Symbol()
@ -35,7 +35,6 @@ export const store = createStore<RootStoreState>({
strict: import.meta.env.DEV,
modules: {
kanban,
tasks,
},
state: () => ({
loading: false,
@ -132,7 +131,7 @@ export const store = createStore<RootStoreState>({
},
async loadApp() {
await checkAndSetApiUrl(window.API_URL)
const authStore = useAuthStore()
const authStore = useAuthStore(pinia)
await authStore.checkAuth()
},
},

View file

@ -94,7 +94,9 @@ export interface NamespaceState {
isLoading: boolean,
}
export interface TaskState {}
export interface TaskState {
isLoading: boolean,
}
export type StoreState = RootStoreState & {

View file

@ -124,7 +124,7 @@ export const useLabelStore = defineStore('label', {
const labelService = new LabelService()
try {
const newLabel = await labelService.create(label)
const newLabel = await labelService.create(label) as ILabel
this.setLabel(newLabel)
return newLabel
} finally {

View file

@ -1,4 +1,4 @@
import type { Module } from 'vuex'
import {defineStore, acceptHMRUpdate} from 'pinia'
import router from '@/router'
import {formatISO} from 'date-fns'
@ -7,8 +7,8 @@ import TaskAssigneeService from '@/services/taskAssignee'
import LabelTaskService from '@/services/labelTask'
import UserService from '@/services/user'
import {HAS_TASKS} from '../mutation-types'
import {setLoading} from '../helper'
import {HAS_TASKS} from '../store/mutation-types'
import {setLoadingPinia} from '../store/helper'
import {getQuickAddMagicMode} from '@/helpers/quickAddMagicMode'
import {parseTaskText} from '@/modules/parseTaskText'
@ -24,11 +24,12 @@ import type { IUser } from '@/modelTypes/IUser'
import type {IAttachment} from '@/modelTypes/IAttachment'
import type {IList} from '@/modelTypes/IList'
import type { RootStoreState, TaskState } from '@/store/types'
import type {TaskState} from '@/store/types'
import {useLabelStore} from '@/stores/labels'
import {useListStore} from '@/stores/lists'
import {useAttachmentStore} from '@/stores/attachments'
import {playPop} from '@/helpers/playPop'
import {store} from '@/store'
// IDEA: maybe use a small fuzzy search here to prevent errors
function findPropertyByValue(object, key, value) {
@ -43,7 +44,7 @@ function validateUsername(users: IUser[], username: IUser['username']) {
}
// Check if the label exists
function validateLabel(labels: ILabel[], label: ILabel) {
function validateLabel(labels: ILabel[], label: string) {
return findPropertyByValue(labels, 'title', label)
}
@ -58,7 +59,7 @@ async function addLabelToTask(task: ITask, label: ILabel) {
return response
}
async function findAssignees(parsedTaskAssignees) {
async function findAssignees(parsedTaskAssignees: string[]) {
if (parsedTaskAssignees.length <= 0) {
return []
}
@ -74,30 +75,31 @@ async function findAssignees(parsedTaskAssignees) {
}
const tasksStore : Module<TaskState, RootStoreState>= {
namespaced: true,
state: () => ({}),
export const useTaskStore = defineStore('task', {
state: () : TaskState => ({
isLoading: false,
}),
actions: {
async loadTasks(ctx, params) {
async loadTasks(params) {
const taskService = new TaskService()
const cancel = setLoading(ctx, 'tasks')
const cancel = setLoadingPinia(this)
try {
const tasks = await taskService.getAll({}, params)
ctx.commit(HAS_TASKS, tasks.length > 0, {root: true})
store.commit(HAS_TASKS, tasks.length > 0)
return tasks
} finally {
cancel()
}
},
async update(ctx, task: ITask) {
const cancel = setLoading(ctx, 'tasks')
async update(task: ITask) {
const cancel = setLoadingPinia(this)
const taskService = new TaskService()
try {
const updatedTask = await taskService.update(task)
ctx.commit('kanban/setTaskInBucket', updatedTask, {root: true})
store.commit('kanban/setTaskInBucket', updatedTask)
if (task.done) {
playPop()
}
@ -107,23 +109,23 @@ const tasksStore : Module<TaskState, RootStoreState>= {
}
},
async delete(ctx, task: ITask) {
async delete(task: ITask) {
const taskService = new TaskService()
const response = await taskService.delete(task)
ctx.commit('kanban/removeTaskInBucket', task, {root: true})
store.commit('kanban/removeTaskInBucket', task)
return response
},
// Adds a task attachment in store.
// This is an action to be able to commit other mutations
addTaskAttachment(ctx, {
addTaskAttachment({
taskId,
attachment,
}: {
taskId: ITask['id']
attachment: IAttachment
}) {
const t = ctx.rootGetters['kanban/getTaskById'](taskId)
const t = store.getters['kanban/getTaskById'](taskId)
if (t.task !== null) {
const attachments = [
...t.task.attachments,
@ -137,24 +139,25 @@ const tasksStore : Module<TaskState, RootStoreState>= {
attachments,
},
}
ctx.commit('kanban/setTaskInBucketByIndex', newTask, {root: true})
store.commit('kanban/setTaskInBucketByIndex', newTask)
}
const attachmentStore = useAttachmentStore()
attachmentStore.add(attachment)
},
async addAssignee(ctx, {
async addAssignee({
user,
taskId,
}: {
user: IUser,
taskId: ITask['id']
}) {
const taskAssignee = new TaskAssigneeModel({userId: user.id, taskId: taskId})
const taskAssigneeService = new TaskAssigneeService()
const r = await taskAssigneeService.create(taskAssignee)
const t = ctx.rootGetters['kanban/getTaskById'](taskId)
const r = await taskAssigneeService.create(new TaskAssigneeModel({
userId: user.id,
taskId: taskId,
}))
const t = store.getters['kanban/getTaskById'](taskId)
if (t.task === null) {
// Don't try further adding a label if the task is not in kanban
// Usually this means the kanban board hasn't been accessed until now.
@ -163,33 +166,32 @@ const tasksStore : Module<TaskState, RootStoreState>= {
return r
}
const assignees = [
...t.task.assignees,
user,
]
ctx.commit('kanban/setTaskInBucketByIndex', {
store.commit('kanban/setTaskInBucketByIndex', {
...t,
task: {
...t.task,
assignees,
assignees: [
...t.task.assignees,
user,
],
},
}, {root: true})
})
return r
},
async removeAssignee(ctx, {
async removeAssignee({
user,
taskId,
}: {
user: IUser,
taskId: ITask['id']
}) {
const taskAssignee = new TaskAssigneeModel({userId: user.id, taskId: taskId})
const taskAssigneeService = new TaskAssigneeService()
const response = await taskAssigneeService.delete(taskAssignee)
const t = ctx.rootGetters['kanban/getTaskById'](taskId)
const response = await taskAssigneeService.delete(new TaskAssigneeModel({
userId: user.id,
taskId: taskId,
}))
const t = store.getters['kanban/getTaskById'](taskId)
if (t.task === null) {
// Don't try further adding a label if the task is not in kanban
// Usually this means the kanban board hasn't been accessed until now.
@ -200,29 +202,30 @@ const tasksStore : Module<TaskState, RootStoreState>= {
const assignees = t.task.assignees.filter(({ id }) => id !== user.id)
ctx.commit('kanban/setTaskInBucketByIndex', {
store.commit('kanban/setTaskInBucketByIndex', {
...t,
task: {
...t.task,
assignees,
},
}, {root: true})
})
return response
},
async addLabel(ctx, {
async addLabel({
label,
taskId,
} : {
label: ILabel,
taskId: ITask['id']
}) {
const labelTask = new LabelTaskModel({taskId, labelId: label.id})
const labelTaskService = new LabelTaskService()
const r = await labelTaskService.create(labelTask)
const t = ctx.rootGetters['kanban/getTaskById'](taskId)
const r = await labelTaskService.create(new LabelTaskModel({
taskId,
labelId: label.id,
}))
const t = store.getters['kanban/getTaskById'](taskId)
if (t.task === null) {
// Don't try further adding a label if the task is not in kanban
// Usually this means the kanban board hasn't been accessed until now.
@ -231,28 +234,30 @@ const tasksStore : Module<TaskState, RootStoreState>= {
return r
}
const labels = [
...t.task.labels,
label,
]
ctx.commit('kanban/setTaskInBucketByIndex', {
store.commit('kanban/setTaskInBucketByIndex', {
...t,
task: {
...t.task,
labels,
labels: [
...t.task.labels,
label,
],
},
}, {root: true})
})
return r
},
async removeLabel(ctx, {label, taskId}) {
const labelTask = new LabelTaskModel({taskId, labelId: label.id})
async removeLabel(
{label, taskId}:
{label: ILabel, taskId: ITask['id']},
) {
const labelTaskService = new LabelTaskService()
const response = await labelTaskService.delete(labelTask)
const t = ctx.rootGetters['kanban/getTaskById'](taskId)
const response = await labelTaskService.delete(new LabelTaskModel({
taskId, labelId:
label.id,
}))
const t = store.getters['kanban/getTaskById'](taskId)
if (t.task === null) {
// Don't try further adding a label if the task is not in kanban
// Usually this means the kanban board hasn't been accessed until now.
@ -264,19 +269,22 @@ const tasksStore : Module<TaskState, RootStoreState>= {
// Remove the label from the list
const labels = t.task.labels.filter(({ id }) => id !== label.id)
ctx.commit('kanban/setTaskInBucketByIndex', {
store.commit('kanban/setTaskInBucketByIndex', {
...t,
task: {
...t.task,
labels,
},
}, {root: true})
})
return response
},
// Do everything that is involved in finding, creating and adding the label to the task
async addLabelsToTask(_, { task, parsedLabels }) {
async addLabelsToTask(
{ task, parsedLabels }:
{ task: ITask, parsedLabels: string[] },
) {
if (parsedLabels.length <= 0) {
return task
}
@ -299,10 +307,9 @@ const tasksStore : Module<TaskState, RootStoreState>= {
return task
},
findListId(_, { list: listName, listId }: {
list: string,
listId: IList['id']
}) {
findListId(
{ list: listName, listId }:
{ list: string, listId: IList['id'] }) {
let foundListId = null
// Uses the following ways to get the list id of the new task:
@ -320,7 +327,7 @@ const tasksStore : Module<TaskState, RootStoreState>= {
// 3. Otherwise use the id from the route parameter
if (typeof router.currentRoute.value.params.listId !== 'undefined') {
foundListId = parseInt(router.currentRoute.value.params.listId)
foundListId = Number(router.currentRoute.value.params.listId)
}
// 4. If none of the above worked, reject the promise with an error.
@ -331,7 +338,7 @@ const tasksStore : Module<TaskState, RootStoreState>= {
return foundListId
},
async createNewTask(ctx, {
async createNewTask({
title,
bucketId,
listId,
@ -339,10 +346,10 @@ const tasksStore : Module<TaskState, RootStoreState>= {
} :
Partial<ITask>,
) {
const cancel = setLoading(ctx, 'tasks')
const cancel = setLoadingPinia(this)
const parsedTask = parseTaskText(title, getQuickAddMagicMode())
const foundListId = await ctx.dispatch('findListId', {
const foundListId = await this.findListId({
list: parsedTask.list,
listId: listId || 0,
})
@ -369,7 +376,7 @@ const tasksStore : Module<TaskState, RootStoreState>= {
const taskService = new TaskService()
const createdTask = await taskService.create(task)
const result = await ctx.dispatch('addLabelsToTask', {
const result = await this.addLabelsToTask({
task: createdTask,
parsedLabels: parsedTask.labels,
})
@ -377,6 +384,9 @@ const tasksStore : Module<TaskState, RootStoreState>= {
return result
},
},
}
})
export default tasksStore
// support hot reloading
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useTaskStore, import.meta.hot))
}

View file

@ -240,6 +240,7 @@ import {calculateItemPosition} from '../../helpers/calculateItemPosition'
import KanbanCard from '@/components/tasks/partials/kanban-card.vue'
import DropdownItem from '@/components/misc/dropdown-item.vue'
import {isSavedFilter} from '@/helpers/savedFilter'
import {useTaskStore} from '@/stores/tasks'
const DRAG_OPTIONS = {
// sortable options
@ -433,7 +434,8 @@ export default defineComponent({
)
try {
await this.$store.dispatch('tasks/update', newTask)
const taskStore = useTaskStore()
await taskStore.update(newTask)
// Make sure the first and second task don't both get position 0 assigned
if(newTaskIndex === 0 && taskAfter !== null && taskAfter.kanbanPosition === 0) {
@ -445,7 +447,7 @@ export default defineComponent({
taskAfterAfter !== null ? taskAfterAfter.kanbanPosition : null,
)
await this.$store.dispatch('tasks/update', newTaskAfter)
await taskStore.update(newTaskAfter)
}
} finally {
this.taskUpdating[task.id] = false
@ -464,7 +466,7 @@ export default defineComponent({
}
this.newTaskError[bucketId] = false
const task = await this.$store.dispatch('tasks/createNewTask', {
const task = await useTaskStore().createNewTask({
title: this.newTaskText,
bucketId,
listId: this.listId,

View file

@ -139,7 +139,7 @@ export default { name: 'List' }
</script>
<script setup lang="ts">
import {ref, computed, toRef, nextTick, onMounted} from 'vue'
import {ref, computed, toRef, nextTick, onMounted, type PropType} from 'vue'
import draggable from 'zhyswan-vuedraggable'
import {useRoute, useRouter} from 'vue-router'
@ -161,6 +161,9 @@ import {RIGHTS as Rights} from '@/constants/rights'
import {calculateItemPosition} from '@/helpers/calculateItemPosition'
import type {ITask} from '@/modelTypes/ITask'
import {isSavedFilter} from '@/helpers/savedFilter'
import {useTaskStore} from '@/stores/tasks'
import type {IList} from '@/modelTypes/IList'
function sortTasks(tasks: ITask[]) {
if (tasks === null || Array.isArray(tasks) && tasks.length === 0) {
@ -182,7 +185,7 @@ function sortTasks(tasks: ITask[]) {
const props = defineProps({
listId: {
type: Number,
type: Number as PropType<IList['id']>,
required: true,
},
})
@ -224,6 +227,7 @@ const firstNewPosition = computed(() => {
return calculateItemPosition(null, tasks.value[0].position)
})
const taskStore = useTaskStore()
const store = useStore()
const list = computed(() => store.state.currentList)
@ -238,6 +242,7 @@ onMounted(async () => {
const route = useRoute()
const router = useRouter()
function searchTasks() {
// Only search if the search term changed
if (route.query as unknown as string === searchTerm.value) {
@ -309,7 +314,7 @@ async function saveTaskPosition(e) {
position: calculateItemPosition(taskBefore !== null ? taskBefore.position : null, taskAfter !== null ? taskAfter.position : null),
}
const updatedTask = await this.$store.dispatch('tasks/update', newTask)
const updatedTask = await taskStore.update(newTask)
tasks.value[e.newIndex] = updatedTask
}
</script>

View file

@ -60,9 +60,11 @@ import {LOADING, LOADING_MODULE} from '@/store/mutation-types'
import LlamaCool from '@/assets/llama-cool.svg?component'
import type {ITask} from '@/modelTypes/ITask'
import {useAuthStore} from '@/stores/auth'
import {useTaskStore} from '@/stores/tasks'
const store = useStore()
const authStore = useAuthStore()
const taskStore = useTaskStore()
const route = useRoute()
const router = useRouter()
const {t} = useI18n({useScope: 'global'})
@ -180,7 +182,7 @@ async function loadPendingTasks(from: string, to: string) {
}
}
tasks.value = await store.dispatch('tasks/loadTasks', params)
tasks.value = await taskStore.loadTasks(params)
}
// FIXME: this modification should happen in the store

View file

@ -464,6 +464,7 @@ import type {IList} from '@/modelTypes/IList'
import {colorIsDark} from '@/helpers/color/colorIsDark'
import {useNamespaceStore} from '@/stores/namespaces'
import {useAttachmentStore} from '@/stores/attachments'
import {useTaskStore} from '@/stores/tasks'
function scrollIntoView(el) {
if (!el) {
@ -696,7 +697,8 @@ export default defineComponent({
task.endDate = task.dueDate
}
this.task = await this.$store.dispatch('tasks/update', task)
this.task = await useTaskStore().update(task)
if (!showNotification) {
return
@ -728,7 +730,7 @@ export default defineComponent({
},
async deleteTask() {
await this.$store.dispatch('tasks/delete', this.task)
await useTaskStore().delete(this.task)
this.$message.success({message: this.$t('task.detail.deleteSuccess')})
this.$router.push({name: 'list.index', params: {listId: this.task.listId}})
},