fix(projects): reload projects when the api recalculated positions

The api renumbers all sibling positions when they drift too close together but
only returns the updated project. The store kept stale positions for the
siblings, so navigating to one of them pulled in its recalculated position and
made it jump to a different spot in the sidebar.
This commit is contained in:
kolaente
2026-08-18 14:28:37 +02:00
parent 57493ef81e
commit d49e587928
2 changed files with 59 additions and 0 deletions
+53
View File
@@ -30,6 +30,22 @@ vi.mock('@/stores/base', () => ({
}),
}))
const projectServiceMock = {
update: vi.fn(),
getAll: vi.fn(),
totalPages: 1,
}
vi.mock('@/services/project', () => ({
default: class {
update = (project: IProject) => projectServiceMock.update(project)
getAll = (...args: unknown[]) => projectServiceMock.getAll(...args)
get totalPages() {
return projectServiceMock.totalPages
}
},
}))
function createMockProject(overrides: Partial<IProject>): IProject {
return {
id: 1,
@@ -211,4 +227,41 @@ describe('project store', () => {
expect(store.getEffectiveParentProjectId(orphanedProject, 5)).toBe(5)
})
})
describe('updateProject', () => {
beforeEach(() => {
projectServiceMock.update.mockReset()
projectServiceMock.getAll.mockReset()
projectServiceMock.totalPages = 1
})
it('should not reload all projects when the api kept the position', async () => {
const store = useProjectStore()
const project = createMockProject({id: 1, position: 100})
store.setProject(project)
projectServiceMock.update.mockResolvedValue(createMockProject({id: 1, position: 100}))
await store.updateProject({...project, title: 'Renamed'})
expect(projectServiceMock.getAll).not.toHaveBeenCalled()
})
it('should reload all projects when the api recalculated the position', async () => {
const store = useProjectStore()
store.setProject(createMockProject({id: 1, position: 0.0001}))
store.setProject(createMockProject({id: 2, position: 100}))
projectServiceMock.update.mockResolvedValue(createMockProject({id: 1, position: 2147483648}))
projectServiceMock.getAll.mockResolvedValue([
createMockProject({id: 1, position: 2147483648}),
createMockProject({id: 2, position: 4294967296}),
])
await store.updateProject(createMockProject({id: 1, position: 0.0001}))
expect(projectServiceMock.getAll).toHaveBeenCalled()
// Project 2 was never updated - only the reload can fix its stale position.
expect(store.projectsArray.map(p => p.id)).toEqual([1, 2])
expect(store.projects[2].position).toBe(4294967296)
})
})
})
+6
View File
@@ -224,6 +224,12 @@ export const useProjectStore = defineStore('project', () => {
const updatedProject = await projectService.update(project)
setProject(project)
// The api renumbers all sibling positions once they drift too close together but
// only returns the updated project, so the rest would keep stale positions.
if (updatedProject.position !== project.position) {
await loadAllProjects()
}
// the returned project from projectService.update is the same!
// in order to not create a manipulation in pinia store we have to create a new copy
return updatedProject