@openrails/contentkit-ui 0.71.0 → 0.73.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/README.md +122 -10
  2. package/dist/client/content/bans.d.ts +2 -0
  3. package/dist/client/content/bans.js +24 -12
  4. package/dist/client/content/bans.js.map +1 -1
  5. package/dist/client/content/comments.d.ts +2 -0
  6. package/dist/client/content/comments.js.map +1 -1
  7. package/dist/client/content/polls.d.ts +9 -2
  8. package/dist/client/content/polls.js.map +1 -1
  9. package/dist/client/generated/routes.d.ts +28 -2
  10. package/dist/client/generated/routes.js +40 -0
  11. package/dist/client/generated/routes.js.map +1 -1
  12. package/dist/client/generated/wire.d.ts +4 -0
  13. package/dist/client/generated/wire.js.map +1 -1
  14. package/dist/client/index.d.ts +3 -3
  15. package/dist/client/media/queue.d.ts +1 -1
  16. package/dist/client/media/queue.js +1 -1
  17. package/dist/client/media/queue.js.map +1 -1
  18. package/dist/client/taxonomy.d.ts +5 -1
  19. package/dist/client/taxonomy.js +7 -0
  20. package/dist/client/taxonomy.js.map +1 -1
  21. package/dist/client.js +2 -2
  22. package/dist/components/admin/media-item-panel.d.ts +27 -0
  23. package/dist/components/admin/media-item-panel.js +397 -0
  24. package/dist/components/admin/media-item-panel.js.map +1 -0
  25. package/dist/components/admin/poll-manager.d.ts +28 -0
  26. package/dist/components/admin/poll-manager.js +297 -0
  27. package/dist/components/admin/poll-manager.js.map +1 -0
  28. package/dist/components/admin/post-manager.d.ts +45 -0
  29. package/dist/components/admin/post-manager.js +602 -0
  30. package/dist/components/admin/post-manager.js.map +1 -0
  31. package/dist/components/admin/shell.d.ts +73 -0
  32. package/dist/components/admin/shell.js +148 -0
  33. package/dist/components/admin/shell.js.map +1 -0
  34. package/dist/components/admin/taxonomy-manager.d.ts +54 -0
  35. package/dist/components/admin/taxonomy-manager.js +976 -0
  36. package/dist/components/admin/taxonomy-manager.js.map +1 -0
  37. package/dist/components/admin/upload-queue.d.ts +23 -0
  38. package/dist/components/admin/upload-queue.js +365 -0
  39. package/dist/components/admin/upload-queue.js.map +1 -0
  40. package/dist/components/admin/user-comment-standing.d.ts +25 -0
  41. package/dist/components/admin/user-comment-standing.js +229 -0
  42. package/dist/components/admin/user-comment-standing.js.map +1 -0
  43. package/dist/components/social/bans.d.ts +5 -2
  44. package/dist/components/social/bans.js +132 -134
  45. package/dist/components/social/bans.js.map +1 -1
  46. package/dist/components/social/index.d.ts +1 -1
  47. package/dist/components/social/moderation.d.ts +11 -13
  48. package/dist/components/social/moderation.js +299 -218
  49. package/dist/components/social/moderation.js.map +1 -1
  50. package/dist/components/social/parts.d.ts +3 -2
  51. package/dist/components/social/parts.js +74 -48
  52. package/dist/components/social/parts.js.map +1 -1
  53. package/dist/components/social/poll-editor.js +1 -0
  54. package/dist/components/social/poll-editor.js.map +1 -1
  55. package/dist/editor/index.d.ts +1 -0
  56. package/dist/editor/rich-text-editor.d.ts +13 -0
  57. package/dist/editor/rich-text-editor.js +228 -0
  58. package/dist/editor/rich-text-editor.js.map +1 -0
  59. package/dist/editor.js +2 -0
  60. package/dist/index.d.ts +8 -0
  61. package/dist/index.js +15 -8
  62. package/dist/locales/admin/de.d.ts +2 -0
  63. package/dist/locales/admin/de.js +227 -0
  64. package/dist/locales/admin/de.js.map +1 -0
  65. package/dist/locales/admin/en.d.ts +222 -0
  66. package/dist/locales/admin/en.js +227 -0
  67. package/dist/locales/admin/en.js.map +1 -0
  68. package/dist/locales/admin/es.d.ts +2 -0
  69. package/dist/locales/admin/es.js +227 -0
  70. package/dist/locales/admin/es.js.map +1 -0
  71. package/dist/locales/admin/ja.d.ts +2 -0
  72. package/dist/locales/admin/ja.js +227 -0
  73. package/dist/locales/admin/ja.js.map +1 -0
  74. package/dist/locales/admin/ko.d.ts +2 -0
  75. package/dist/locales/admin/ko.js +227 -0
  76. package/dist/locales/admin/ko.js.map +1 -0
  77. package/dist/locales/admin/zh.d.ts +2 -0
  78. package/dist/locales/admin/zh.js +227 -0
  79. package/dist/locales/admin/zh.js.map +1 -0
  80. package/dist/locales/de.js +5 -3
  81. package/dist/locales/de.js.map +1 -1
  82. package/dist/locales/en.d.ts +227 -0
  83. package/dist/locales/en.js +5 -3
  84. package/dist/locales/en.js.map +1 -1
  85. package/dist/locales/es.js +5 -3
  86. package/dist/locales/es.js.map +1 -1
  87. package/dist/locales/ja.js +5 -3
  88. package/dist/locales/ja.js.map +1 -1
  89. package/dist/locales/ko.js +5 -3
  90. package/dist/locales/ko.js.map +1 -1
  91. package/dist/locales/social/de.js +8 -1
  92. package/dist/locales/social/de.js.map +1 -1
  93. package/dist/locales/social/en.d.ts +7 -0
  94. package/dist/locales/social/en.js +8 -1
  95. package/dist/locales/social/en.js.map +1 -1
  96. package/dist/locales/social/es.js +8 -1
  97. package/dist/locales/social/es.js.map +1 -1
  98. package/dist/locales/social/ja.js +8 -1
  99. package/dist/locales/social/ja.js.map +1 -1
  100. package/dist/locales/social/ko.js +8 -1
  101. package/dist/locales/social/ko.js.map +1 -1
  102. package/dist/locales/social/zh.js +8 -1
  103. package/dist/locales/social/zh.js.map +1 -1
  104. package/dist/locales/zh.js +5 -3
  105. package/dist/locales/zh.js.map +1 -1
  106. package/dist/provider.d.ts +2 -0
  107. package/dist/provider.js +23 -19
  108. package/dist/provider.js.map +1 -1
  109. package/dist/react/admin.d.ts +55 -0
  110. package/dist/react/admin.js +97 -0
  111. package/dist/react/admin.js.map +1 -0
  112. package/dist/react/comments.d.ts +18 -2
  113. package/dist/react/comments.js +24 -8
  114. package/dist/react/comments.js.map +1 -1
  115. package/dist/react/context.d.ts +7 -1
  116. package/dist/react/context.js +6 -1
  117. package/dist/react/context.js.map +1 -1
  118. package/dist/react/folder.js.map +1 -1
  119. package/dist/react/index.d.ts +4 -3
  120. package/dist/react/polls.js +88 -87
  121. package/dist/react/polls.js.map +1 -1
  122. package/dist/react/posts.js +123 -122
  123. package/dist/react/posts.js.map +1 -1
  124. package/dist/react/resources.js +3 -0
  125. package/dist/react/resources.js.map +1 -1
  126. package/dist/react/upload.d.ts +10 -10
  127. package/dist/react/upload.js +1 -1
  128. package/dist/react/upload.js.map +1 -1
  129. package/dist/react/use-resource.d.ts +16 -0
  130. package/dist/react/use-resource.js +20 -1
  131. package/dist/react/use-resource.js.map +1 -1
  132. package/dist/react.js +21 -20
  133. package/dist/styles.css +1 -1
  134. package/package.json +37 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taxonomy-manager.js","names":[],"sources":["../../../src/components/admin/taxonomy-manager.tsx"],"sourcesContent":["import { useEffect, useId, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport { toContentKitError, type ContentKitError } from \"../../client/errors.js\";\nimport type { Assignment, AssignmentPage, ContentRef, Edge, MergeReport, Name, NodeDetail, NodePage, NodeRow } from \"../../client/generated/wire.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { useAdminLocation, useFlowClient, useStaffAccess, type AdminLocation, type FlowClientOptions, type StaffAccess } from \"../../react/admin.js\";\nimport { useErrorReporter } from \"../../react/context.js\";\nimport { usePublicImage } from \"../../react/public.js\";\nimport { keyOf, useContentScope, useResource } from \"../../react/use-resource.js\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Input } from \"#ckui/ui/input\";\nimport { Label } from \"#ckui/ui/label\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"#ckui/ui/select\";\nimport { Skeleton } from \"#ckui/ui/skeleton\";\nimport { Tabs, TabsList, TabsTrigger } from \"#ckui/ui/tabs\";\nimport { CoverUpload } from \"../slot-upload.js\";\nimport { contentError, ErrorLine, RelativeTime, useAction } from \"../social/parts.js\";\nimport { AdminRoot, LoadFailed, NoAccess, Pager, Rows, pageOf, useConfirm, type AdminFlowProps, type AdminRouteProps } from \"./shell.js\";\n\ntype Choice = string | { value: string; label: string };\nexport type TaxonomyRelation = Edge[\"relation\"];\n\n/** One node kind the flow manages. */\nexport interface TaxonomyKind {\n /** The kind as the store registers it, e.g. \"tag\", \"series\". */\n kind: string;\n label: string;\n /** Edges a node of this kind may have, \"node is <relation> of a <to> node\": e.g. a character member_of a series. */\n relations?: readonly { relation: TaxonomyRelation; to: string; label: string; inverseLabel?: string }[];\n /** A cover in the host's media: the media kind whose items are node ids, its upload path (\"cover\") and public preset (\"cover\"). */\n cover?: { kind: string; path?: string; preset?: string };\n}\n\nexport interface TaxonomyManagerProps extends AdminFlowProps, AdminRouteProps {\n /** The kinds, in tab order; the first is at basePath. */\n kinds: readonly TaxonomyKind[];\n /** Languages names are written in; the first resolves the list's names. */\n languages?: readonly Choice[];\n /** Counts of this content kind; default every kind. */\n contentKind?: string;\n /** Host-owned fields of a node (a creator's type, a tag's restricted flag), below its names. */\n renderFields?: (node: NodeDetail) => ReactNode;\n /** One assigned content, e.g. a link with its title. Default its kind and id. */\n renderContent?: (ref: ContentRef, assignment: Assignment) => ReactNode;\n pageSize?: number;\n}\n\n/** Whether the caller may manage the taxonomy (root:taxonomy:write). */\nexport function useTaxonomyManagerAccess(o: FlowClientOptions = {}): StaffAccess<\"taxonomy\"> {\n return useStaffAccess([\"taxonomy\"] as const, o);\n}\n\nconst choices = (list?: readonly Choice[]) => (list ?? []).map((c) => (typeof c === \"string\" ? { value: c, label: c } : c));\nconst SORTS = [\"name\", \"count\", \"created\", \"updated\", \"oldest\"] as const;\nconst STATES = [\"active\", \"deleted\", \"merged\"] as const;\ntype NodeState = (typeof STATES)[number];\n\n/** A slug from a name: lowercase words joined by dashes. */\nexport function slugify(name: string): string {\n return name\n .normalize(\"NFKD\")\n .replace(/[̀-ͯ]/g, \"\")\n .toLowerCase()\n .trim()\n .replace(/[\\s/]+/g, \"-\")\n .replace(/[^\\p{L}\\p{N}-]+/gu, \"\")\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .slice(0, 200);\n}\n\n/**\n * Staff: the taxonomy per kind. Each kind's nodes by name, state, language,\n * minimum count and order; a node's names and aliases per language, host\n * fields, relations (with a typeahead), cover, counts and assigned contents;\n * create, delete, restore and merge. Kinds are at basePath/{kind}, a node at\n * basePath/{kind}/{id}, filters in the query.\n */\nexport function TaxonomyManager({ client: own, baseUrl, auth, guard, appearance, className, language, messages, ...p }: TaxonomyManagerProps) {\n const client = useFlowClient({ client: own, baseUrl, auth });\n return (\n <AdminRoot flow=\"taxonomy-manager\" appearance={appearance} className={className} language={language} messages={messages} guard={guard}>\n <Taxonomy {...p} client={client} />\n </AdminRoot>\n );\n}\n\ntype Inner = Omit<TaxonomyManagerProps, \"client\" | \"baseUrl\" | \"auth\" | \"guard\" | \"appearance\" | \"className\" | \"language\" | \"messages\"> & { client: ContentKitClient };\ntype Ctx = Inner & { loc: AdminLocation; kind: TaxonomyKind; lang: string };\n\nfunction Taxonomy({ basePath, navigation, ...p }: Inner) {\n const { t } = useMessages();\n const loc = useAdminLocation(basePath, navigation);\n const access = useTaxonomyManagerAccess({ client: p.client });\n if (access.loading) return <Rows />;\n if (!access.allowed.taxonomy) return <NoAccess>{t(\"taxonomyManager.noAccess\")}</NoAccess>;\n if (!p.kinds.length) return null;\n const [k, sub] = loc.view.split(\"/\");\n const kind = p.kinds.find((x) => x.kind === k) ?? p.kinds[0]!;\n const ctx: Ctx = { ...p, loc, kind, lang: choices(p.languages)[0]?.value ?? \"en\" };\n return (\n <>\n {p.kinds.length > 1 && (\n <Tabs value={kind.kind} onValueChange={(v) => loc.go(String(v))}>\n <TabsList>\n {p.kinds.map((x) => (\n <TabsTrigger key={x.kind} value={x.kind}>\n {x.label}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n )}\n {!sub ? <NodeList key={kind.kind} {...ctx} /> : sub === \"new\" ? <NodeCreate key={kind.kind} {...ctx} /> : <NodeView key={sub} {...ctx} id={sub} />}\n </>\n );\n}\n\nfunction NodeList({ loc, kind, client, languages: offered, contentKind, pageSize = 25, lang }: Ctx) {\n const m = useMessages();\n const { t } = m;\n const ids = useId();\n const languages = choices(offered);\n const query = loc.query.get(\"q\") ?? \"\";\n const stateParam = loc.query.get(\"state\") ?? \"\";\n const state: NodeState = (STATES as readonly string[]).includes(stateParam) ? (stateParam as NodeState) : \"active\";\n const language = loc.query.get(\"language\") || lang;\n const minCount = Math.max(0, Number(loc.query.get(\"min_count\")) || 0);\n const sortParam = loc.query.get(\"sort\") ?? \"\";\n const sort = (SORTS as readonly string[]).includes(sortParam) ? sortParam : \"name\";\n const page = pageOf(loc.query);\n const filters: { q?: string; state?: NodeState; language?: string; min_count?: number; sort?: string } = {\n q: query,\n state: state === \"active\" ? undefined : state,\n language: language === lang ? undefined : language,\n min_count: minCount || undefined,\n sort: sort === \"name\" ? undefined : sort,\n };\n const filter = (next: Partial<typeof filters>) => loc.go(kind.kind, { ...filters, ...next });\n const [text, setText] = useState(query);\n useEffect(() => setText(query), [query]);\n const { store, scope } = useContentScope(client);\n const offset = (page - 1) * pageSize;\n const r = useResource<NodePage>(store, keyOf(\"taxonomy-nodes\", scope, kind.kind, query, state, language, minCount, sort, contentKind, offset, pageSize), { type: \"taxonomy-nodes\" }, (signal) =>\n client.taxonomy.nodes(\n { kind: kind.kind, q: query || undefined, state: [state], language, min_count: minCount || undefined, sort, content_kind: contentKind, offset, limit: pageSize },\n signal,\n ),\n );\n const nodes = r.data?.nodes ?? [];\n const total = r.data?.total ?? 0;\n const loading = r.loading || !r.loaded;\n return (\n <div className=\"grid gap-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h2 className=\"text-base font-semibold\">{kind.label}</h2>\n <Button size=\"sm\" onClick={() => loc.go(`${kind.kind}/new`)}>\n {t(\"taxonomyManager.new\")}\n </Button>\n </div>\n <div className=\"grid gap-2 sm:grid-cols-[minmax(0,1fr)_auto]\">\n <form\n className=\"flex gap-2\"\n role=\"search\"\n onSubmit={(e) => {\n e.preventDefault();\n filter({ q: text.trim() });\n }}\n >\n <Label htmlFor={`${ids}-q`} className=\"sr-only\">\n {t(\"taxonomyManager.search\")}\n </Label>\n <Input id={`${ids}-q`} className=\"h-8\" type=\"search\" value={text} placeholder={t(\"taxonomyManager.search\")} onChange={(e) => setText(e.target.value)} />\n <Button type=\"submit\" size=\"sm\" variant=\"outline\">\n {t(\"moderation.filter\")}\n </Button>\n </form>\n <div className=\"flex flex-wrap gap-2\">\n <Select value={state} onValueChange={(v) => filter({ state: v === \"active\" ? undefined : (String(v) as NodeState) })}>\n <SelectTrigger size=\"sm\" aria-label={t(\"taxonomyManager.state\")}>\n <SelectValue>{(v: string) => t(`taxonomyManager.${v as NodeState}`)}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {STATES.map((s) => (\n <SelectItem key={s} value={s}>\n {t(`taxonomyManager.${s}`)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {languages.length > 1 && (\n <Select value={language} onValueChange={(v) => filter({ language: v === lang ? undefined : String(v) })}>\n <SelectTrigger size=\"sm\" aria-label={t(\"taxonomyManager.language\")}>\n <SelectValue>{(v: string) => languages.find((l) => l.value === v)?.label ?? v}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {languages.map((l) => (\n <SelectItem key={l.value} value={l.value}>\n {l.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n <Select value={sort} onValueChange={(v) => filter({ sort: v === \"name\" ? undefined : String(v) })}>\n <SelectTrigger size=\"sm\" aria-label={t(\"taxonomyManager.sort\")}>\n <SelectValue>{(v: string) => t(`taxonomyManager.sort_${v as (typeof SORTS)[number]}`)}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {SORTS.map((s) => (\n <SelectItem key={s} value={s}>\n {t(`taxonomyManager.sort_${s}`)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <div className=\"flex items-center gap-1.5\">\n <Label htmlFor={`${ids}-min`} className=\"text-xs text-muted-foreground\">\n {t(\"taxonomyManager.minCount\")}\n </Label>\n <Input\n id={`${ids}-min`}\n className=\"h-8 w-20\"\n type=\"number\"\n min={0}\n value={minCount || \"\"}\n onChange={(e) => filter({ min_count: Number(e.target.value) || undefined })}\n />\n </div>\n </div>\n </div>\n {loading && !nodes.length ? (\n <Rows />\n ) : r.error && !nodes.length ? (\n <LoadFailed error={r.error} message={t(\"taxonomyManager.loadFailed\")} retry={r.reload} />\n ) : !nodes.length ? (\n <p className=\"text-muted-foreground\">{t(\"taxonomyManager.empty\")}</p>\n ) : (\n <ul className=\"grid divide-y divide-border rounded-lg border border-border\" aria-busy={loading}>\n {nodes.map((n) => (\n <li key={n.taxonomy_id} className=\"flex flex-wrap items-center gap-3 p-3\" data-ckui=\"node-row\" data-state={n.state}>\n <div className=\"grid min-w-0 flex-1 gap-0.5\">\n <button type=\"button\" className=\"text-left font-medium break-words hover:underline\" onClick={() => loc.go(`${kind.kind}/${n.taxonomy_id}`)}>\n {n.name || n.slug}\n </button>\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground\">\n <span>{n.slug}</span>\n {n.state !== \"active\" && <Badge variant=\"outline\">{t(`taxonomyManager.${n.state}`)}</Badge>}\n <RelativeTime at={n.updated_at} />\n </div>\n </div>\n <span className=\"text-sm tabular-nums text-muted-foreground\" title={t(\"taxonomyManager.count\")}>\n {n.count}\n </span>\n </li>\n ))}\n </ul>\n )}\n {total > 0 && <p className=\"text-center text-xs text-muted-foreground\">{m.plural(\"taxonomyManager.total\", total)}</p>}\n <Pager page={page} hasNext={offset + nodes.length < total} disabled={loading} onPage={(n) => loc.go(kind.kind, { ...filters, page: n > 1 ? n : undefined })} />\n </div>\n );\n}\n\nfunction NodeCreate({ loc, kind, client, languages: offered, lang, onError }: Ctx) {\n const m = useMessages();\n const { t } = m;\n const ids = useId();\n const languages = choices(offered);\n const [names, setNames] = useState<Record<string, string>>({});\n const [slug, setSlug] = useState(\"\");\n const [slugEdited, setSlugEdited] = useState(false);\n const create = useAction(\"taxonomy.save\", onError);\n const first = names[lang] ?? \"\";\n useEffect(() => {\n if (!slugEdited) setSlug(slugify(first));\n }, [first, slugEdited]);\n const list = languages.length ? languages : [{ value: lang, label: lang }];\n const submit = async () => {\n const given: Name[] = list.filter((l) => names[l.value]?.trim()).map((l) => ({ language: l.value, kind: \"name\", name: names[l.value]!.trim(), source_revision: 0 }));\n const made = await create.run(() => client.taxonomy.createNodes([{ kind: kind.kind, slug: slug.trim(), names: given, source_revision: 0 }]));\n if (made?.[0]) loc.go(`${kind.kind}/${made[0].taxonomy_id}`, undefined, { replace: true });\n };\n return (\n <form\n className=\"grid gap-4\"\n data-ckui=\"node-create\"\n onSubmit={(e) => {\n e.preventDefault();\n void submit();\n }}\n >\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" className=\"justify-self-start\" onClick={() => loc.go(kind.kind)}>\n {t(\"taxonomyManager.back\", { kind: kind.label })}\n </Button>\n <h2 className=\"text-base font-semibold\">{t(\"taxonomyManager.newTitle\", { kind: kind.label })}</h2>\n {list.map((l, i) => (\n <div key={l.value} className=\"grid gap-1.5\">\n <Label htmlFor={`${ids}-${l.value}`}>{t(\"taxonomyManager.nameIn\", { language: l.label })}</Label>\n <Input id={`${ids}-${l.value}`} required={i === 0} value={names[l.value] ?? \"\"} onChange={(e) => setNames((n) => ({ ...n, [l.value]: e.target.value }))} />\n </div>\n ))}\n <div className=\"grid gap-1.5\">\n <Label htmlFor={`${ids}-slug`}>{t(\"taxonomyManager.slug\")}</Label>\n <Input\n id={`${ids}-slug`}\n required\n value={slug}\n onChange={(e) => {\n setSlugEdited(true);\n setSlug(e.target.value);\n }}\n />\n </div>\n {create.error && <ErrorLine>{contentError(m, create.error)}</ErrorLine>}\n <Button type=\"submit\" className=\"justify-self-start\" disabled={create.pending || !first.trim() || !slug.trim()}>\n {create.pending ? t(\"common.saving\") : t(\"taxonomyManager.create\")}\n </Button>\n </form>\n );\n}\n\nfunction NodeView({ id, loc, kind, client, lang, ...p }: Ctx & { id: string }) {\n const m = useMessages();\n const { t } = m;\n const { store, scope } = useContentScope(client);\n const r = useResource<NodeDetail>(store, keyOf(\"taxonomy-node\", scope, id), { type: \"taxonomy-node\", id }, (signal) => client.taxonomy.node(id, signal));\n const node = r.data;\n const partnerIds = useMemo(() => [...new Set((node?.edges ?? []).flatMap((e) => [e.from_taxonomy_id, e.to_taxonomy_id]).filter((x) => x !== id))].sort(), [node?.edges, id]);\n const partners = useResource<NodePage>(\n store,\n partnerIds.length ? keyOf(\"taxonomy-partners\", scope, lang, ...partnerIds) : null,\n { type: \"taxonomy-partners\" },\n (signal) => client.taxonomy.nodes({ id: partnerIds, state: [\"active\", \"merged\", \"deleted\"], language: lang, limit: Math.min(500, partnerIds.length) }, signal),\n );\n const byId = useMemo(() => new Map((partners.data?.nodes ?? []).map((n) => [n.taxonomy_id, n])), [partners.data]);\n const save = useAction(\"taxonomy.save\", p.onError);\n const { confirm, dialog } = useConfirm();\n const back = (\n <Button variant=\"ghost\" size=\"sm\" className=\"justify-self-start\" onClick={() => loc.go(kind.kind)}>\n {t(\"taxonomyManager.back\", { kind: kind.label })}\n </Button>\n );\n if (!node) {\n return (\n <>\n {back}\n {r.error ? <LoadFailed error={r.error} message={t(\"taxonomyManager.nodeLoadFailed\")} retry={r.reload} /> : <Skeleton className=\"h-40 w-full\" />}\n </>\n );\n }\n const canonical = node.names.find((n) => n.kind === \"name\" && n.language === lang) ?? node.names.find((n) => n.kind === \"name\");\n const title = canonical?.name ?? node.slug;\n const setState = async (state: \"active\" | \"deleted\") => {\n if (state === \"deleted\" && !(await confirm({ title: t(\"taxonomyManager.deleteTitle\", { name: title }), description: t(\"taxonomyManager.deleteBody\"), confirm: t(\"taxonomyManager.delete\") }))) return;\n await save.run(() => client.taxonomy.updateNode(id, { state }));\n };\n return (\n <div className=\"grid gap-5\" data-ckui=\"node-view\" data-state={node.state}>\n {back}\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"text-base font-semibold break-words\">{title}</h2>\n <Badge variant={node.state === \"active\" ? \"outline\" : \"secondary\"}>{t(`taxonomyManager.${node.state}`)}</Badge>\n <div className=\"ms-auto flex flex-wrap gap-2\">\n {node.state === \"active\" && <MergeButton node={node} title={title} kind={kind} client={client} loc={loc} lang={lang} onError={p.onError} />}\n {node.state === \"active\" ? (\n <Button size=\"sm\" variant=\"destructive\" disabled={save.pending} onClick={() => void setState(\"deleted\")}>\n {t(\"taxonomyManager.delete\")}\n </Button>\n ) : node.state === \"deleted\" ? (\n <Button size=\"sm\" variant=\"outline\" disabled={save.pending} onClick={() => void setState(\"active\")}>\n {t(\"taxonomyManager.restore\")}\n </Button>\n ) : null}\n </div>\n </div>\n {node.state === \"merged\" && <MergedInto node={node} byId={byId} kind={kind} loc={loc} />}\n <ErrorLine error={save.error} />\n <SlugField node={node} client={client} onError={p.onError} />\n <Names node={node} client={client} languages={p.languages} lang={lang} onError={p.onError} />\n {p.renderFields && <section data-ckui=\"node-fields\">{p.renderFields(node)}</section>}\n {kind.cover && <Cover node={node} cover={kind.cover} client={client} />}\n <Relations node={node} kind={kind} kinds={p.kinds} byId={byId} client={client} loc={loc} lang={lang} onError={p.onError} />\n <Counts node={node} />\n <Contents id={id} client={client} renderContent={p.renderContent} />\n {dialog}\n </div>\n );\n}\n\nfunction Section({ title, children, ckui }: { title: ReactNode; children: ReactNode; ckui: string }) {\n return (\n <section className=\"grid gap-2\" data-ckui={ckui}>\n <h3 className=\"font-medium\">{title}</h3>\n {children}\n </section>\n );\n}\n\nfunction SlugField({ node, client, onError }: { node: NodeDetail; client: ContentKitClient; onError?: Inner[\"onError\"] }) {\n const { t } = useMessages();\n const ids = useId();\n const [slug, setSlug] = useState(node.slug);\n useEffect(() => setSlug(node.slug), [node.slug]);\n const save = useAction(\"taxonomy.save\", onError);\n return (\n <form\n className=\"flex flex-wrap items-end gap-2\"\n onSubmit={(e) => {\n e.preventDefault();\n void save.run(() => client.taxonomy.updateNode(node.taxonomy_id, { slug: slug.trim() }));\n }}\n >\n <div className=\"grid min-w-48 flex-1 gap-1.5\">\n <Label htmlFor={`${ids}-slug`}>{t(\"taxonomyManager.slug\")}</Label>\n <Input id={`${ids}-slug`} className=\"h-8\" value={slug} onChange={(e) => setSlug(e.target.value)} />\n </div>\n <Button type=\"submit\" size=\"sm\" variant=\"outline\" disabled={save.pending || !slug.trim() || slug.trim() === node.slug}>\n {t(\"common.save\")}\n </Button>\n <ErrorLine error={save.error} className=\"basis-full\" />\n </form>\n );\n}\n\nfunction Names({ node, client, languages: offered, lang, onError }: { node: NodeDetail; client: ContentKitClient; languages?: readonly Choice[]; lang: string; onError?: Inner[\"onError\"] }) {\n const { t } = useMessages();\n const ids = useId();\n const languages = choices(offered);\n const list = languages.length ? languages : [{ value: lang, label: lang }];\n const [language, setLanguage] = useState(list[0]!.value);\n const [kind, setKind] = useState<Name[\"kind\"]>(\"alias\");\n const [text, setText] = useState(\"\");\n const save = useAction(\"taxonomy.save\", onError);\n const id = node.taxonomy_id;\n const label = (code: string) => list.find((l) => l.value === code)?.label ?? code;\n const sorted = [...node.names].sort((a, b) => a.language.localeCompare(b.language) || (a.kind === b.kind ? a.name.localeCompare(b.name) : a.kind === \"name\" ? -1 : 1));\n return (\n <Section title={t(\"taxonomyManager.names\")} ckui=\"node-names\">\n {sorted.length ? (\n <ul className=\"grid divide-y divide-border rounded-lg border border-border\">\n {sorted.map((n) => (\n <li key={`${n.language}:${n.name}`} className=\"flex flex-wrap items-center gap-2 p-2.5\" data-ckui=\"node-name\" data-kind={n.kind}>\n <Badge variant=\"outline\">{label(n.language)}</Badge>\n <span className=\"min-w-0 flex-1 break-words\">{n.name}</span>\n <span className=\"text-xs text-muted-foreground\">{t(n.kind === \"name\" ? \"taxonomyManager.canonical\" : \"taxonomyManager.alias\")}</span>\n {n.kind === \"alias\" && (\n <Button size=\"xs\" variant=\"ghost\" disabled={save.pending} onClick={() => void save.run(() => client.taxonomy.names(id, \"add\", [{ ...n, kind: \"name\" }]))}>\n {t(\"taxonomyManager.makeCanonical\")}\n </Button>\n )}\n <Button size=\"xs\" variant=\"ghost\" disabled={save.pending} aria-label={t(\"taxonomyManager.removeName\", { name: n.name })} onClick={() => void save.run(() => client.taxonomy.names(id, \"remove\", [n]))}>\n {t(\"common.remove\")}\n </Button>\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"text-muted-foreground\">{t(\"taxonomyManager.noNames\")}</p>\n )}\n <form\n className=\"flex flex-wrap items-end gap-2\"\n onSubmit={(e) => {\n e.preventDefault();\n const name = text.trim();\n if (!name) return;\n void save.run(() => client.taxonomy.names(id, \"add\", [{ language, kind, name, source_revision: 0 }])).then((d) => d && setText(\"\"));\n }}\n >\n {list.length > 1 && (\n <Select value={language} onValueChange={(v) => setLanguage(String(v))}>\n <SelectTrigger size=\"sm\" aria-label={t(\"taxonomyManager.language\")}>\n <SelectValue>{(v: string) => label(v)}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {list.map((l) => (\n <SelectItem key={l.value} value={l.value}>\n {l.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n <Select value={kind} onValueChange={(v) => setKind(v as Name[\"kind\"])}>\n <SelectTrigger size=\"sm\" aria-label={t(\"taxonomyManager.nameKind\")}>\n <SelectValue>{(v: string) => t(v === \"name\" ? \"taxonomyManager.canonical\" : \"taxonomyManager.alias\")}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"alias\">{t(\"taxonomyManager.alias\")}</SelectItem>\n <SelectItem value=\"name\">{t(\"taxonomyManager.canonical\")}</SelectItem>\n </SelectContent>\n </Select>\n <Label htmlFor={`${ids}-name`} className=\"sr-only\">\n {t(\"taxonomyManager.newName\")}\n </Label>\n <Input id={`${ids}-name`} className=\"h-8 min-w-40 flex-1\" value={text} placeholder={t(\"taxonomyManager.newName\")} onChange={(e) => setText(e.target.value)} />\n <Button type=\"submit\" size=\"sm\" variant=\"outline\" disabled={save.pending || !text.trim()}>\n {t(\"taxonomyManager.addName\")}\n </Button>\n </form>\n <ErrorLine error={save.error} />\n </Section>\n );\n}\n\nfunction Cover({ node, cover, client }: { node: NodeDetail; cover: NonNullable<TaxonomyKind[\"cover\"]>; client: ContentKitClient }) {\n const { t } = useMessages();\n const item = { kind: cover.kind, id: node.taxonomy_id };\n const { image } = usePublicImage(cover.kind, node.taxonomy_id, cover.preset ?? \"cover\", { client });\n return (\n <section className=\"grid max-w-xl gap-2\" data-ckui=\"node-cover\">\n <CoverUpload item={item} path={cover.path ?? \"cover\"} image={image} client={client} removable label={t(\"taxonomyManager.cover\")} />\n </section>\n );\n}\n\nfunction MergedInto({ node, byId, kind, loc }: { node: NodeDetail; byId: Map<string, NodeRow>; kind: TaxonomyKind; loc: AdminLocation }) {\n const { t } = useMessages();\n const into = node.edges.find((e) => e.relation === \"alias_of\" && e.from_taxonomy_id === node.taxonomy_id)?.to_taxonomy_id;\n if (!into) return null;\n const target = byId.get(into);\n return (\n <p className=\"text-muted-foreground\" data-ckui=\"merged-into\">\n {t(\"taxonomyManager.mergedInto\")}{\" \"}\n <button type=\"button\" className=\"font-medium text-foreground hover:underline\" onClick={() => loc.go(`${target?.kind ?? kind.kind}/${into}`)}>\n {target?.name || target?.slug || into}\n </button>\n </p>\n );\n}\n\nfunction MergeButton({ node, title, kind, client, loc, lang, onError }: { node: NodeDetail; title: string; kind: TaxonomyKind; client: ContentKitClient; loc: AdminLocation; lang: string; onError?: Inner[\"onError\"] }) {\n const { t } = useMessages();\n const [picking, setPicking] = useState(false);\n const merge = useAction(\"taxonomy.save\", onError);\n const { confirm, dialog } = useConfirm();\n const [report, setReport] = useState<MergeReport | null>(null);\n const pick = async (into: NodeRow) => {\n setPicking(false);\n const ok = await confirm({\n title: t(\"taxonomyManager.mergeTitle\", { from: title, into: into.name || into.slug }),\n description: t(\"taxonomyManager.mergeBody\"),\n confirm: t(\"taxonomyManager.merge\"),\n typed: t(\"taxonomyManager.mergeWord\"),\n });\n if (!ok) return;\n const r = await merge.run(() => client.taxonomy.merge(node.taxonomy_id, into.taxonomy_id));\n if (r) {\n setReport(r);\n loc.go(`${kind.kind}/${into.taxonomy_id}`);\n }\n };\n return (\n <>\n {picking ? (\n <div className=\"flex flex-wrap items-center gap-2\" data-ckui=\"merge-picker\">\n <NodePicker kind={kind.kind} exclude={node.taxonomy_id} client={client} lang={lang} label={t(\"taxonomyManager.mergeInto\")} onPick={(n) => void pick(n)} />\n <Button size=\"sm\" variant=\"ghost\" onClick={() => setPicking(false)}>\n {t(\"common.cancel\")}\n </Button>\n </div>\n ) : (\n <Button size=\"sm\" variant=\"outline\" disabled={merge.pending} onClick={() => setPicking(true)}>\n {t(\"taxonomyManager.merge\")}\n </Button>\n )}\n {merge.error && <ErrorLine error={merge.error} className=\"basis-full\" />}\n {report && (\n <p role=\"status\" className=\"sr-only\">\n {t(\"taxonomyManager.mergeDone\", { count: report.assignments_moved })}\n </p>\n )}\n {dialog}\n </>\n );\n}\n\n/** A typeahead over one kind's active nodes. */\nfunction NodePicker({ kind, exclude, client, lang, label, onPick }: { kind: string; exclude?: string; client: ContentKitClient; lang: string; label: string; onPick: (n: NodeRow) => void }) {\n const { t } = useMessages();\n const id = useId();\n const [text, setText] = useState(\"\");\n const [results, setResults] = useState<NodeRow[]>([]);\n const [active, setActive] = useState(0);\n const [error, setError] = useState<ContentKitError | null>(null);\n const seq = useRef(0);\n useEffect(() => {\n const q = text.trim();\n const n = ++seq.current;\n if (!q) {\n setResults([]);\n return;\n }\n const ctl = new AbortController();\n const timer = setTimeout(() => {\n client.taxonomy.nodes({ kind, q, language: lang, limit: 8, sort: \"name\" }, ctl.signal).then(\n (page) => {\n if (n !== seq.current) return;\n setError(null);\n setResults(page.nodes.filter((x) => x.taxonomy_id !== exclude));\n setActive(0);\n },\n (e) => {\n const err = toContentKitError(e);\n if (err.code !== \"aborted\" && n === seq.current) setError(err);\n },\n );\n }, 200);\n return () => {\n clearTimeout(timer);\n ctl.abort();\n };\n }, [text, kind, lang, exclude, client]);\n const open = results.length > 0;\n return (\n <div className=\"relative grid min-w-56 flex-1 gap-1\" data-ckui=\"node-picker\">\n <Input\n role=\"combobox\"\n aria-label={label}\n aria-expanded={open}\n aria-controls={`${id}-list`}\n aria-activedescendant={open ? `${id}-${active}` : undefined}\n autoComplete=\"off\"\n className=\"h-8\"\n value={text}\n placeholder={t(\"taxonomyManager.searchNodes\")}\n autoFocus\n onChange={(e) => setText(e.target.value)}\n onKeyDown={(e) => {\n if (!open) return;\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActive((a) => Math.min(results.length - 1, a + 1));\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActive((a) => Math.max(0, a - 1));\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n onPick(results[active]!);\n } else if (e.key === \"Escape\") setResults([]);\n }}\n />\n {open && (\n <ul id={`${id}-list`} role=\"listbox\" aria-label={label} className=\"absolute top-full z-10 mt-1 grid w-full overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md\">\n {results.map((n, i) => (\n <li\n key={n.taxonomy_id}\n id={`${id}-${i}`}\n role=\"option\"\n aria-selected={i === active}\n className={`cursor-pointer px-3 py-1.5 ${i === active ? \"bg-accent text-accent-foreground\" : \"\"}`}\n onMouseEnter={() => setActive(i)}\n onMouseDown={(e) => {\n e.preventDefault();\n onPick(n);\n }}\n >\n {n.name || n.slug} <span className=\"text-xs text-muted-foreground\">{n.slug}</span>\n </li>\n ))}\n </ul>\n )}\n {error && <ErrorLine error={error} />}\n </div>\n );\n}\n\nfunction Relations({\n node,\n kind,\n kinds,\n byId,\n client,\n loc,\n lang,\n onError,\n}: {\n node: NodeDetail;\n kind: TaxonomyKind;\n kinds: readonly TaxonomyKind[];\n byId: Map<string, NodeRow>;\n client: ContentKitClient;\n loc: AdminLocation;\n lang: string;\n onError?: Inner[\"onError\"];\n}) {\n const { t } = useMessages();\n const save = useAction(\"taxonomy.save\", onError);\n const [adding, setAdding] = useState<number | null>(null);\n const id = node.taxonomy_id;\n const out = node.edges.filter((e) => e.from_taxonomy_id === id && e.relation !== \"alias_of\");\n const incoming = node.edges.filter((e) => e.to_taxonomy_id === id && e.relation !== \"alias_of\");\n const own = kind.relations ?? [];\n // Relations other kinds declare toward this one, shown from this side.\n const inverse = kinds.flatMap((k) => (k.relations ?? []).filter((r) => r.to === kind.kind).map((r) => ({ ...r, from: k })));\n const link = (other: string, fallbackKind: string) => {\n const n = byId.get(other);\n return (\n <button type=\"button\" className=\"font-medium hover:underline\" onClick={() => loc.go(`${n?.kind ?? fallbackKind}/${other}`)}>\n {n?.name || n?.slug || other}\n </button>\n );\n };\n if (!own.length && !inverse.length && !out.length && !incoming.length) return null;\n return (\n <Section title={t(\"taxonomyManager.relations\")} ckui=\"node-relations\">\n {own.map((r, i) => {\n const edges = out.filter((e) => e.relation === r.relation && (byId.get(e.to_taxonomy_id)?.kind ?? r.to) === r.to);\n return (\n <div key={`${r.relation}:${r.to}`} className=\"grid gap-1.5\" data-ckui=\"relation\" data-relation={r.relation}>\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">{r.label}</span>\n {edges.map((e) => (\n <span key={e.to_taxonomy_id} className=\"inline-flex items-center gap-1 rounded-md border border-border px-2 py-0.5\" data-ckui=\"edge\">\n {link(e.to_taxonomy_id, r.to)}\n <button\n type=\"button\"\n className=\"text-muted-foreground hover:text-destructive\"\n aria-label={t(\"taxonomyManager.removeRelation\", { name: byId.get(e.to_taxonomy_id)?.name ?? e.to_taxonomy_id })}\n disabled={save.pending}\n onClick={() => void save.run(() => client.taxonomy.edges(\"remove\", [e]))}\n >\n ×\n </button>\n </span>\n ))}\n {adding !== i && (\n <Button size=\"xs\" variant=\"ghost\" onClick={() => setAdding(i)}>\n {t(\"taxonomyManager.addRelation\", { relation: r.label })}\n </Button>\n )}\n </div>\n {adding === i && (\n <div className=\"flex flex-wrap items-center gap-2\">\n <NodePicker\n kind={r.to}\n exclude={id}\n client={client}\n lang={lang}\n label={r.label}\n onPick={(n) => {\n setAdding(null);\n void save.run(() => client.taxonomy.edges(\"add\", [{ from_taxonomy_id: id, relation: r.relation, to_taxonomy_id: n.taxonomy_id, source_revision: 0 }]));\n }}\n />\n <Button size=\"sm\" variant=\"ghost\" onClick={() => setAdding(null)}>\n {t(\"common.cancel\")}\n </Button>\n </div>\n )}\n </div>\n );\n })}\n {inverse.map((r) => {\n const edges = incoming.filter((e) => e.relation === r.relation && (byId.get(e.from_taxonomy_id)?.kind ?? r.from.kind) === r.from.kind);\n if (!edges.length) return null;\n return (\n <div key={`in:${r.relation}:${r.from.kind}`} className=\"flex flex-wrap items-center gap-2\" data-ckui=\"relation\" data-relation={`inverse:${r.relation}`}>\n <span className=\"text-sm text-muted-foreground\">{r.inverseLabel ?? r.from.label}</span>\n {edges.map((e) => (\n <span key={e.from_taxonomy_id} className=\"rounded-md border border-border px-2 py-0.5\" data-ckui=\"edge\">\n {link(e.from_taxonomy_id, r.from.kind)}\n </span>\n ))}\n </div>\n );\n })}\n <ErrorLine error={save.error} />\n </Section>\n );\n}\n\nfunction Counts({ node }: { node: NodeDetail }) {\n const { t } = useMessages();\n return (\n <Section title={t(\"taxonomyManager.counts\")} ckui=\"node-counts\">\n {node.counts.length ? (\n <ul className=\"flex flex-wrap gap-2\">\n {node.counts.map((c) => (\n <li key={`${c.content_kind}:${c.language}`} className=\"rounded-md border border-border px-2 py-1 text-xs\">\n {c.content_kind} · {c.language}: <span className=\"tabular-nums font-medium\">{c.count}</span>\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"text-muted-foreground\">{t(\"taxonomyManager.noCounts\")}</p>\n )}\n </Section>\n );\n}\n\nfunction Contents({ id, client, renderContent }: { id: string; client: ContentKitClient; renderContent?: Inner[\"renderContent\"] }) {\n const { t } = useMessages();\n const report = useErrorReporter();\n const [pages, setPages] = useState<AssignmentPage[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<ContentKitError | null>(null);\n const load = async (cursor?: string) => {\n setLoading(true);\n setError(null);\n try {\n const page = await client.taxonomy.nodeAssignments(id, { cursor, limit: 25 });\n setPages((ps) => (cursor ? [...ps, page] : [page]));\n } catch (e) {\n const err = toContentKitError(e);\n setError(err);\n report(err, \"taxonomy.load\");\n } finally {\n setLoading(false);\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(() => void load(), [id, client]);\n const items = pages.flatMap((p) => p.assignments);\n const next = pages.at(-1)?.next_cursor;\n return (\n <Section title={t(\"taxonomyManager.contents\")} ckui=\"node-contents\">\n {loading && !items.length ? (\n <Rows count={2} />\n ) : error && !items.length ? (\n <LoadFailed error={error} message={t(\"taxonomyManager.contentsLoadFailed\")} retry={() => void load()} />\n ) : !items.length ? (\n <p className=\"text-muted-foreground\">{t(\"taxonomyManager.noContents\")}</p>\n ) : (\n <ul className=\"grid divide-y divide-border rounded-lg border border-border\">\n {items.map((a) => (\n <li\n key={`${a.content_kind}/${a.content_id}/${a.content_version_id ?? \"\"}/${a.relation}`}\n className=\"flex flex-wrap items-center gap-2 p-2.5\"\n data-ckui=\"node-content\"\n data-state={a.state}\n >\n <span className=\"min-w-0 flex-1 break-words\">\n {renderContent ? renderContent(a, a) : `${a.content_kind}/${a.content_id}${a.content_version_id ? ` (${a.content_version_id})` : \"\"}`}\n </span>\n <span className=\"text-xs text-muted-foreground\">{a.relation}</span>\n {a.state === \"proposed\" && <Badge variant=\"secondary\">{t(\"taxonomyManager.proposed\")}</Badge>}\n </li>\n ))}\n </ul>\n )}\n {next && (\n <Button variant=\"outline\" size=\"sm\" className=\"justify-self-center\" disabled={loading} onClick={() => void load(next)}>\n {t(\"moderation.loadMore\")}\n </Button>\n )}\n </Section>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { FileInfo, RefBody } from '../../client/generated/wire.js';
2
+ import { AdminFlowProps } from './shell.js';
3
+ export interface UploadQueueProps extends AdminFlowProps {
4
+ /** Makes the host's item for a file (e.g. a video record) and resolves with its ref; once per file, a reload included. */
5
+ createItem: (file: File) => Promise<RefBody>;
6
+ /** The upload path in each item. Default "source". */
7
+ path?: string;
8
+ /** The file picker's accept, e.g. "video/*". */
9
+ accept?: string;
10
+ /** Files uploading at once. Default 2. */
11
+ concurrency?: number;
12
+ /** Each committed file: its item and the upload as an editor reads it. */
13
+ onUploaded?: (ref: RefBody, file: FileInfo) => void;
14
+ /** The localStorage key unfinished uploads are kept under, to resume after a reload. Default "ckui.uploads". */
15
+ storageKey?: string;
16
+ }
17
+ /**
18
+ * Many files, each into its own new item (createItem): uploads in the
19
+ * background with progress, pause, retry and resume. An unfinished upload is
20
+ * kept in localStorage; adding the same file after a reload continues it in
21
+ * the same item. Leaving the page while files upload asks first.
22
+ */
23
+ export declare function UploadQueue({ client: own, baseUrl, auth, guard, appearance, className, language, messages, ...p }: UploadQueueProps): import('react').JSX.Element;
@@ -0,0 +1,365 @@
1
+ import { toContentKitError as e } from "../../client/errors.js";
2
+ import { samePath as t } from "../../client/media/client.js";
3
+ import { megabytes as n } from "../../i18n/messages.js";
4
+ import { useMessages as r } from "../../i18n/context.js";
5
+ import { useErrorReporter as i, useGuarded as a } from "../../react/context.js";
6
+ import { Button as o } from "../../ui/button.js";
7
+ import { Badge as s } from "../../ui/badge.js";
8
+ import { ErrorLine as c } from "../social/parts.js";
9
+ import { AdminRoot as l } from "./shell.js";
10
+ import { useFlowClient as u } from "../../react/admin.js";
11
+ import { useCallback as d, useEffect as f, useRef as p, useState as m } from "react";
12
+ import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
13
+ import { cn as v } from "cn";
14
+ //#region src/components/admin/upload-queue.tsx
15
+ var y = [
16
+ "creating",
17
+ "uploading",
18
+ "committing"
19
+ ], b = (e) => `${e.name}\u0000${e.size}\u0000${e.lastModified}`, x = 0;
20
+ function S(e) {
21
+ try {
22
+ return JSON.parse(localStorage.getItem(e) ?? "{}");
23
+ } catch {
24
+ return {};
25
+ }
26
+ }
27
+ function C(e, t) {
28
+ try {
29
+ let n = S(e);
30
+ t(n), Object.keys(n).length ? localStorage.setItem(e, JSON.stringify(n)) : localStorage.removeItem(e);
31
+ } catch {}
32
+ }
33
+ function w({ client: e, baseUrl: t, auth: n, guard: r, appearance: i, className: a, language: o, messages: s, ...c }) {
34
+ let d = u({
35
+ client: e,
36
+ baseUrl: t,
37
+ auth: n
38
+ });
39
+ return /* @__PURE__ */ g(l, {
40
+ flow: "upload-queue",
41
+ appearance: i,
42
+ className: a,
43
+ language: o,
44
+ messages: s,
45
+ guard: r,
46
+ children: /* @__PURE__ */ g(T, {
47
+ ...c,
48
+ client: d
49
+ })
50
+ });
51
+ }
52
+ function T({ client: l, createItem: u, path: w = "source", accept: T, concurrency: E = 2, onUploaded: D, storageKey: O = "ckui.uploads", onError: k }) {
53
+ let A = r(), { t: j } = A, M = i(k), N = a(), [P, F] = m([]), [I, L] = m(() => Object.values(S(O))), [R, z] = m(!1), B = p(null), V = p(/* @__PURE__ */ new Map()), H = p({
54
+ createItem: u,
55
+ onUploaded: D
56
+ });
57
+ f(() => {
58
+ H.current = {
59
+ createItem: u,
60
+ onUploaded: D
61
+ };
62
+ });
63
+ let U = d((e, t) => F((n) => n.map((n) => n.id === e ? {
64
+ ...n,
65
+ ...t
66
+ } : n)), []), W = d(async (n) => {
67
+ let r = new AbortController();
68
+ V.current.set(n.id, r);
69
+ let i = S(O)[n.key];
70
+ try {
71
+ let a = n.ref ?? i?.ref;
72
+ if (!a) {
73
+ U(n.id, {
74
+ status: "creating",
75
+ error: void 0
76
+ }), a = await H.current.createItem(n.file);
77
+ let e = a;
78
+ C(O, (t) => void (t[n.key] = {
79
+ ref: e,
80
+ name: n.file.name,
81
+ size: n.file.size
82
+ }));
83
+ }
84
+ let o = a;
85
+ U(n.id, {
86
+ status: "uploading",
87
+ ref: a,
88
+ error: void 0
89
+ });
90
+ let s = {
91
+ ref: a,
92
+ path: w,
93
+ signal: r.signal,
94
+ onProgress: (e) => U(n.id, { progress: e }),
95
+ onState: (e) => C(O, (t) => void (t[n.key] = {
96
+ ref: o,
97
+ name: n.file.name,
98
+ size: n.file.size,
99
+ state: e ?? void 0
100
+ }))
101
+ }, c = await N(async () => {
102
+ try {
103
+ return await l.media.upload(n.file, {
104
+ ...s,
105
+ resume: i?.state
106
+ });
107
+ } catch (t) {
108
+ if (i?.state && e(t).code === "resume_mismatch") return l.media.upload(n.file, s);
109
+ throw t;
110
+ }
111
+ });
112
+ U(n.id, { status: "committing" });
113
+ let u = await N(() => l.media.commit(o, [{
114
+ op: "put",
115
+ path: c.path,
116
+ blob: c.blob
117
+ }], { signal: r.signal }));
118
+ C(O, (e) => void delete e[n.key]), U(n.id, {
119
+ status: "done",
120
+ progress: void 0
121
+ });
122
+ let d = u.find((e) => t(e.path, c.path));
123
+ d && H.current.onUploaded?.(o, d);
124
+ } catch (t) {
125
+ let r = e(t);
126
+ r.code === "aborted" ? U(n.id, { status: "paused" }) : (U(n.id, {
127
+ status: "failed",
128
+ error: r
129
+ }), M(r, "upload", n.file.name));
130
+ } finally {
131
+ V.current.delete(n.id);
132
+ }
133
+ }, [
134
+ l,
135
+ w,
136
+ O,
137
+ N,
138
+ U,
139
+ M
140
+ ]);
141
+ f(() => {
142
+ let e = P.filter((e) => y.includes(e.status)).length, t = P.filter((e) => e.status === "queued").slice(0, Math.max(0, E - e));
143
+ if (t.length) {
144
+ F((e) => e.map((e) => t.some((t) => t.id === e.id) ? {
145
+ ...e,
146
+ status: "creating"
147
+ } : e));
148
+ for (let e of t) W(e);
149
+ }
150
+ }, [
151
+ P,
152
+ E,
153
+ W
154
+ ]);
155
+ let G = P.some((e) => y.includes(e.status) || e.status === "queued");
156
+ f(() => {
157
+ if (!G) return;
158
+ let e = (e) => {
159
+ e.preventDefault(), e.returnValue = "";
160
+ };
161
+ return addEventListener("beforeunload", e), () => removeEventListener("beforeunload", e);
162
+ }, [G]), f(() => {
163
+ let e = V.current;
164
+ return () => {
165
+ for (let t of e.values()) t.abort();
166
+ };
167
+ }, []);
168
+ let K = (e) => {
169
+ let t = S(O), n = [];
170
+ for (let r of e) {
171
+ let e = b(r);
172
+ P.some((t) => t.key === e && t.status !== "done") || n.some((t) => t.key === e) || n.push({
173
+ id: `u${++x}`,
174
+ file: r,
175
+ key: e,
176
+ status: "queued",
177
+ ref: t[e]?.ref,
178
+ resumed: !!t[e]
179
+ });
180
+ }
181
+ n.length && (L((e) => e.filter((e) => !n.some((t) => t.file.name === e.name && t.file.size === e.size))), F((e) => [...e, ...n]));
182
+ }, q = (e) => {
183
+ for (let [t, n] of V.current) (!e || t === e) && n.abort();
184
+ F((t) => t.map((t) => t.status === "queued" && (!e || t.id === e) ? {
185
+ ...t,
186
+ status: "paused"
187
+ } : t));
188
+ }, J = (e) => F((t) => t.map((t) => (t.status === "paused" || t.status === "failed") && (!e || t.id === e) ? {
189
+ ...t,
190
+ status: "queued",
191
+ error: void 0
192
+ } : t)), Y = (e) => {
193
+ V.current.get(e.id)?.abort(), e.status !== "done" && C(O, (t) => void delete t[e.key]), F((t) => t.filter((t) => t.id !== e.id));
194
+ }, X = (e) => {
195
+ C(O, (t) => {
196
+ for (let [n, r] of Object.entries(t)) r.name === e.name && r.size === e.size && delete t[n];
197
+ }), L((t) => t.filter((t) => t !== e));
198
+ }, Z = P.filter((e) => e.status === "done").length, Q = P.some((e) => y.includes(e.status) || e.status === "queued"), ee = P.some((e) => e.status === "paused" || e.status === "failed"), $ = (e) => e.progress?.total ? Math.round(e.progress.loaded / e.progress.total * 100) : 0;
199
+ return /* @__PURE__ */ _(h, { children: [
200
+ /* @__PURE__ */ _("div", {
201
+ className: v("grid justify-items-center gap-2 rounded-lg border-2 border-dashed border-border p-6 text-center transition-colors", R && "border-primary bg-accent"),
202
+ "data-ckui": "upload-drop",
203
+ onDragOver: (e) => {
204
+ e.preventDefault(), z(!0);
205
+ },
206
+ onDragLeave: () => z(!1),
207
+ onDrop: (e) => {
208
+ e.preventDefault(), z(!1), K(e.dataTransfer.files);
209
+ },
210
+ children: [
211
+ /* @__PURE__ */ g("p", {
212
+ className: "text-muted-foreground",
213
+ children: j("uploadQueue.drop")
214
+ }),
215
+ /* @__PURE__ */ g(o, {
216
+ size: "sm",
217
+ onClick: () => B.current?.click(),
218
+ children: j("uploadQueue.add")
219
+ }),
220
+ /* @__PURE__ */ g("input", {
221
+ ref: B,
222
+ type: "file",
223
+ multiple: !0,
224
+ hidden: !0,
225
+ accept: T,
226
+ "aria-label": j("uploadQueue.add"),
227
+ onChange: (e) => {
228
+ K(e.target.files ?? []), e.target.value = "";
229
+ }
230
+ })
231
+ ]
232
+ }),
233
+ I.length > 0 && /* @__PURE__ */ _("div", {
234
+ className: "grid gap-2 rounded-lg border border-border p-3",
235
+ "data-ckui": "upload-waiting",
236
+ role: "status",
237
+ children: [
238
+ /* @__PURE__ */ g("p", {
239
+ className: "font-medium",
240
+ children: j("uploadQueue.unfinished")
241
+ }),
242
+ /* @__PURE__ */ g("ul", {
243
+ className: "grid gap-1",
244
+ children: I.map((e) => /* @__PURE__ */ _("li", {
245
+ className: "flex flex-wrap items-center gap-2",
246
+ children: [
247
+ /* @__PURE__ */ g("span", {
248
+ className: "min-w-0 flex-1 break-all",
249
+ children: e.name
250
+ }),
251
+ /* @__PURE__ */ g("span", {
252
+ className: "text-xs text-muted-foreground",
253
+ children: n(e.size)
254
+ }),
255
+ /* @__PURE__ */ g(o, {
256
+ size: "xs",
257
+ variant: "ghost",
258
+ onClick: () => X(e),
259
+ children: j("uploadQueue.forget")
260
+ })
261
+ ]
262
+ }, `${e.name}:${e.size}`))
263
+ }),
264
+ /* @__PURE__ */ g("p", {
265
+ className: "text-xs text-muted-foreground",
266
+ children: j("uploadQueue.unfinishedHint")
267
+ })
268
+ ]
269
+ }),
270
+ P.length > 0 && /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ _("div", {
271
+ className: "flex flex-wrap items-center gap-2",
272
+ children: [/* @__PURE__ */ g("p", {
273
+ className: "text-muted-foreground",
274
+ "aria-live": "polite",
275
+ children: j("uploadQueue.summary", {
276
+ done: Z,
277
+ total: P.length
278
+ })
279
+ }), /* @__PURE__ */ _("div", {
280
+ className: "ms-auto flex gap-2",
281
+ children: [Q && /* @__PURE__ */ g(o, {
282
+ size: "sm",
283
+ variant: "outline",
284
+ onClick: () => q(),
285
+ children: j("uploadQueue.pauseAll")
286
+ }), ee && /* @__PURE__ */ g(o, {
287
+ size: "sm",
288
+ variant: "outline",
289
+ onClick: () => J(),
290
+ children: j("uploadQueue.resumeAll")
291
+ })]
292
+ })]
293
+ }), /* @__PURE__ */ g("ul", {
294
+ className: "grid divide-y divide-border rounded-lg border border-border",
295
+ children: P.map((e) => /* @__PURE__ */ _("li", {
296
+ className: "grid gap-1.5 p-3",
297
+ "data-ckui": "upload-entry",
298
+ "data-status": e.status,
299
+ children: [
300
+ /* @__PURE__ */ _("div", {
301
+ className: "flex flex-wrap items-center gap-2",
302
+ children: [
303
+ /* @__PURE__ */ g("span", {
304
+ className: "min-w-0 flex-1 font-medium break-all",
305
+ children: e.file.name
306
+ }),
307
+ /* @__PURE__ */ g("span", {
308
+ className: "text-xs text-muted-foreground",
309
+ children: n(e.file.size)
310
+ }),
311
+ e.resumed && e.status !== "done" && /* @__PURE__ */ g(s, {
312
+ variant: "secondary",
313
+ children: j("uploadQueue.resumed")
314
+ }),
315
+ /* @__PURE__ */ g(s, {
316
+ variant: e.status === "failed" ? "destructive" : e.status === "done" ? "outline" : "secondary",
317
+ children: j(`uploadQueue.${e.status}`)
318
+ })
319
+ ]
320
+ }),
321
+ e.status === "uploading" && /* @__PURE__ */ g("div", {
322
+ className: "h-1.5 overflow-hidden rounded-full bg-muted",
323
+ role: "progressbar",
324
+ "aria-label": e.file.name,
325
+ "aria-valuenow": $(e),
326
+ "aria-valuemin": 0,
327
+ "aria-valuemax": 100,
328
+ children: /* @__PURE__ */ g("div", {
329
+ className: "h-full bg-primary transition-[width]",
330
+ style: { width: `${$(e)}%` }
331
+ })
332
+ }),
333
+ e.error && /* @__PURE__ */ g(c, { children: A.error(e.error) }),
334
+ /* @__PURE__ */ _("div", {
335
+ className: "flex flex-wrap gap-2",
336
+ children: [
337
+ (y.includes(e.status) || e.status === "queued") && /* @__PURE__ */ g(o, {
338
+ size: "xs",
339
+ variant: "ghost",
340
+ onClick: () => q(e.id),
341
+ children: j("uploadQueue.pause")
342
+ }),
343
+ (e.status === "paused" || e.status === "failed") && /* @__PURE__ */ g(o, {
344
+ size: "xs",
345
+ variant: "outline",
346
+ onClick: () => J(e.id),
347
+ children: j(e.status === "failed" ? "common.retry" : "uploadQueue.resume")
348
+ }),
349
+ e.status !== "done" && /* @__PURE__ */ g(o, {
350
+ size: "xs",
351
+ variant: "ghost",
352
+ onClick: () => Y(e),
353
+ children: j("common.remove")
354
+ })
355
+ ]
356
+ })
357
+ ]
358
+ }, e.id))
359
+ })] })
360
+ ] });
361
+ }
362
+ //#endregion
363
+ export { w as UploadQueue };
364
+
365
+ //# sourceMappingURL=upload-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-queue.js","names":[],"sources":["../../../src/components/admin/upload-queue.tsx"],"sourcesContent":["import { cn } from \"cn\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport { toContentKitError, type ContentKitError } from \"../../client/errors.js\";\nimport type { FileInfo, RefBody } from \"../../client/generated/wire.js\";\nimport { samePath, type Progress, type UploadState } from \"../../client/media/client.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { megabytes } from \"../../i18n/messages.js\";\nimport { useFlowClient } from \"../../react/admin.js\";\nimport { useErrorReporter, useGuarded } from \"../../react/context.js\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { Button } from \"#ckui/ui/button\";\nimport { ErrorLine } from \"../social/parts.js\";\nimport { AdminRoot, type AdminFlowProps } from \"./shell.js\";\n\nexport interface UploadQueueProps extends AdminFlowProps {\n /** Makes the host's item for a file (e.g. a video record) and resolves with its ref; once per file, a reload included. */\n createItem: (file: File) => Promise<RefBody>;\n /** The upload path in each item. Default \"source\". */\n path?: string;\n /** The file picker's accept, e.g. \"video/*\". */\n accept?: string;\n /** Files uploading at once. Default 2. */\n concurrency?: number;\n /** Each committed file: its item and the upload as an editor reads it. */\n onUploaded?: (ref: RefBody, file: FileInfo) => void;\n /** The localStorage key unfinished uploads are kept under, to resume after a reload. Default \"ckui.uploads\". */\n storageKey?: string;\n}\n\ntype Status = \"queued\" | \"creating\" | \"uploading\" | \"committing\" | \"done\" | \"failed\" | \"paused\";\n\ninterface Entry {\n id: string;\n file: File;\n key: string;\n status: Status;\n progress?: Progress;\n ref?: RefBody;\n error?: ContentKitError;\n /** Resumed from an upload saved before a reload. */\n resumed?: boolean;\n}\n\ninterface Saved {\n ref: RefBody;\n name: string;\n size: number;\n state?: UploadState;\n}\n\nconst ACTIVE: readonly Status[] = [\"creating\", \"uploading\", \"committing\"];\nconst fingerprint = (f: File) => `${f.name}\\u0000${f.size}\\u0000${f.lastModified}`;\nlet seq = 0;\n\nfunction readSaved(key: string): Record<string, Saved> {\n try {\n return JSON.parse(localStorage.getItem(key) ?? \"{}\") as Record<string, Saved>;\n } catch {\n return {};\n }\n}\n\nfunction writeSaved(key: string, fn: (all: Record<string, Saved>) => void) {\n try {\n const all = readSaved(key);\n fn(all);\n if (Object.keys(all).length) localStorage.setItem(key, JSON.stringify(all));\n else localStorage.removeItem(key);\n } catch {\n // Without storage, a reload starts over.\n }\n}\n\n/**\n * Many files, each into its own new item (createItem): uploads in the\n * background with progress, pause, retry and resume. An unfinished upload is\n * kept in localStorage; adding the same file after a reload continues it in\n * the same item. Leaving the page while files upload asks first.\n */\nexport function UploadQueue({ client: own, baseUrl, auth, guard, appearance, className, language, messages, ...p }: UploadQueueProps) {\n const client = useFlowClient({ client: own, baseUrl, auth });\n return (\n <AdminRoot flow=\"upload-queue\" appearance={appearance} className={className} language={language} messages={messages} guard={guard}>\n <Queue {...p} client={client} />\n </AdminRoot>\n );\n}\n\ntype Inner = Omit<UploadQueueProps, \"client\" | \"baseUrl\" | \"auth\" | \"guard\" | \"appearance\" | \"className\" | \"language\" | \"messages\"> & { client: ContentKitClient };\n\nfunction Queue({ client, createItem, path = \"source\", accept, concurrency = 2, onUploaded, storageKey = \"ckui.uploads\", onError }: Inner) {\n const m = useMessages();\n const { t } = m;\n const report = useErrorReporter(onError);\n const guarded = useGuarded();\n const [entries, setEntries] = useState<Entry[]>([]);\n const [waiting, setWaiting] = useState<Saved[]>(() => Object.values(readSaved(storageKey)));\n const [over, setOver] = useState(false);\n const input = useRef<HTMLInputElement>(null);\n const controllers = useRef(new Map<string, AbortController>());\n const latest = useRef({ createItem, onUploaded });\n useEffect(() => {\n latest.current = { createItem, onUploaded };\n });\n\n const patch = useCallback((id: string, next: Partial<Entry>) => setEntries((es) => es.map((e) => (e.id === id ? { ...e, ...next } : e))), []);\n\n const run = useCallback(\n async (entry: Entry) => {\n const ctl = new AbortController();\n controllers.current.set(entry.id, ctl);\n const saved = readSaved(storageKey)[entry.key];\n try {\n let ref = entry.ref ?? saved?.ref;\n if (!ref) {\n patch(entry.id, { status: \"creating\", error: undefined });\n ref = await latest.current.createItem(entry.file);\n const made = ref;\n writeSaved(storageKey, (all) => void (all[entry.key] = { ref: made, name: entry.file.name, size: entry.file.size }));\n }\n const target = ref;\n patch(entry.id, { status: \"uploading\", ref, error: undefined });\n const remember = (state: UploadState | null) =>\n writeSaved(storageKey, (all) => void (all[entry.key] = { ref: target, name: entry.file.name, size: entry.file.size, state: state ?? undefined }));\n const options = { ref, path, signal: ctl.signal, onProgress: (progress: Progress) => patch(entry.id, { progress }), onState: remember };\n const up = await guarded(async () => {\n try {\n return await client.media.upload(entry.file, { ...options, resume: saved?.state });\n } catch (e) {\n if (saved?.state && toContentKitError(e).code === \"resume_mismatch\") return client.media.upload(entry.file, options);\n throw e;\n }\n });\n patch(entry.id, { status: \"committing\" });\n const files = await guarded(() => client.media.commit(target, [{ op: \"put\", path: up.path, blob: up.blob }], { signal: ctl.signal }));\n writeSaved(storageKey, (all) => void delete all[entry.key]);\n patch(entry.id, { status: \"done\", progress: undefined });\n const file = files.find((f) => samePath(f.path, up.path));\n if (file) latest.current.onUploaded?.(target, file);\n } catch (e) {\n const error = toContentKitError(e);\n if (error.code === \"aborted\") patch(entry.id, { status: \"paused\" });\n else {\n patch(entry.id, { status: \"failed\", error });\n report(error, \"upload\", entry.file.name);\n }\n } finally {\n controllers.current.delete(entry.id);\n }\n },\n [client, path, storageKey, guarded, patch, report],\n );\n\n // Starts queued files while fewer than concurrency run.\n useEffect(() => {\n const active = entries.filter((e) => ACTIVE.includes(e.status)).length;\n const next = entries.filter((e) => e.status === \"queued\").slice(0, Math.max(0, concurrency - active));\n if (!next.length) return;\n setEntries((es) => es.map((e) => (next.some((n) => n.id === e.id) ? { ...e, status: \"creating\" } : e)));\n for (const e of next) void run(e);\n }, [entries, concurrency, run]);\n\n const busy = entries.some((e) => ACTIVE.includes(e.status) || e.status === \"queued\");\n useEffect(() => {\n if (!busy) return;\n const ask = (e: BeforeUnloadEvent) => {\n e.preventDefault();\n e.returnValue = \"\";\n };\n addEventListener(\"beforeunload\", ask);\n return () => removeEventListener(\"beforeunload\", ask);\n }, [busy]);\n useEffect(() => {\n const running = controllers.current;\n return () => {\n for (const c of running.values()) c.abort();\n };\n }, []);\n\n const add = (files: Iterable<File>) => {\n const saved = readSaved(storageKey);\n const added: Entry[] = [];\n for (const file of files) {\n const key = fingerprint(file);\n if (entries.some((e) => e.key === key && e.status !== \"done\") || added.some((e) => e.key === key)) continue;\n added.push({ id: `u${++seq}`, file, key, status: \"queued\", ref: saved[key]?.ref, resumed: !!saved[key] });\n }\n if (!added.length) return;\n setWaiting((w) => w.filter((s) => !added.some((a) => a.file.name === s.name && a.file.size === s.size)));\n setEntries((es) => [...es, ...added]);\n };\n const pause = (id?: string) => {\n for (const [k, c] of controllers.current) if (!id || k === id) c.abort();\n setEntries((es) => es.map((e) => (e.status === \"queued\" && (!id || e.id === id) ? { ...e, status: \"paused\" } : e)));\n };\n const resume = (id?: string) => setEntries((es) => es.map((e) => ((e.status === \"paused\" || e.status === \"failed\") && (!id || e.id === id) ? { ...e, status: \"queued\", error: undefined } : e)));\n const remove = (entry: Entry) => {\n controllers.current.get(entry.id)?.abort();\n if (entry.status !== \"done\") writeSaved(storageKey, (all) => void delete all[entry.key]);\n setEntries((es) => es.filter((e) => e.id !== entry.id));\n };\n const forget = (s: Saved) => {\n writeSaved(storageKey, (all) => {\n for (const [k, v] of Object.entries(all)) if (v.name === s.name && v.size === s.size) delete all[k];\n });\n setWaiting((w) => w.filter((x) => x !== s));\n };\n\n const done = entries.filter((e) => e.status === \"done\").length;\n const pausable = entries.some((e) => ACTIVE.includes(e.status) || e.status === \"queued\");\n const resumable = entries.some((e) => e.status === \"paused\" || e.status === \"failed\");\n const percent = (e: Entry) => (e.progress?.total ? Math.round((e.progress.loaded / e.progress.total) * 100) : 0);\n return (\n <>\n <div\n className={cn(\"grid justify-items-center gap-2 rounded-lg border-2 border-dashed border-border p-6 text-center transition-colors\", over && \"border-primary bg-accent\")}\n data-ckui=\"upload-drop\"\n onDragOver={(e) => {\n e.preventDefault();\n setOver(true);\n }}\n onDragLeave={() => setOver(false)}\n onDrop={(e) => {\n e.preventDefault();\n setOver(false);\n add(e.dataTransfer.files);\n }}\n >\n <p className=\"text-muted-foreground\">{t(\"uploadQueue.drop\")}</p>\n <Button size=\"sm\" onClick={() => input.current?.click()}>\n {t(\"uploadQueue.add\")}\n </Button>\n <input\n ref={input}\n type=\"file\"\n multiple\n hidden\n accept={accept}\n aria-label={t(\"uploadQueue.add\")}\n onChange={(e) => {\n add(e.target.files ?? []);\n e.target.value = \"\";\n }}\n />\n </div>\n {waiting.length > 0 && (\n <div className=\"grid gap-2 rounded-lg border border-border p-3\" data-ckui=\"upload-waiting\" role=\"status\">\n <p className=\"font-medium\">{t(\"uploadQueue.unfinished\")}</p>\n <ul className=\"grid gap-1\">\n {waiting.map((s) => (\n <li key={`${s.name}:${s.size}`} className=\"flex flex-wrap items-center gap-2\">\n <span className=\"min-w-0 flex-1 break-all\">{s.name}</span>\n <span className=\"text-xs text-muted-foreground\">{megabytes(s.size)}</span>\n <Button size=\"xs\" variant=\"ghost\" onClick={() => forget(s)}>\n {t(\"uploadQueue.forget\")}\n </Button>\n </li>\n ))}\n </ul>\n <p className=\"text-xs text-muted-foreground\">{t(\"uploadQueue.unfinishedHint\")}</p>\n </div>\n )}\n {entries.length > 0 && (\n <>\n <div className=\"flex flex-wrap items-center gap-2\">\n <p className=\"text-muted-foreground\" aria-live=\"polite\">\n {t(\"uploadQueue.summary\", { done, total: entries.length })}\n </p>\n <div className=\"ms-auto flex gap-2\">\n {pausable && (\n <Button size=\"sm\" variant=\"outline\" onClick={() => pause()}>\n {t(\"uploadQueue.pauseAll\")}\n </Button>\n )}\n {resumable && (\n <Button size=\"sm\" variant=\"outline\" onClick={() => resume()}>\n {t(\"uploadQueue.resumeAll\")}\n </Button>\n )}\n </div>\n </div>\n <ul className=\"grid divide-y divide-border rounded-lg border border-border\">\n {entries.map((e) => (\n <li key={e.id} className=\"grid gap-1.5 p-3\" data-ckui=\"upload-entry\" data-status={e.status}>\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"min-w-0 flex-1 font-medium break-all\">{e.file.name}</span>\n <span className=\"text-xs text-muted-foreground\">{megabytes(e.file.size)}</span>\n {e.resumed && e.status !== \"done\" && <Badge variant=\"secondary\">{t(\"uploadQueue.resumed\")}</Badge>}\n <Badge variant={e.status === \"failed\" ? \"destructive\" : e.status === \"done\" ? \"outline\" : \"secondary\"}>{t(`uploadQueue.${e.status}`)}</Badge>\n </div>\n {e.status === \"uploading\" && (\n <div className=\"h-1.5 overflow-hidden rounded-full bg-muted\" role=\"progressbar\" aria-label={e.file.name} aria-valuenow={percent(e)} aria-valuemin={0} aria-valuemax={100}>\n <div className=\"h-full bg-primary transition-[width]\" style={{ width: `${percent(e)}%` }} />\n </div>\n )}\n {e.error && <ErrorLine>{m.error(e.error)}</ErrorLine>}\n <div className=\"flex flex-wrap gap-2\">\n {(ACTIVE.includes(e.status) || e.status === \"queued\") && (\n <Button size=\"xs\" variant=\"ghost\" onClick={() => pause(e.id)}>\n {t(\"uploadQueue.pause\")}\n </Button>\n )}\n {(e.status === \"paused\" || e.status === \"failed\") && (\n <Button size=\"xs\" variant=\"outline\" onClick={() => resume(e.id)}>\n {t(e.status === \"failed\" ? \"common.retry\" : \"uploadQueue.resume\")}\n </Button>\n )}\n {e.status !== \"done\" && (\n <Button size=\"xs\" variant=\"ghost\" onClick={() => remove(e)}>\n {t(\"common.remove\")}\n </Button>\n )}\n </div>\n </li>\n ))}\n </ul>\n </>\n )}\n </>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { FlowClientOptions, StaffAccess } from '../../react/admin.js';
2
+ import { AdminFlowProps } from './shell.js';
3
+ export interface UserCommentStandingProps extends AdminFlowProps {
4
+ /** The user's id. */
5
+ user: string;
6
+ /** Their name in headings and dialogs; else their username once known. */
7
+ name?: string;
8
+ /** A link to a commented item. */
9
+ itemHref?: (item: {
10
+ kind: string;
11
+ id: string;
12
+ }) => string | undefined;
13
+ /** Comments per page. Default 10. */
14
+ pageSize?: number;
15
+ }
16
+ type StandingArea = "bans" | "comments";
17
+ /** Whether the caller may manage site-wide comment bans and moderate comments: what UserCommentStanding shows. */
18
+ export declare function useUserCommentStandingAccess(o?: FlowClientOptions): StaffAccess<StandingArea>;
19
+ /**
20
+ * A user page's comment panel: the person's site-wide comment ban (ban,
21
+ * replace, lift) and their recent comments (delete, restore), each as the
22
+ * caller's permissions allow.
23
+ */
24
+ export declare function UserCommentStanding({ client: own, baseUrl, auth, guard, appearance, className, language, messages, ...p }: UserCommentStandingProps): import('react').JSX.Element;
25
+ export {};