feat: file blocks
Pull request / title (pull_request) Successful in 1s
CI / test (pull_request) Successful in 1m8s
CI / image (apps/api/Dockerfile, t5de-hub-api) (pull_request) Skipped
CI / image (apps/web/Dockerfile, t5de-hub-web) (pull_request) Skipped

Moderators block a file network-wide by its sha256, from a product's files or the console's new Blocks tab, which
first shows the products using it. Blocking removes those products (their creators are told and may appeal), puts
a `block` change in the changes feed of every catalog hosting it, and refuses uploads with it; moderators see who
tried. Unblocking lets it in again; the products it removed stay removed until restored.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
dhkatzandClaude Opus 5.5 committed 2026-11-05 14:32:08 -08:00
1 parent 7299e10b08
commit ba423f32d8
18 files changed
+4074 -10

No files matched your search

+9
View File
@@ -189,6 +189,7 @@ export default async function ProductPage({ params }: { params: Promise<{ id: st
stayOn={stayOn}
using={using === r.number}
mine={mine}
canBlock={permissions.includes("product:remove")}
/>
))}
</ul>
@@ -212,6 +213,7 @@ function RevisionRow({
stayOn,
using,
mine,
canBlock,
}: {
id: string;
revision: Revision;
@@ -220,6 +222,8 @@ function RevisionRow({
stayOn: number | null;
using: boolean;
mine: boolean;
/** Moderators: each file links to blocking it. */
canBlock: boolean;
}) {
const facts = [
formatSize(r.size),
@@ -247,6 +251,11 @@ function RevisionRow({
<li key={f.name} className="flex gap-3">
<span className="min-w-0 flex-1 truncate">{f.name}</span>
<span className="text-muted-foreground tabular-nums">{formatSize(f.size)}</span>
{canBlock && (
<Link href={`/console/blocks/${f.sha256}`} className="text-muted-foreground underline-offset-4 hover:text-foreground hover:underline">
Block
</Link>
)}
</li>
))}
</ul>