Files
siftlode/frontend/src/components/ui/DataTable.cards.dom.test.tsx
T
peter 078194731b feat(files): the Downloads page goes — the tray, a Storage tab and a Downloads settings tab take its place
- The Downloads module, its rail icon and badge are gone. A bookmark, the remembered page and an old
  history entry that name it land on Files (urlState.resolvePage); `g d` goes to Files too.
- Users page: a Storage tab — the disk in numbers, every user's use against their own limit with
  their file count, every user's downloads; aligned tables, one menu per row (edit / reset quota,
  open source, copy, the owner's quota). The admin storage rows carry quota + file count, the admin
  job list its owner.
- Settings: a Downloads tab — the download formats in one list (duplicate a built-in, edit or delete
  your own) and the site sign-ins, moved from Account.
- "View" on an added download, a clip or a converting upload opens the tray on that row (unfolded,
  back if closed; a finished one opens as a file; under a player it opens without taking focus).
- The download dialog opens on the format used last.
- DataTable: `pager={false}` for a short list, `cardRow` to give a lone "…" its own card line.
- Welcome and README speak of Files; a new Files screenshot.
2026-10-11 19:37:13 +02:00

47 lines
1.7 KiB
TypeScript

// @vitest-environment jsdom
//
// Below `md` a table is a list of cards, its columns flowing one after another. A column marked
// `cardRow` takes a line of its own there — a row's lone "…" otherwise landed at the end of one
// card's line and on the next line of another.
import { describe, it, expect, afterEach, vi } from "vitest";
import { render, cleanup, screen } from "@testing-library/react";
import DataTable, { type Column } from "./DataTable";
vi.mock("react-i18next", async (importOriginal) => ({
...(await importOriginal<typeof import("react-i18next")>()),
useTranslation: () => ({ i18n: { language: "en" }, t: (key: string) => key }),
}));
const narrow = (matches: boolean) =>
vi.stubGlobal(
"matchMedia",
(query: string) =>
({
matches,
media: query,
addEventListener: () => {},
removeEventListener: () => {},
}) as unknown as MediaQueryList,
);
afterEach(() => {
cleanup();
vi.unstubAllGlobals();
});
type Row = { id: string };
const columns: Column<Row>[] = [
{ key: "name", header: "Name", cardPrimary: true, render: (r) => r.id },
{ key: "size", header: "Size", render: () => "1 MB" },
{ key: "menu", header: "", cardLabel: false, cardRow: true, render: () => <button>more</button> },
];
describe("DataTable cards", () => {
it("gives a cardRow column a line of its own; the others flow", () => {
narrow(false);
render(<DataTable rows={[{ id: "a" }]} columns={columns} rowKey={(r) => r.id} />);
expect(screen.getByText("more").parentElement!.className).toContain("basis-full");
expect(screen.getByText("1 MB").parentElement!.className).not.toContain("basis-full");
});
});