1
Fork 0
mirror of https://github.com/thegeneralist01/archivr synced 2026-07-22 11:15:41 +02:00

fix(frontend): resolve detail entry for any remaining child after ctrl-deselect

Add entryCacheRef (uid→entry Map) populated on every row click. When
ctrl/meta-deselecting leaves exactly one other entry selected, look up
the remaining UID in the cache before falling back to the root entries
array. Without this, deselecting from a multi-selection where the
remaining entry is a child row left selectedEntry null (auto-snap only
searches root entries).
This commit is contained in:
TheGeneralist 2026-07-21 13:40:33 +02:00
parent 03406099de
commit 74d3b0b3be
Signed by: thegeneralist01
SSH key fingerprint: SHA256:pp9qddbCNmVNoSjevdvQvM5z0DHN7LTa8qBMbcMq/R4
3 changed files with 30 additions and 16 deletions

View file

@ -4,7 +4,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Archivr</title> <title>Archivr</title>
<script type="module" crossorigin src="/assets/index-DQR_MNv8.js"></script> <script type="module" crossorigin src="/assets/index-mnEjEwmD.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-sQJOY7Hx.css"> <link rel="stylesheet" crossorigin href="/assets/index-sQJOY7Hx.css">
</head> </head>
<body> <body>

View file

@ -131,6 +131,9 @@ export default function App() {
const pendingSearchFocus = useRef(false) const pendingSearchFocus = useRef(false)
const firstArchiveLoad = useRef(true) const firstArchiveLoad = useRef(true)
const lastAnchorIndexRef = useRef(null) const lastAnchorIndexRef = useRef(null)
// uid entry object cache; populated on every row click so ctrl/shift
// selections can resolve child entries that aren't in the root entries array.
const entryCacheRef = useRef(new Map())
const humanizeTags = currentUser?.humanize_slugs ?? false; const humanizeTags = currentUser?.humanize_slugs ?? false;
@ -260,6 +263,10 @@ export default function App() {
}, []) }, [])
const handleRowClick = useCallback((entry, e) => { const handleRowClick = useCallback((entry, e) => {
// Cache every clicked entry so shift/ctrl can resolve child entries
// that are not present in the root `entries` array.
entryCacheRef.current.set(entry.entry_uid, entry)
if (e.shiftKey && lastAnchorIndexRef.current !== null) { if (e.shiftKey && lastAnchorIndexRef.current !== null) {
e.preventDefault() e.preventDefault()
// Use DOM order so child rows (not in the `entries` array) participate // Use DOM order so child rows (not in the `entries` array) participate
@ -268,7 +275,6 @@ export default function App() {
const anchorIdx = allNodes.findIndex(n => n.dataset.entryUid === lastAnchorIndexRef.current) const anchorIdx = allNodes.findIndex(n => n.dataset.entryUid === lastAnchorIndexRef.current)
const clickIdx = allNodes.findIndex(n => n.dataset.entryUid === entry.entry_uid) const clickIdx = allNodes.findIndex(n => n.dataset.entryUid === entry.entry_uid)
if (anchorIdx === -1 || clickIdx === -1) { if (anchorIdx === -1 || clickIdx === -1) {
// anchor no longer visible fall back to single select
lastAnchorIndexRef.current = entry.entry_uid lastAnchorIndexRef.current = entry.entry_uid
setSelectedUids(new Set([entry.entry_uid])) setSelectedUids(new Set([entry.entry_uid]))
selectEntry(entry) selectEntry(entry)
@ -285,10 +291,18 @@ export default function App() {
if (next.has(entry.entry_uid)) next.delete(entry.entry_uid) if (next.has(entry.entry_uid)) next.delete(entry.entry_uid)
else next.add(entry.entry_uid) else next.add(entry.entry_uid)
setSelectedUids(next) setSelectedUids(next)
// Auto-snap only restores root entries; explicitly drive selectEntry so if (next.size === 0) {
// ctrl-clicking a single child row loads its detail and clears on multi. selectEntry(null)
if (next.size === 1 && next.has(entry.entry_uid)) selectEntry(entry) } else if (next.size === 1) {
else if (next.size !== 1) selectEntry(null) // Resolve the remaining UID may be a child not in root entries array.
const [remainingUid] = next
const cached = entryCacheRef.current.get(remainingUid)
?? entries.find(x => x.entry_uid === remainingUid)
?? null
selectEntry(cached)
} else {
selectEntry(null)
}
} else { } else {
lastAnchorIndexRef.current = entry.entry_uid lastAnchorIndexRef.current = entry.entry_uid
setSelectedUids(new Set([entry.entry_uid])) setSelectedUids(new Set([entry.entry_uid]))