Ability to move task statuses between categories (#7569)

Signed-off-by: Anna Khismatullina <anna.khismatullina@gmail.com>
This commit is contained in:
Anna Khismatullina 2024-12-27 17:34:56 +07:00 committed by GitHub
parent f13469c052
commit 7101c3524f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 86 additions and 15 deletions

View File

@ -229,7 +229,13 @@ export class WorkspaceImporter {
kind: 'both', kind: 'both',
name: taskType.name, name: taskType.name,
ofClass: tracker.class.Issue, ofClass: tracker.class.Issue,
statusCategories: [task.statusCategory.Active], statusCategories: [
task.statusCategory.UnStarted,
task.statusCategory.ToDo,
task.statusCategory.Active,
task.statusCategory.Won,
task.statusCategory.Lost
],
statusClass: tracker.class.IssueStatus, statusClass: tracker.class.IssueStatus,
icon: tracker.icon.Issue, icon: tracker.icon.Issue,
color: 0, color: 0,

View File

@ -35,32 +35,73 @@
let dragState: Ref<Status> let dragState: Ref<Status>
let opened: Ref<Status> | undefined let opened: Ref<Status> | undefined
function dragswap (ev: MouseEvent, i: number): boolean { function dragswap (ev: MouseEvent, i: number, targetCategory: Ref<StatusCategory>): boolean {
if (readonly) return false if (readonly) return false
const s = selected as number const s = selected as number
if (i < s) { const sourceState = states[s]
return ev.offsetY < elements[i].offsetHeight / 2 const sourceCategory = sourceState.category
} else if (i > s) {
return ev.offsetY > elements[i].offsetHeight / 2 if (sourceCategory === targetCategory) {
if (i < s) {
return ev.offsetY < elements[i].offsetHeight / 2
} else if (i > s) {
return ev.offsetY > elements[i].offsetHeight / 2
}
} else {
return true
} }
return false return false
} }
function dragover (ev: MouseEvent, i: number): void { function dragover (ev: MouseEvent, i: number, targetCategory: Ref<StatusCategory>): void {
if (readonly) return if (readonly) return
const s = selected as number const s = selected as number
if (dragswap(ev, i)) {
if (dragswap(ev, i, targetCategory)) {
;[states[i], states[s]] = [states[s], states[i]] ;[states[i], states[s]] = [states[s], states[i]]
selected = i selected = i
} }
} }
function onMove (to: number): void { function moveState (i: number): void {
if (readonly || selected === undefined || i === selected) return
// Get state to move
const stateToMove = states[selected]
// Remove state from old position
states.splice(selected, 1)
// Adjust target index if moving forward
const targetIndex = i > selected ? i - 1 : i
// Insert state at new position
states.splice(targetIndex, 0, stateToMove)
// Update selected index
selected = targetIndex
}
function onMove (to: number, targetCategory: Ref<StatusCategory>): void {
if (readonly) return if (readonly) return
dispatch('move', {
stateID: dragState, const state = $statusStore.byId.get(dragState)
position: to
}) if (state !== undefined && state.category !== targetCategory) {
const newStates = states.filter((s) => s._id !== dragState)
newStates.splice(to, 0, state)
dispatch('move', {
stateID: dragState,
position: to,
newCategory: targetCategory
})
} else {
dispatch('move', {
stateID: dragState,
position: to
})
}
} }
let categories: StatusCategory[] = [] let categories: StatusCategory[] = []
@ -150,6 +191,21 @@
<Label label={cat.label} /> <Label label={cat.label} />
</div> </div>
<div class="hulyTableAttr-content__wrapper"> <div class="hulyTableAttr-content__wrapper">
{#if states.length === 0}
<!-- Placeholder для пустой категории -->
<button
class="hulyTableAttr-content__row disableMouseOver"
style="height: 100%; min-height: 3rem;"
draggable={false}
on:drop|preventDefault={() => {
onMove(prevIndex, cat._id)
}}
on:dragover|preventDefault={() => {
moveState(prevIndex)
}}
>
</button>
{/if}
{#each states as state, i (state._id)} {#each states as state, i (state._id)}
<!-- svelte-ignore a11y-no-static-element-interactions --> <!-- svelte-ignore a11y-no-static-element-interactions -->
<button <button
@ -161,10 +217,10 @@
handleSelect(state) handleSelect(state)
}} }}
on:dragover|preventDefault={(ev) => { on:dragover|preventDefault={(ev) => {
dragover(ev, i + prevIndex) dragover(ev, i + prevIndex, cat._id)
}} }}
on:drop|preventDefault={() => { on:drop|preventDefault={() => {
onMove(prevIndex + i) onMove(prevIndex + i, cat._id)
}} }}
on:dragstart={() => { on:dragstart={() => {
selected = i + prevIndex selected = i + prevIndex

View File

@ -237,6 +237,15 @@
const index = taskType.statuses.findIndex((p) => p === evt.detail.stateID) const index = taskType.statuses.findIndex((p) => p === evt.detail.stateID)
const state = taskType.statuses.splice(index, 1)[0] const state = taskType.statuses.splice(index, 1)[0]
if (evt.detail.newCategory !== undefined) {
const stateDoc = $statusStore.byId.get(evt.detail.stateID)
if (stateDoc !== undefined) {
await client.update(stateDoc, {
category: evt.detail.newCategory
})
}
}
const statuses = [ const statuses = [
...taskType.statuses.slice(0, evt.detail.position), ...taskType.statuses.slice(0, evt.detail.position),
state, state,