feat(views): save task position
This commit is contained in:
parent
c36fdb9f5d
commit
786e67f692
8
frontend/src/modelTypes/ITaskPosition.ts
Normal file
8
frontend/src/modelTypes/ITaskPosition.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import type {IProjectView} from '@/modelTypes/IProjectView'
|
||||||
|
import type {IAbstract} from '@/modelTypes/IAbstract'
|
||||||
|
|
||||||
|
export interface ITaskPosition extends IAbstract {
|
||||||
|
position: number
|
||||||
|
projectViewId: IProjectView['id']
|
||||||
|
taskId: number
|
||||||
|
}
|
13
frontend/src/models/taskPosition.ts
Normal file
13
frontend/src/models/taskPosition.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import AbstractModel from '@/models/abstractModel'
|
||||||
|
import type {ITaskPosition} from '@/modelTypes/ITaskPosition'
|
||||||
|
|
||||||
|
export default class TaskPositionModel extends AbstractModel<ITaskPosition> implements ITaskPosition {
|
||||||
|
position = 0
|
||||||
|
projectViewId = 0
|
||||||
|
taskId = 0
|
||||||
|
|
||||||
|
constructor(data: Partial<ITaskPosition>) {
|
||||||
|
super()
|
||||||
|
this.assignData(data)
|
||||||
|
}
|
||||||
|
}
|
15
frontend/src/services/taskPosition.ts
Normal file
15
frontend/src/services/taskPosition.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import AbstractService from '@/services/abstractService'
|
||||||
|
import type {ITaskPosition} from '@/modelTypes/ITaskPosition'
|
||||||
|
import TaskPositionModel from '@/models/taskPosition'
|
||||||
|
|
||||||
|
export default class TaskPositionService extends AbstractService<ITaskPosition> {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
update: '/tasks/{taskId}/position',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
modelFactory(data: Partial<ITaskPosition>) {
|
||||||
|
return new TaskPositionModel(data)
|
||||||
|
}
|
||||||
|
}
|
@ -302,6 +302,8 @@ import {success} from '@/message'
|
|||||||
import {useProjectStore} from '@/stores/projects'
|
import {useProjectStore} from '@/stores/projects'
|
||||||
import type {TaskFilterParams} from '@/services/taskCollection'
|
import type {TaskFilterParams} from '@/services/taskCollection'
|
||||||
import type {IProjectView} from '@/modelTypes/IProjectView'
|
import type {IProjectView} from '@/modelTypes/IProjectView'
|
||||||
|
import TaskPositionService from '@/services/taskPosition'
|
||||||
|
import TaskPositionModel from '@/models/taskPosition'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
projectId = undefined,
|
projectId = undefined,
|
||||||
@ -328,6 +330,7 @@ const baseStore = useBaseStore()
|
|||||||
const kanbanStore = useKanbanStore()
|
const kanbanStore = useKanbanStore()
|
||||||
const taskStore = useTaskStore()
|
const taskStore = useTaskStore()
|
||||||
const projectStore = useProjectStore()
|
const projectStore = useProjectStore()
|
||||||
|
const taskPositionService = ref(new TaskPositionService())
|
||||||
|
|
||||||
const taskContainerRefs = ref<{ [id: IBucket['id']]: HTMLElement }>({})
|
const taskContainerRefs = ref<{ [id: IBucket['id']]: HTMLElement }>({})
|
||||||
const bucketLimitInputRef = ref<HTMLInputElement | null>(null)
|
const bucketLimitInputRef = ref<HTMLInputElement | null>(null)
|
||||||
@ -390,7 +393,7 @@ const project = computed(() => projectId ? projectStore.projects[projectId] : nu
|
|||||||
const buckets = computed(() => kanbanStore.buckets)
|
const buckets = computed(() => kanbanStore.buckets)
|
||||||
const loading = computed(() => kanbanStore.isLoading)
|
const loading = computed(() => kanbanStore.isLoading)
|
||||||
|
|
||||||
const taskLoading = computed(() => taskStore.isLoading)
|
const taskLoading = computed(() => taskStore.isLoading || taskPositionService.value.loading)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => ({
|
() => ({
|
||||||
@ -478,7 +481,7 @@ async function updateTaskPosition(e) {
|
|||||||
|
|
||||||
const newTask = klona(task) // cloning the task to avoid pinia store manipulation
|
const newTask = klona(task) // cloning the task to avoid pinia store manipulation
|
||||||
newTask.bucketId = newBucket.id
|
newTask.bucketId = newBucket.id
|
||||||
newTask.kanbanPosition = calculateItemPosition(
|
const position = calculateItemPosition(
|
||||||
taskBefore !== null ? taskBefore.kanbanPosition : null,
|
taskBefore !== null ? taskBefore.kanbanPosition : null,
|
||||||
taskAfter !== null ? taskAfter.kanbanPosition : null,
|
taskAfter !== null ? taskAfter.kanbanPosition : null,
|
||||||
)
|
)
|
||||||
@ -488,6 +491,8 @@ async function updateTaskPosition(e) {
|
|||||||
) {
|
) {
|
||||||
newTask.done = project.value?.doneBucketId === newBucket.id
|
newTask.done = project.value?.doneBucketId === newBucket.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let bucketHasChanged = false
|
||||||
if (
|
if (
|
||||||
oldBucket !== undefined && // This shouldn't actually be `undefined`, but let's play it safe.
|
oldBucket !== undefined && // This shouldn't actually be `undefined`, but let's play it safe.
|
||||||
newBucket.id !== oldBucket.id
|
newBucket.id !== oldBucket.id
|
||||||
@ -500,10 +505,20 @@ async function updateTaskPosition(e) {
|
|||||||
...newBucket,
|
...newBucket,
|
||||||
count: newBucket.count + 1,
|
count: newBucket.count + 1,
|
||||||
})
|
})
|
||||||
|
bucketHasChanged = true
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await taskStore.update(newTask)
|
const newPosition = new TaskPositionModel({
|
||||||
|
position,
|
||||||
|
projectViewId: view.id,
|
||||||
|
taskId: newTask.id,
|
||||||
|
})
|
||||||
|
await taskPositionService.value.update(newPosition)
|
||||||
|
|
||||||
|
if(bucketHasChanged) {
|
||||||
|
await taskStore.update(newTask)
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure the first and second task don't both get position 0 assigned
|
// Make sure the first and second task don't both get position 0 assigned
|
||||||
if (newTaskIndex === 0 && taskAfter !== null && taskAfter.kanbanPosition === 0) {
|
if (newTaskIndex === 0 && taskAfter !== null && taskAfter.kanbanPosition === 0) {
|
||||||
|
@ -306,6 +306,7 @@ func GetProjectViewByIDAndProject(s *xorm.Session, id, projectID int64) (view *P
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetProjectViewByID(s *xorm.Session, id int64) (view *ProjectView, err error) {
|
func GetProjectViewByID(s *xorm.Session, id int64) (view *ProjectView, err error) {
|
||||||
|
view = &ProjectView{}
|
||||||
exists, err := s.
|
exists, err := s.
|
||||||
Where("id = ?", id).
|
Where("id = ?", id).
|
||||||
NoAutoCondition().
|
NoAutoCondition().
|
||||||
|
@ -46,7 +46,10 @@ func (tp *TaskPosition) TableName() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tp *TaskPosition) CanUpdate(s *xorm.Session, a web.Auth) (bool, error) {
|
func (tp *TaskPosition) CanUpdate(s *xorm.Session, a web.Auth) (bool, error) {
|
||||||
pv := &ProjectView{ID: tp.ProjectViewID}
|
pv, err := GetProjectViewByID(s, tp.ProjectViewID)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
return pv.CanUpdate(s, a)
|
return pv.CanUpdate(s, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user