Open a folder chip on its folder, in the folder that really holds it
A bot's folder chip went to bare /admin/files instead of the folder it named, and even once there the computer volume pointed at the wrong directory, so the folder a bot linked to looked empty. The chip lost its folder because folderRefUrl only accepted a ref's volume name (computer) while the chip hands it the browser's (computers), so storageVolumeFromRef found nothing and the whole query was dropped. Both spellings resolve now, through parseStorageSpec, so a bad owner falls back cleanly instead of emitting owner=0. The deeper bug: a computer's home was assumed to be DATA_DIR/computers/<id>, but on a bind mount it can be anywhere on the docker host, and a computer the app didn't provision (the main one on a server reached at MAIN_COMPUTER_URL, i.e. a dev server outside docker) records nothing at all. resolveComputerHomeDir holds the precedence: the directory provisionComputer actually bound in (containers.metadata.data_dir), else the new MAIN_COMPUTER_DATA_DIR app setting for the main computer, else the conventional folder. A path that isn't on disk also no longer reads as an empty folder: listStorageEntries reports it as missing and the page says so, so a stale folder link can't look like a folder nothing has written yet.
This commit is contained in:
@@ -55,6 +55,26 @@ describe("folderRefUrl", () => {
|
||||
`/admin/files?volume=computers&owner=3&path=seo%2Fraw`,
|
||||
);
|
||||
});
|
||||
|
||||
test("keeps the folder when given the browser's own volume name", () => {
|
||||
/**
|
||||
* What the chip does: it holds a parsed spec, whose `volume` is the
|
||||
* browser's (`computers`), not the ref's (`computer`). Losing that
|
||||
* dropped the whole query and landed on the files browser's first
|
||||
* folder.
|
||||
*/
|
||||
expect(folderRefUrl({ volume: "computers", owner_id: 1, path: "seo/coderank" })).toBe(
|
||||
`/admin/files?volume=computers&owner=1&path=seo%2Fcoderank`,
|
||||
);
|
||||
expect(folderRefUrl({ volume: "bots", owner_id: 6, path: "reports" })).toBe(
|
||||
`/admin/files?volume=bots&owner=6&path=reports`,
|
||||
);
|
||||
});
|
||||
|
||||
test("falls back to the files browser for a volume it doesn't know", () => {
|
||||
expect(folderRefUrl({ volume: "secrets", owner_id: 1, path: "a" })).toBe("/admin/files");
|
||||
expect(folderRefUrl({ volume: "computers", owner_id: 0 })).toBe("/admin/files");
|
||||
});
|
||||
});
|
||||
|
||||
describe("linkComputerRefs", () => {
|
||||
@@ -68,6 +88,16 @@ describe("linkComputerRefs", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test("a linked folder ref still opens on that folder", () => {
|
||||
const linked = linkComputerRefs({ text: "straight off the machine: [folder:computer:1:seo/coderank]" });
|
||||
const ref = parseFolderRefHref({ href: linked.match(/\((#folder-[^)]+)\)/)?.[1] });
|
||||
|
||||
expect(ref).not.toBeNull();
|
||||
expect(
|
||||
folderRefUrl({ volume: ref!.spec.volume, owner_id: ref!.spec.owner_id, path: ref!.path }),
|
||||
).toBe(`/admin/files?volume=computers&owner=1&path=seo%2Fcoderank`);
|
||||
});
|
||||
|
||||
test("leaves a file ref to the file chip", () => {
|
||||
const linked = linkComputerRefs({ text: "The report: [file:12]." });
|
||||
|
||||
|
||||
+14
-2
@@ -10,6 +10,8 @@
|
||||
* name's extension: the ref says which one it is.
|
||||
*/
|
||||
import {
|
||||
isStorageVolume,
|
||||
parseStorageSpec,
|
||||
StorageBrowserPath,
|
||||
storageSpecHref,
|
||||
storageVolumeFromRef,
|
||||
@@ -96,11 +98,21 @@ export function parseFolderRefHref({
|
||||
/**
|
||||
* Where a folder ref opens: the files browser, on that folder. A volume the
|
||||
* browser doesn't know lands on its first folder.
|
||||
*
|
||||
* Both spellings of a volume come through here: a ref names it the way a
|
||||
* bot writes it (`computer`), the files browser the way it stores it
|
||||
* (`computers`). Either one resolves, so a chip never loses its folder and
|
||||
* drops back to the files browser's first folder.
|
||||
*/
|
||||
export function folderRefUrl({ volume, owner_id, path }: RefParams) {
|
||||
const known = storageVolumeFromRef({ name: volume });
|
||||
const from_ref = storageVolumeFromRef({ name: volume });
|
||||
const known = from_ref || (isStorageVolume(volume) ? volume : null);
|
||||
|
||||
if (!known) return StorageBrowserPath;
|
||||
|
||||
return storageSpecHref({ spec: { volume: known, owner_id: Number(owner_id) }, path });
|
||||
const spec = parseStorageSpec({ volume: known, owner_id });
|
||||
|
||||
if (!spec) return StorageBrowserPath;
|
||||
|
||||
return storageSpecHref({ spec, path });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user