diff --git a/plugins/file-manager/src/frontend/FileManagerGrid.tsx b/plugins/file-manager/src/frontend/FileManagerGrid.tsx
index 8d3b33a9c..e1202aa4a 100644
--- a/plugins/file-manager/src/frontend/FileManagerGrid.tsx
+++ b/plugins/file-manager/src/frontend/FileManagerGrid.tsx
@@ -1353,7 +1353,7 @@ export function FileManagerGrid({
)}
{listColumns.isVisible("owner") && (
-
+
@@ -1502,7 +1502,7 @@ export function FileManagerGrid({
)}
{!isEditing && listColumns.isVisible("owner") && (
-
+
{file.owner
? `${file.owner}${file.group ? `:${file.group}` : ""}`
: "—"}
@@ -1510,7 +1510,7 @@ export function FileManagerGrid({
)}
{!isEditing && listColumns.isVisible("size") && (
-
+
{file.type === "file" &&
file.size !== undefined &&
file.size !== null
diff --git a/plugins/file-manager/src/frontend/LocalFilePane.tsx b/plugins/file-manager/src/frontend/LocalFilePane.tsx
index 5290b15d9..4b19e238f 100644
--- a/plugins/file-manager/src/frontend/LocalFilePane.tsx
+++ b/plugins/file-manager/src/frontend/LocalFilePane.tsx
@@ -1058,7 +1058,7 @@ export function LocalFilePane({
)}
{columns.isVisible("size") && (
-
+
{entry.type === "directory"
? "--"
: formatFileSize(entry.size)}
diff --git a/plugins/file-manager/src/frontend/hooks/useResizableColumns.ts b/plugins/file-manager/src/frontend/hooks/useResizableColumns.ts
index 1b7fe9ac1..01a38a10e 100644
--- a/plugins/file-manager/src/frontend/hooks/useResizableColumns.ts
+++ b/plugins/file-manager/src/frontend/hooks/useResizableColumns.ts
@@ -15,8 +15,8 @@ interface UseResizableColumnsOptions {
/** localStorage key; widths are remembered per pane. */
storageKey: string;
/**
- * Fixed-width columns, in visual order, that follow a leading flexible
- * column (the file name). The flexible column absorbs whatever is left.
+ * Columns, in visual order, that follow the file name. Saved widths are
+ * preferred maxima; metadata shrinks first when the pane is narrow.
*/
columns: ResizableColumnSpec[];
}
@@ -72,7 +72,7 @@ function clamp(value: number, column: ResizableColumnSpec): number {
/**
* Column widths for a list view whose first column is flexible and whose
- * remaining columns are fixed and user-resizable by dragging the boundary at
+ * remaining columns are user-resizable by dragging the boundary at
* the left edge of each header cell. Double-clicking a handle resets that
* column to its default. Widths persist in localStorage.
*/
@@ -141,8 +141,8 @@ export function useResizableColumns({
const gridTemplateColumns = useMemo(
() =>
[
- "minmax(140px, 1fr)",
- ...visibleColumns.map((c) => `${widths[c.key]}px`),
+ "minmax(min(240px, 50%), 1fr)",
+ ...visibleColumns.map((c) => `minmax(0, ${widths[c.key]}px)`),
].join(" "),
[visibleColumns, widths],
);
diff --git a/plugins/file-manager/tests/frontend/hooks/useResizableColumns.test.ts b/plugins/file-manager/tests/frontend/hooks/useResizableColumns.test.ts
index 460339c6a..8f47ab647 100644
--- a/plugins/file-manager/tests/frontend/hooks/useResizableColumns.test.ts
+++ b/plugins/file-manager/tests/frontend/hooks/useResizableColumns.test.ts
@@ -20,7 +20,7 @@ describe("useResizableColumns", () => {
useResizableColumns({ storageKey: STORAGE_KEY, columns }),
);
expect(result.current.gridTemplateColumns).toBe(
- "minmax(140px, 1fr) 120px 80px",
+ "minmax(min(240px, 50%), 1fr) minmax(0, 120px) minmax(0, 80px)",
);
});
@@ -64,7 +64,9 @@ describe("useResizableColumns", () => {
);
act(() => result.current.toggleColumn("size"));
expect(result.current.isVisible("size")).toBe(false);
- expect(result.current.gridTemplateColumns).toBe("minmax(140px, 1fr) 120px");
+ expect(result.current.gridTemplateColumns).toBe(
+ "minmax(min(240px, 50%), 1fr) minmax(0, 120px)",
+ );
expect(result.current.visibleColumns.map((c) => c.key)).toEqual([
"modified",
]);
@@ -79,7 +81,7 @@ describe("useResizableColumns", () => {
expect(remount.result.current.isVisible("size")).toBe(false);
act(() => remount.result.current.toggleColumn("size"));
expect(remount.result.current.gridTemplateColumns).toBe(
- "minmax(140px, 1fr) 120px 80px",
+ "minmax(min(240px, 50%), 1fr) minmax(0, 120px) minmax(0, 80px)",
);
});
diff --git a/plugins/remote-desktop/tests/backend/token-security.test.ts b/plugins/remote-desktop/tests/backend/token-security.test.ts
index 7a033d99e..b19cafdba 100644
--- a/plugins/remote-desktop/tests/backend/token-security.test.ts
+++ b/plugins/remote-desktop/tests/backend/token-security.test.ts
@@ -41,8 +41,12 @@ describe("verifyToken", () => {
expect(
tokens.verifyToken(encode({ ...data, iv: iv.toString("base64") })),
).toBeNull();
+ const ciphertext = Buffer.from(data.value, "base64");
+ ciphertext[0] ^= 0xff;
expect(
- tokens.verifyToken(encode({ ...data, value: `A${data.value.slice(1)}` })),
+ tokens.verifyToken(
+ encode({ ...data, value: ciphertext.toString("base64") }),
+ ),
).toBeNull();
});
diff --git a/plugins/termix-identity/tests/backend/termix-identity.test.ts b/plugins/termix-identity/tests/backend/termix-identity.test.ts
index a9ad47dd9..0ea89c789 100644
--- a/plugins/termix-identity/tests/backend/termix-identity.test.ts
+++ b/plugins/termix-identity/tests/backend/termix-identity.test.ts
@@ -13,11 +13,14 @@ afterEach(async () => {
});
function ed25519Line(comment = "") {
- const pair = ssh2.utils.generateKeyPairSync("ed25519");
- const parsed = ssh2.utils.parseKey(pair.public);
- const key = Array.isArray(parsed) ? parsed[0] : parsed;
- if (key instanceof Error) throw key;
- const line = `${key.type} ${key.getPublicSSH().toString("base64")}`;
+ // ssh2's generator can truncate leading zero bytes in Ed25519 keys.
+ const { publicKey } = crypto.generateKeyPairSync("ed25519");
+ const raw = Buffer.from(publicKey.export({ format: "jwk" }).x!, "base64url");
+ const blob = Buffer.concat([
+ Buffer.from("0000000b7373682d6564323535313900000020", "hex"),
+ raw,
+ ]);
+ const line = `ssh-ed25519 ${blob.toString("base64")}`;
return comment ? `${line} ${comment}` : line;
}