mirror of
https://github.com/gramps-project/gramps-web.git
synced 2026-10-16 21:01:38 +08:00
14b4767d3a
* Don't delete a place that encloses other places Like Gramps desktop, refuse to delete a place that other places are enclosed by: Gramps 6.0 would leave those places pointing to a place that no longer exists. The delete button shows Gramps' own "Cannot delete place." message instead of the confirmation. Refs #381 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Check whether deletion is blocked only in the active view Every retained object view hears edit-mode:delete, so an inactive place view that encloses others reported a false error whenever another object was deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Check enclosed places when Delete is clicked, also in the places list - The app bar asks the view being edited when Delete is clicked, instead of a value captured when edit mode began, so the two can't disagree. - The check fetches the place's backlinks then, as the view's own data may be stale. - A place enclosed by itself, and enclosed places deleted along with it, don't block the deletion. - The places list applies the same check before a bulk delete. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
35 lines
1.2 KiB
JavaScript
35 lines
1.2 KiB
JavaScript
import {describe, it, expect} from 'vitest'
|
|
import {getEnclosingPlaces} from '../../src/util.js'
|
|
|
|
// a fake appState answering GET /api/places/<handle>?backlinks=true
|
|
const appStateWith = enclosed => ({
|
|
apiGet: async url => {
|
|
const handle = url.split('/')[3].split('?')[0]
|
|
return {data: {handle, backlinks: {place: enclosed[handle] ?? []}}}
|
|
},
|
|
})
|
|
|
|
describe('getEnclosingPlaces', () => {
|
|
const appState = appStateWith({county: ['city'], city: [], farm: []})
|
|
|
|
it('returns places that other places are enclosed by', async () => {
|
|
expect(await getEnclosingPlaces(appState, ['county', 'farm'])).toEqual([
|
|
'county',
|
|
])
|
|
})
|
|
|
|
it('ignores enclosed places deleted along with them', async () => {
|
|
expect(await getEnclosingPlaces(appState, ['county', 'city'])).toEqual([])
|
|
})
|
|
|
|
it('ignores a place enclosed by itself', async () => {
|
|
const self = appStateWith({loop: ['loop']})
|
|
expect(await getEnclosingPlaces(self, ['loop'])).toEqual([])
|
|
})
|
|
|
|
it('does not block when the backlinks cannot be read', async () => {
|
|
const failing = {apiGet: async () => ({error: 'Not found'})}
|
|
expect(await getEnclosingPlaces(failing, ['county'])).toEqual([])
|
|
})
|
|
})
|