Skip to content

Commit efb5440

Browse files
committed
fix(staged): properly revert changes when dragging back to original column
- stageChange now preserves the original "from" column and detects when a bug is dragged back to it, clearing the staged change correctly - Auto-stage qe-verify+ flag when moving bugs to in-testing column, ensuring bugs have both RESOLVED-FIXED status and qe-verify+ flag
1 parent c7a7e87 commit efb5440

File tree

4 files changed

+133
-11
lines changed

4 files changed

+133
-11
lines changed

src/App.test.tsx

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,4 +375,76 @@ describe('App', () => {
375375
expect(replaceStateMock).not.toHaveBeenCalled()
376376
})
377377
})
378+
379+
describe('handleBugMove side effects', () => {
380+
beforeEach(() => {
381+
useStore.setState({
382+
apiKey: 'test-api-key',
383+
isValid: true,
384+
isValidating: false,
385+
changes: new Map(),
386+
bugs: [
387+
{
388+
id: 123,
389+
summary: 'Test bug',
390+
status: 'ASSIGNED',
391+
assigned_to: 'dev@test.com',
392+
priority: 'P2',
393+
severity: 'normal',
394+
component: 'Core',
395+
whiteboard: '',
396+
last_change_time: '2024-01-01T00:00:00Z',
397+
creation_time: '2024-01-01T00:00:00Z',
398+
},
399+
],
400+
})
401+
})
402+
403+
it('should stage qe-verify plus when moving bug to in-testing column', () => {
404+
const { stageChange, stageQeVerifyChange } = useStore.getState()
405+
406+
// Simulate handleBugMove for in-testing: should stage both status and qe-verify
407+
stageChange(123, 'in-progress', 'in-testing')
408+
stageQeVerifyChange(123, 'unknown', 'plus')
409+
410+
const { changes } = useStore.getState()
411+
const change = changes.get(123)
412+
413+
expect(change?.status).toEqual({ from: 'in-progress', to: 'in-testing' })
414+
expect(change?.qeVerify).toEqual({ from: 'unknown', to: 'plus' })
415+
})
416+
417+
it('should NOT stage qe-verify when bug already has qe-verify plus', () => {
418+
// Set up a bug that already has qe-verify+
419+
useStore.setState({
420+
bugs: [
421+
{
422+
id: 123,
423+
summary: 'Test bug',
424+
status: 'RESOLVED',
425+
resolution: 'FIXED',
426+
assigned_to: 'dev@test.com',
427+
priority: 'P2',
428+
severity: 'normal',
429+
component: 'Core',
430+
whiteboard: '',
431+
last_change_time: '2024-01-01T00:00:00Z',
432+
creation_time: '2024-01-01T00:00:00Z',
433+
flags: [{ name: 'qe-verify', status: '+' }],
434+
},
435+
],
436+
})
437+
438+
const { stageChange } = useStore.getState()
439+
440+
// When bug already has qe-verify+, moving to in-testing shouldn't add qeVerify change
441+
stageChange(123, 'done', 'in-testing')
442+
443+
const { changes } = useStore.getState()
444+
const change = changes.get(123)
445+
446+
expect(change?.status).toEqual({ from: 'done', to: 'in-testing' })
447+
expect(change?.qeVerify).toBeUndefined()
448+
})
449+
})
378450
})

src/App.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,9 @@ function App() {
160160
(bugId: number, fromColumn: string, toColumn: string) => {
161161
stageChange(bugId, fromColumn, toColumn)
162162

163-
// Handle sprint tag for backlog <-> todo moves
164163
const bug = bugs.find((b) => b.id === bugId)
165164
if (bug) {
165+
// Handle sprint tag for backlog <-> todo moves
166166
const currentWhiteboard = bug.whiteboard
167167

168168
// Moving from backlog to todo: add sprint tag
@@ -180,9 +180,18 @@ function App() {
180180
stageWhiteboardChange(bugId, currentWhiteboard, newWhiteboard)
181181
}
182182
}
183+
184+
// Handle qe-verify for moves to in-testing
185+
// Bug needs qe-verify+ to stay in in-testing column
186+
if (toColumn === 'in-testing') {
187+
const currentQeVerify = getQeVerifyStatus(bug.flags)
188+
if (currentQeVerify !== 'plus') {
189+
stageQeVerifyChange(bugId, currentQeVerify, 'plus')
190+
}
191+
}
183192
}
184193
},
185-
[stageChange, bugs, stageWhiteboardChange],
194+
[stageChange, bugs, stageWhiteboardChange, stageQeVerifyChange],
186195
)
187196

188197
// Handle assignee change

src/store/slices/staged-slice.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,42 @@ describe('StagedSlice', () => {
102102
const { changes } = useStore.getState()
103103
expect(changes.has(123)).toBe(false)
104104
})
105+
106+
it('should remove change when dragging from staged position back to original', () => {
107+
const { stageChange } = useStore.getState()
108+
109+
// First drag: backlog -> todo
110+
stageChange(123, 'backlog', 'todo')
111+
expect(useStore.getState().changes.get(123)?.status).toEqual({
112+
from: 'backlog',
113+
to: 'todo',
114+
})
115+
116+
// Second drag: from staged position (todo) back to original (backlog)
117+
// This simulates the actual drag flow where fromColumn is the staged column
118+
stageChange(123, 'todo', 'backlog')
119+
120+
// Should remove the change since we're back to original
121+
const { changes } = useStore.getState()
122+
expect(changes.has(123)).toBe(false)
123+
})
124+
125+
it('should update to new column when dragging from staged position to third column', () => {
126+
const { stageChange } = useStore.getState()
127+
128+
// First drag: backlog -> todo
129+
stageChange(123, 'backlog', 'todo')
130+
131+
// Second drag: from staged position (todo) to in-progress
132+
stageChange(123, 'todo', 'in-progress')
133+
134+
// Should preserve original "from" but update "to"
135+
const change = useStore.getState().changes.get(123)
136+
expect(change?.status).toEqual({
137+
from: 'backlog',
138+
to: 'in-progress',
139+
})
140+
})
105141
})
106142

107143
describe('unstageChange', () => {

src/store/slices/staged-slice.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,25 @@ export const createStagedSlice: StateCreator<StagedSlice> = (set, get) => ({
6363
const newChanges = new Map(state.changes)
6464
const existing = newChanges.get(bugId)
6565

66+
// Preserve the original column from any existing staged change
67+
const originalColumn = existing?.status?.from ?? fromColumn
68+
6669
// If moving back to original column, remove the status change
67-
if (fromColumn === toColumn) {
68-
if (existing?.assignee) {
69-
// Keep assignee change, remove status
70-
newChanges.set(bugId, { assignee: existing.assignee })
71-
} else {
72-
// No other changes, remove the bug entry
73-
newChanges.delete(bugId)
70+
if (originalColumn === toColumn) {
71+
if (existing) {
72+
const { status: _removed, ...rest } = existing
73+
// Check if there are other changes remaining
74+
if (Object.keys(rest).length > 0) {
75+
newChanges.set(bugId, rest)
76+
} else {
77+
newChanges.delete(bugId)
78+
}
7479
}
7580
} else {
76-
// Add/update status change, preserve assignee if exists
81+
// Add/update status change, preserve other changes if exist
7782
newChanges.set(bugId, {
7883
...existing,
79-
status: { from: fromColumn, to: toColumn },
84+
status: { from: originalColumn, to: toColumn },
8085
})
8186
}
8287

0 commit comments

Comments
 (0)