Settings gains an API tokens tab: a row per token (name and prefix; each folder with its rights; last use and expiry, "expires soon" marked), revoked from its menu behind a confirm. A new token is the Hub exchange in one click, or folders and rights picked per folder (no Write where an upload cannot land); expiry 30/90 days, 1 year or never (warned). The token shows once in the same dialog, with Copy and a ready curl line. The Hub folder closes the Sources in the Files rail, takes uploads and moved-in files. A token about to run out warns its user once, a week before (the Files GC's sixth pass); the notice opens the tokens tab.
45 lines
1.9 KiB
TypeScript
45 lines
1.9 KiB
TypeScript
import { Film, Folder, Globe, Server, Upload, type LucideIcon } from "lucide-react";
|
|
import { YouTubeIcon } from "../lib/brandIcons";
|
|
import type { FileFolder } from "../lib/api";
|
|
|
|
// A library folder's and a file's origin, named and drawn. The backend sends a source folder's KEY
|
|
// (`youtube`, `plex`, `upload`, `site:<host>`, see backend downloads/folders.py) and leaves
|
|
// its name to the client, in the reader's language; an own folder carries the name its user gave it;
|
|
// the Hub folder (one per user, made by a hub token) is named by the client too.
|
|
|
|
const SITE_PREFIX = "site:";
|
|
|
|
type T = (key: string) => string;
|
|
|
|
/** The name of a source: a site is its host, the rest are words of the UI. */
|
|
export function sourceLabel(key: string, t: T): string {
|
|
if (key.startsWith(SITE_PREFIX)) return key.slice(SITE_PREFIX.length);
|
|
if (key === "youtube" || key === "plex" || key === "upload") return t(`files.source.${key}`);
|
|
return key;
|
|
}
|
|
|
|
export function sourceIcon(key: string): LucideIcon | typeof YouTubeIcon {
|
|
if (key === "youtube") return YouTubeIcon;
|
|
if (key === "plex") return Film;
|
|
if (key === "upload") return Upload;
|
|
return Globe;
|
|
}
|
|
|
|
type Folderish = Pick<FileFolder, "kind" | "source_key" | "name">;
|
|
|
|
export function folderLabel(folder: Folderish, t: T): string {
|
|
if (folder.kind === "hub") return t("files.folder.hub");
|
|
return folder.kind === "own" ? (folder.name ?? "") : sourceLabel(folder.source_key ?? "", t);
|
|
}
|
|
|
|
export function folderIcon(folder: Folderish): LucideIcon | typeof YouTubeIcon {
|
|
if (folder.kind === "hub") return Server;
|
|
return folder.kind === "own" ? Folder : sourceIcon(folder.source_key ?? "");
|
|
}
|
|
|
|
/** Whether an upload may land in `folder` (the backend's `folders.upload_target`): an own folder,
|
|
* the Hub folder, or Uploads — a file put in a site's folder would claim an origin it does not have. */
|
|
export function takesUploads(folder: Folderish): boolean {
|
|
return folder.kind !== "source" || folder.source_key === "upload";
|
|
}
|