@anthusai/papyrus 2.0.0-next.9 → 2.0.0-next.90
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.
- package/amplify/auth/resource.js +16 -1
- package/amplify/auth/resource.ts +19 -1
- package/amplify/data/function-handler.js +20 -0
- package/amplify/data/function-handler.ts +40 -0
- package/amplify/data/resource.js +151 -61
- package/amplify/data/resource.ts +157 -61
- package/amplify/data/schema.js +2096 -1980
- package/amplify/data/schema.ts +198 -69
- package/amplify/functions/assignment-action/data-access.js +2 -0
- package/amplify/functions/assignment-action/data-access.ts +2 -0
- package/amplify/functions/assignment-action/handler.ts +1 -1
- package/amplify/functions/automation-view/handler.py +17 -0
- package/amplify/functions/automation-view/resource.js +24 -0
- package/amplify/functions/automation-view/resource.ts +34 -0
- package/amplify/functions/automation-view/schema.js +26 -0
- package/amplify/functions/automation-view/schema.ts +28 -0
- package/amplify/functions/automation-view/wire.js +56 -0
- package/amplify/functions/automation-view/wire.ts +76 -0
- package/amplify/functions/content-actions/handler.py +61 -2
- package/amplify/functions/content-actions/requirements.txt +1 -0
- package/amplify/functions/content-actions/resource.js +1 -1
- package/amplify/functions/content-actions/resource.ts +1 -1
- package/amplify/{plugins/editorial-checks/function → functions/editorial-checks}/handler.py +3 -3
- package/amplify/functions/editorial-checks/requirements.txt +1 -0
- package/amplify/{plugins/editorial-checks/function → functions/editorial-checks}/resource.js +7 -7
- package/amplify/{plugins/editorial-checks/function → functions/editorial-checks}/resource.ts +7 -7
- package/amplify/functions/editorial-checks/schema.js +122 -0
- package/amplify/{plugins → functions}/editorial-checks/schema.ts +40 -12
- package/amplify/functions/editorial-checks/wire.js +53 -0
- package/amplify/functions/editorial-checks/wire.ts +61 -0
- package/amplify/functions/monitoring-view/handler.py +11 -0
- package/amplify/functions/monitoring-view/resource.js +24 -0
- package/amplify/functions/monitoring-view/resource.ts +34 -0
- package/amplify/functions/monitoring-view/schema.js +17 -0
- package/amplify/functions/monitoring-view/schema.ts +19 -0
- package/amplify/functions/monitoring-view/wire.js +37 -0
- package/amplify/functions/monitoring-view/wire.ts +47 -0
- package/amplify/functions/public-forms/core.js +247 -0
- package/amplify/functions/public-forms/core.ts +310 -0
- package/amplify/functions/public-forms/handler.ts +41 -0
- package/amplify/functions/public-forms/origins.js +35 -0
- package/amplify/functions/public-forms/origins.ts +43 -0
- package/amplify/functions/public-forms/resource.js +9 -0
- package/amplify/functions/public-forms/resource.ts +10 -0
- package/amplify/functions/public-forms/wire.js +25 -0
- package/amplify/functions/public-forms/wire.ts +32 -0
- package/amplify/functions/shared/editorial-context.ts +63 -4
- package/amplify/functions/shared/python-bundle.js +20 -14
- package/amplify/functions/shared/python-bundle.ts +25 -18
- package/amplify/plugins/newsletter/config.js +245 -0
- package/amplify/plugins/newsletter/config.ts +305 -0
- package/amplify/plugins/newsletter/function/handler.py +6 -0
- package/amplify/plugins/newsletter/function/requirements.txt +5 -0
- package/amplify/plugins/newsletter/ops/handler.py +12 -0
- package/amplify/plugins/newsletter/ops/resource.js +27 -0
- package/amplify/plugins/newsletter/ops/resource.ts +37 -0
- package/amplify/plugins/newsletter/papyrus.plugin.js +263 -0
- package/amplify/plugins/newsletter/papyrus.plugin.ts +311 -0
- package/amplify/plugins/newsletter/schema.js +57 -0
- package/amplify/plugins/newsletter/schema.ts +62 -0
- package/amplify/plugins/newsletter/secure-string-parameter.js +107 -0
- package/amplify/plugins/newsletter/secure-string-parameter.ts +120 -0
- package/amplify/plugins/newsletter/sending.js +140 -0
- package/amplify/plugins/newsletter/sending.ts +186 -0
- package/amplify/plugins/reader-steering/config.js +182 -0
- package/amplify/plugins/reader-steering/config.ts +290 -0
- package/amplify/plugins/reader-steering/function/ai_moderation.py +246 -0
- package/amplify/plugins/reader-steering/function/handler.py +1567 -0
- package/amplify/plugins/reader-steering/function/moderation-prompt.md +27 -0
- package/amplify/plugins/reader-steering/function/moderation.py +316 -0
- package/amplify/plugins/reader-steering/function/proposals.py +458 -0
- package/amplify/plugins/reader-steering/function/resource.js +27 -0
- package/amplify/plugins/reader-steering/function/resource.ts +35 -0
- package/amplify/plugins/reader-steering/papyrus.plugin.js +186 -0
- package/amplify/plugins/reader-steering/papyrus.plugin.ts +212 -0
- package/amplify/plugins/reader-steering/schema.js +229 -0
- package/amplify/plugins/reader-steering/schema.ts +231 -0
- package/amplify/plugins/registry.js +4 -2
- package/amplify/plugins/registry.ts +4 -2
- package/amplify/plugins/signup/schema.js +2 -1
- package/amplify/plugins/signup/schema.ts +2 -1
- package/amplify/plugins/types.ts +5 -0
- package/amplify/plugins/wire.js +1 -0
- package/amplify/plugins/wire.ts +1 -0
- package/amplify/publication/projection-lease.js +30 -0
- package/amplify/publication/projection-lease.ts +39 -0
- package/amplify/publication/redirect-and-index.js +105 -0
- package/amplify/publication/redirect-rules.js +73 -0
- package/amplify/publication/redirect-rules.ts +93 -0
- package/amplify/publication/s3-projection.js +7 -1
- package/amplify/publication/s3-projection.ts +9 -1
- package/amplify/site-backend-config.ts +18 -1
- package/amplify/site-backend-names.js +4 -2
- package/amplify/site-backend-names.ts +4 -2
- package/amplify/site-backend.js +45 -3
- package/amplify/site-backend.ts +51 -3
- package/app/api/auth/prospectus/sign-in/route.ts +4 -0
- package/app/api/newsletter/confirm/route.ts +13 -0
- package/app/api/newsletter/preferences/route.ts +13 -0
- package/app/api/newsletter/state/route.ts +9 -0
- package/app/api/newsletter/subscribe/route.ts +9 -0
- package/app/api/newsletter/unsubscribe/route.ts +13 -0
- package/app/api/newsroom/curation/context/route.ts +9 -0
- package/app/api/newsroom/curation/priming/route.ts +9 -0
- package/app/api/newsroom/curation/publication/route.ts +9 -0
- package/app/api/reader/comment/delete/route.ts +9 -0
- package/app/api/reader/comment/edit/route.ts +9 -0
- package/app/api/reader/comment/route.ts +9 -0
- package/app/api/reader/flag/route.ts +9 -0
- package/app/api/reader/handle/route.ts +9 -0
- package/app/api/reader/me/route.ts +9 -0
- package/app/api/reader/rating/route.ts +9 -0
- package/app/api/reader/report/route.ts +9 -0
- package/app/api/reader/retired/route.ts +9 -0
- package/app/api/reader/submit/route.ts +9 -0
- package/app/api/reader/vote/route.ts +9 -0
- package/bin/papyrus-infra.mjs +20 -1
- package/components/automation-panel.tsx +49 -0
- package/components/automation-run-now.tsx +97 -0
- package/components/automation-view.tsx +195 -0
- package/components/editorial-checks-admin-panel.tsx +38 -13
- package/components/moderation-panel.tsx +248 -0
- package/components/monitoring-overview-view.tsx +241 -0
- package/components/monitoring-panel.tsx +40 -0
- package/components/news-desk-client-provider.tsx +18 -18
- package/components/news-desk-taxonomy-client.ts +28 -8
- package/components/newsletter-panel.tsx +474 -0
- package/components/newsletter-sections.tsx +163 -0
- package/components/newsroom-access-gate.tsx +16 -2
- package/components/newsroom-article-editor.tsx +11 -11
- package/components/newsroom-articles-view.tsx +6 -6
- package/components/newsroom-assignment-detail.tsx +6 -6
- package/components/newsroom-board-view.tsx +8 -3
- package/components/newsroom-curation-bootstrap.tsx +45 -0
- package/components/newsroom-ops-overview.tsx +26 -96
- package/components/newsroom-ops-shell.tsx +2 -2
- package/components/newsroom-organizer.css +33 -0
- package/components/newsroom-overview-skeleton.tsx +25 -0
- package/components/newsroom-references-view.tsx +192 -49
- package/components/notification-center.tsx +277 -0
- package/components/publication-cyclotron-panel.tsx +15 -10
- package/components/reader-auth-state.ts +1 -1
- package/components/reference-add-entry.tsx +75 -0
- package/components/reference-curation-controls.tsx +31 -22
- package/components/reference-cyclotron-priming.tsx +58 -19
- package/components/reference-cyclotron-suggestion.tsx +10 -6
- package/components/reference-priming.tsx +14 -10
- package/components/reference-relevance-review.tsx +3 -3
- package/components/reference-section-suggestion.tsx +1 -1
- package/components/topic-steering-workspace.tsx +237 -158
- package/components/use-editorial-checks.ts +12 -10
- package/infra/amplify-app-shell.js +94 -16
- package/infra/amplify-app-shell.ts +106 -18
- package/infra/cloud-email-config.js +32 -0
- package/infra/cloud-email-config.ts +39 -0
- package/infra/cloud-email.js +57 -0
- package/infra/cloud-email.test.js +69 -0
- package/infra/cloud-email.test.ts +66 -0
- package/infra/cloud-email.ts +60 -0
- package/infra/index.js +1 -0
- package/infra/secure-string-parameter-handler.js +41 -0
- package/infra/secure-string-parameter-handler.ts +41 -0
- package/infra/secure-string-parameter.js +79 -0
- package/infra/secure-string-parameter.ts +91 -0
- package/infra/site-config.js +88 -6
- package/infra/site-config.ts +134 -6
- package/lib/automation-client.ts +54 -0
- package/lib/automation-fixture.ts +93 -0
- package/lib/automation-overview.ts +252 -0
- package/lib/category-repository.ts +14 -12
- package/lib/console-web-context.ts +1 -1
- package/lib/curation-routes.ts +345 -0
- package/lib/cyclotron-suggestions.ts +4 -4
- package/lib/editorial-checks-backend.ts +1 -1
- package/lib/editorial-checks-client.ts +19 -1
- package/lib/editorial-checks-demo.ts +2 -2
- package/lib/editorial-checks-settings.ts +3 -0
- package/lib/editorial-checks.ts +8 -11
- package/lib/editorial-preview.ts +5 -5
- package/lib/monitoring-client.ts +29 -0
- package/lib/monitoring-overview-fixture.ts +51 -0
- package/lib/monitoring-overview.ts +145 -0
- package/lib/news-desk-session.ts +12 -21
- package/lib/newsletter-api.ts +418 -0
- package/lib/newsletter-client.ts +46 -0
- package/lib/newsletter-fixture.ts +184 -0
- package/lib/newsletter-model.ts +202 -0
- package/lib/newsroom-demo-dashboard.ts +1 -1
- package/lib/newsroom-nav.ts +1 -1
- package/lib/newsroom-organizer-nav.ts +2 -1
- package/lib/prospectus-session.ts +15 -14
- package/lib/prospectus-sign-in-routes.ts +105 -20
- package/lib/prospectus-site-identity.ts +46 -6
- package/lib/reader-api.ts +145 -0
- package/lib/reader-moderation.ts +220 -0
- package/lib/reader-retirement-route.ts +89 -0
- package/lib/reader-subject.md +29 -0
- package/lib/reader-subject.ts +53 -0
- package/lib/reference-review-details.ts +71 -0
- package/lib/reference-review-request.ts +14 -0
- package/lib/relevance-decisions.ts +42 -10
- package/lib/relevance-status.ts +2 -2
- package/lib/review-client.ts +117 -0
- package/lib/review-fixture.ts +45 -0
- package/lib/review-requests.ts +244 -0
- package/lib/semantic-graph.ts +2 -0
- package/lib/site-brand-tenant.ts +11 -6
- package/lib/site-brand.ts +6 -3
- package/lib/site-origin.ts +67 -0
- package/lib/use-reference-review-data.ts +44 -0
- package/middleware.ts +14 -3
- package/package.json +56 -3
- package/routes.manifest.json +215 -2
- package/amplify/plugins/editorial-checks/function/requirements.txt +0 -1
- package/amplify/plugins/editorial-checks/papyrus.plugin.js +0 -71
- package/amplify/plugins/editorial-checks/papyrus.plugin.ts +0 -87
- package/amplify/plugins/editorial-checks/schema.js +0 -94
|
@@ -23,6 +23,8 @@ body:has(.newsroom-organizer)>[data-staging-banner]{flex-shrink:0}
|
|
|
23
23
|
.organizer-sidebar-head{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}.organizer-sidebar-head .organizer-brand{flex:1;min-width:0}
|
|
24
24
|
.organizer-header-actions{display:flex;align-items:center;gap:8px;min-width:0;max-width:45%;overflow-x:auto}
|
|
25
25
|
.organizer-main{min-width:0;min-height:0;overflow:auto;overscroll-behavior:contain;flex:1;padding:16px 0}
|
|
26
|
+
.newsroom-overview-feed-frame{height:auto}
|
|
27
|
+
@media(min-width:640px){.newsroom-overview-feed-frame{height:38rem;overflow-y:auto}}
|
|
26
28
|
.organizer-main>[data-category-steering]{min-height:0}.organizer-demo-notice{font-size:11px;color:var(--org-muted);margin-bottom:12px}
|
|
27
29
|
.organizer-account{display:flex;align-items:center;gap:10px;min-height:44px;flex-shrink:0;border:1px solid var(--org-line);padding:8px;text-align:left;border-radius:3px}
|
|
28
30
|
.organizer-account span{min-width:0}.organizer-account strong{display:block;font:600 11px var(--kb-theme-ui-font);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.organizer-account small{display:block;font-size:9px;color:var(--org-muted);margin-top:2px}
|
|
@@ -313,3 +315,34 @@ body:has(.newsroom-organizer)>[data-staging-banner]{flex-shrink:0}
|
|
|
313
315
|
.news-desk-columns--administration .news-desk-delegation-decision button:focus-visible{outline:2px solid var(--org-ink);outline-offset:2px}
|
|
314
316
|
@container (max-width:640px){.news-desk-columns--administration .news-desk-delegation-pending-list li{grid-template-columns:minmax(0,1fr)}.news-desk-columns--administration .news-desk-delegation-code{font-size:28px}}
|
|
315
317
|
@container (max-width:640px){.news-desk-columns--administration .news-desk-delegation-form{grid-template-columns:minmax(0,1fr)}.news-desk-columns--administration .news-desk-delegation-list li{grid-template-columns:minmax(0,1fr)}}
|
|
318
|
+
.news-desk-columns--administration .news-desk-monitoring__scope{display:flex;flex-wrap:wrap;gap:8px}
|
|
319
|
+
.news-desk-columns--administration .news-desk-monitoring__scope button{min-height:36px;padding:4px 12px;border:1px solid var(--org-line);background:transparent;color:var(--administration-strong);font:600 12px/1.2 var(--kb-theme-ui-font);letter-spacing:.05em;text-transform:uppercase;cursor:pointer}
|
|
320
|
+
.news-desk-columns--administration .news-desk-monitoring__scope button[aria-pressed=true]{border-color:var(--org-ink);border-width:2px;text-decoration:underline;text-underline-offset:4px}
|
|
321
|
+
.news-desk-columns--administration .news-desk-monitoring__list,.news-desk-columns--administration .news-desk-monitoring__queue,.news-desk-columns--administration .news-desk-monitoring__relevance{list-style:none;margin:0;padding:0;display:grid}
|
|
322
|
+
.news-desk-columns--administration .news-desk-monitoring__list li{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr) minmax(0,2fr);gap:4px 16px;align-items:baseline;padding:10px 0;border-top:1px solid var(--org-line);min-width:0;overflow-wrap:anywhere}
|
|
323
|
+
.news-desk-columns--administration .news-desk-monitoring__list li>div{display:grid;gap:2px}
|
|
324
|
+
.news-desk-columns--administration .news-desk-monitoring__queue>li{display:grid;gap:6px;padding:12px 0;border-top:1px solid var(--org-line);min-width:0}
|
|
325
|
+
.news-desk-columns--administration .news-desk-monitoring__queue>li>div{display:grid;gap:2px}
|
|
326
|
+
.news-desk-columns--administration .news-desk-monitoring__queue>li>div>span,.news-desk-columns--administration .news-desk-monitoring__routing{margin:0;font:400 12px/1.4 var(--kb-theme-ui-font);color:var(--administration-quiet)}
|
|
327
|
+
.news-desk-columns--administration .news-desk-monitoring__queue li[data-routing=error]{padding-left:12px;border-left:3px solid var(--org-ink)}
|
|
328
|
+
.news-desk-columns--administration .news-desk-monitoring__relevance{gap:4px;padding-left:12px;border-left:1px solid var(--org-line)}
|
|
329
|
+
.news-desk-columns--administration .news-desk-monitoring__relevance li{display:flex;flex-wrap:wrap;gap:4px 12px;font:400 13px/1.4 var(--kb-theme-ui-font)}
|
|
330
|
+
.news-desk-columns--administration .news-desk-monitoring__relevance li[data-delivery=failed] span:last-child{font-weight:700}
|
|
331
|
+
.news-desk-columns--administration .news-desk-monitoring__usage{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px 24px;margin:0}
|
|
332
|
+
.news-desk-columns--administration .news-desk-monitoring__usage dt{font:600 11px/1.4 var(--kb-theme-ui-font);letter-spacing:.07em;text-transform:uppercase;color:var(--administration-quiet)}
|
|
333
|
+
.news-desk-columns--administration .news-desk-monitoring__usage dd{margin:0;font:700 26px/1.1 var(--kb-theme-title-font);font-variant-numeric:tabular-nums}
|
|
334
|
+
@container (max-width:640px){.news-desk-columns--administration .news-desk-monitoring__list li{grid-template-columns:minmax(0,1fr)}}
|
|
335
|
+
|
|
336
|
+
/* Newsletter panel (components/newsletter-panel.tsx): reuses the administration card, row and button styles above. */
|
|
337
|
+
.news-desk-columns--administration .news-desk-newsletter__quiet{font:400 12px/1.4 var(--kb-theme-ui-font);color:var(--administration-quiet)}
|
|
338
|
+
.news-desk-columns--administration .news-desk-monitoring__usage>div{display:grid;gap:4px;align-content:start}
|
|
339
|
+
.news-desk-columns--administration .news-desk-newsletter__links{display:flex;flex-wrap:wrap;gap:4px 8px}
|
|
340
|
+
.news-desk-columns--administration .news-desk-newsletter__table{width:100%;border-collapse:collapse;font:400 13px/1.4 var(--kb-theme-ui-font)}
|
|
341
|
+
.news-desk-columns--administration .news-desk-newsletter__table td:first-child{word-break:keep-all;overflow-wrap:break-word}
|
|
342
|
+
.news-desk-columns--administration .news-desk-newsletter__table th{text-align:left;padding:6px 8px;border-bottom:2px solid var(--administration-strong);font:600 11px/1.4 var(--kb-theme-ui-font);letter-spacing:.07em;text-transform:uppercase;color:var(--administration-quiet)}
|
|
343
|
+
.news-desk-columns--administration .news-desk-newsletter__table td{padding:8px;border-bottom:1px solid var(--org-line);vertical-align:top}
|
|
344
|
+
.news-desk-columns--administration .news-desk-newsletter__drawer{grid-column:1/-1;display:grid;gap:12px;padding:12px 0 0;border-top:1px dashed var(--org-line);min-width:0}
|
|
345
|
+
.news-desk-columns--administration .news-desk-newsletter__frame{width:100%;height:480px;border:1px solid var(--org-line);background:#fff}
|
|
346
|
+
.news-desk-columns--administration .news-desk-newsletter__text{margin:0;padding:12px;max-height:280px;overflow:auto;border:1px solid var(--org-line);font:400 12px/1.5 ui-monospace,monospace;white-space:pre-wrap;overflow-wrap:anywhere}
|
|
347
|
+
.news-desk-columns--administration .news-desk-newsletter__filters{display:flex;flex-wrap:wrap;gap:12px 24px}
|
|
348
|
+
.news-desk-columns--administration .news-desk-newsletter__filters .news-desk-doctrine-card__field{min-width:180px}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
|
|
5
|
+
/** Placeholder geometry for the overview while private records or access are unresolved. */
|
|
6
|
+
export function NewsroomOverviewSkeleton() {
|
|
7
|
+
return (
|
|
8
|
+
<div aria-label="Loading newsroom overview" className="space-y-8 font-sans" data-newsroom-overview-skeleton role="status">
|
|
9
|
+
<section className="newsroom-overview-feed-frame space-y-4 overflow-hidden rounded-xl border bg-card p-4" aria-label="Notification Center">
|
|
10
|
+
<div className="h-6 w-48 rounded bg-muted" />
|
|
11
|
+
<div className="h-4 w-3/4 max-w-xl rounded bg-muted" />
|
|
12
|
+
<div className="h-4 w-2/3 max-w-lg rounded bg-muted" />
|
|
13
|
+
<div className="grid gap-3 sm:grid-cols-2">
|
|
14
|
+
{Array.from({ length: 4 }, (_, index) => <div className="h-28 rounded-xl border bg-card p-4" key={index}>
|
|
15
|
+
<div className="h-4 w-2/3 rounded bg-muted" /><div className="mt-4 h-3 w-1/2 rounded bg-muted" />
|
|
16
|
+
</div>)}
|
|
17
|
+
</div>
|
|
18
|
+
</section>
|
|
19
|
+
<section aria-label="Needs attention" className="space-y-3">
|
|
20
|
+
<div className="h-4 w-32 rounded bg-muted" />
|
|
21
|
+
<div className="h-16 rounded-xl border bg-card p-4"><div className="h-4 w-1/2 rounded bg-muted" /><div className="mt-2 h-3 w-1/3 rounded bg-muted" /></div>
|
|
22
|
+
</section>
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import type { PrimingPanelProps } from "cyclotron/components/priming-panel";
|
|
4
|
-
import {
|
|
5
|
-
import { ReferenceCurationControls } from "./reference-curation-controls";
|
|
4
|
+
import { ReferenceAddEntry } from "./reference-add-entry";
|
|
5
|
+
import { ReferenceCurationControls, useReferenceImport } from "./reference-curation-controls";
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
8
|
ArchiveIcon,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
ThumbsUpIcon,
|
|
14
14
|
} from "lucide-react";
|
|
15
15
|
import { usePathname } from "next/navigation";
|
|
16
|
-
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
16
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
17
17
|
import { Badge } from "./ui/badge";
|
|
18
18
|
import { Button } from "./ui/button";
|
|
19
19
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./ui/card";
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
import { Tabs, TabsList, TabsTrigger } from "./ui/tabs";
|
|
29
29
|
import type { ReferenceAttachmentRecord, ReferenceRecord } from "../lib/category-repository";
|
|
30
30
|
import {
|
|
31
|
+
buildReferencesIndexQuery,
|
|
31
32
|
parseReferenceLineageIdFromNewsroomPathname,
|
|
32
33
|
syncBrowserNewsroomIndexUrl,
|
|
33
34
|
} from "../lib/newsroom-index-filters";
|
|
@@ -45,7 +46,7 @@ import {
|
|
|
45
46
|
type ReferenceCurationAction,
|
|
46
47
|
type ReferenceStatusFilter,
|
|
47
48
|
} from "../lib/newsroom-references";
|
|
48
|
-
import { normalizeReferenceCurationStatus } from "../lib/reference-policy";
|
|
49
|
+
import { normalizeReferenceCurationStatus, referenceReasonCode, REFERENCE_REJECTION_REASON_CODES, type ReferenceRejectionReasonCode } from "../lib/reference-policy";
|
|
49
50
|
import { newsroomListRowClassName } from "../lib/newsroom-list-selection";
|
|
50
51
|
import { ReferenceSourcePreview } from "./reference-source-preview";
|
|
51
52
|
import { ReferenceRelevanceReview } from "./reference-relevance-review";
|
|
@@ -61,9 +62,16 @@ import { SectionPicker, SectionSuggestionBlock, type SectionChoice } from "./ref
|
|
|
61
62
|
import type { SectionSuggestion, SiteSectionAgreement } from "../lib/site-section-suggestions";
|
|
62
63
|
|
|
63
64
|
/** What an editor adds to an accept: the Section the reference belongs in, which becomes a training label. */
|
|
64
|
-
export type ReferenceReviewOptions = {
|
|
65
|
+
export type ReferenceReviewOptions = {
|
|
66
|
+
sectionId?: string | null;
|
|
67
|
+
note?: string;
|
|
68
|
+
reasonCode?: ReferenceRejectionReasonCode | null;
|
|
69
|
+
decisionRelationId?: string;
|
|
70
|
+
shareable?: boolean;
|
|
71
|
+
};
|
|
72
|
+
type PredictionState = "loading" | "ready" | "error";
|
|
65
73
|
import type { DelegatedCuration, ShadowAgreement } from "../lib/cyclotron-suggestions";
|
|
66
|
-
import {
|
|
74
|
+
import type { PrimingFormInput } from "./reference-cyclotron-priming";
|
|
67
75
|
import { ReferenceCyclotronStatus, type ReviewRateChoice } from "./reference-cyclotron-status";
|
|
68
76
|
import type { PrimingRequestView } from "../lib/relevance-status";
|
|
69
77
|
import type { CyclotronStatus } from "cyclotron/cyclotron-status";
|
|
@@ -102,9 +110,14 @@ type NewsroomReferencesViewProps = {
|
|
|
102
110
|
sectionSuggestions?: Map<string, SectionSuggestion>;
|
|
103
111
|
/** How often the Section suggestions matched later editor decisions. */
|
|
104
112
|
sectionAgreement?: SiteSectionAgreement | null;
|
|
105
|
-
|
|
113
|
+
reviewReasons?: Map<string, ReferenceRejectionReasonCode>;
|
|
114
|
+
reviewSectionIds?: Map<string, string>;
|
|
115
|
+
predictionState?: PredictionState;
|
|
116
|
+
predictionError?: string | null;
|
|
117
|
+
onRetryPredictions?: () => void;
|
|
118
|
+
onRelevanceReview?: (reference: ReferenceRecord, curation: RelevanceCuration) => Promise<void> | void;
|
|
106
119
|
initialReferenceLineageId?: string | null;
|
|
107
|
-
onReview: (reference: ReferenceRecord, action: ReferenceCurationAction, options?: ReferenceReviewOptions) => void;
|
|
120
|
+
onReview: (reference: ReferenceRecord, action: ReferenceCurationAction, options?: ReferenceReviewOptions) => Promise<void> | void;
|
|
108
121
|
referenceAttachments?: ReferenceAttachmentRecord[];
|
|
109
122
|
references: ReferenceRecord[];
|
|
110
123
|
};
|
|
@@ -251,6 +264,9 @@ function ReferenceDetailPanel({
|
|
|
251
264
|
disabled,
|
|
252
265
|
onRelevanceReview,
|
|
253
266
|
onReview,
|
|
267
|
+
predictionState = "ready",
|
|
268
|
+
reviewReason,
|
|
269
|
+
reviewSectionId,
|
|
254
270
|
previewAttachments,
|
|
255
271
|
reference,
|
|
256
272
|
onClose,
|
|
@@ -263,8 +279,11 @@ function ReferenceDetailPanel({
|
|
|
263
279
|
decision?: RelevanceDecisionView;
|
|
264
280
|
demo?: boolean;
|
|
265
281
|
disabled?: boolean;
|
|
266
|
-
onRelevanceReview?: (curation: RelevanceCuration) => void;
|
|
267
|
-
onReview: (action: ReferenceCurationAction, options?: ReferenceReviewOptions) => void;
|
|
282
|
+
onRelevanceReview?: (curation: RelevanceCuration) => Promise<void> | void;
|
|
283
|
+
onReview: (action: ReferenceCurationAction, options?: ReferenceReviewOptions) => Promise<void> | void;
|
|
284
|
+
predictionState?: PredictionState;
|
|
285
|
+
reviewReason?: ReferenceRejectionReasonCode;
|
|
286
|
+
reviewSectionId?: string;
|
|
268
287
|
sectionAgreement?: SiteSectionAgreement | null;
|
|
269
288
|
sectionSuggestion?: SectionSuggestion;
|
|
270
289
|
sections?: SectionChoice[];
|
|
@@ -273,13 +292,77 @@ function ReferenceDetailPanel({
|
|
|
273
292
|
onClose?: () => void;
|
|
274
293
|
}) {
|
|
275
294
|
const lineageId = referenceLineageId(reference);
|
|
276
|
-
const
|
|
277
|
-
|
|
295
|
+
const sourceNote = normalizeReferenceCurationStatus(reference.curationStatus) === "pending" ? "" : reference.curationStatusReason ?? "";
|
|
296
|
+
const sourceReason = reviewReason ?? referenceReasonCode(reference) ?? "";
|
|
297
|
+
const [note, setNote] = useState(sourceNote);
|
|
298
|
+
const [reasonCode, setReasonCode] = useState<ReferenceRejectionReasonCode | "">(sourceReason);
|
|
299
|
+
const [savedNote, setSavedNote] = useState(sourceNote);
|
|
300
|
+
const [savedReason, setSavedReason] = useState<ReferenceRejectionReasonCode | "">(sourceReason);
|
|
301
|
+
const [busy, setBusy] = useState(false);
|
|
302
|
+
const [reviewError, setReviewError] = useState<string | null>(null);
|
|
303
|
+
const [saved, setSaved] = useState(false);
|
|
304
|
+
const saving = useRef(false);
|
|
305
|
+
const noteEdited = useRef(false);
|
|
306
|
+
const reasonEdited = useRef(false);
|
|
307
|
+
useEffect(() => {
|
|
308
|
+
setSavedNote(sourceNote);
|
|
309
|
+
if (!noteEdited.current) setNote(sourceNote);
|
|
310
|
+
}, [sourceNote]);
|
|
311
|
+
useEffect(() => {
|
|
312
|
+
setSavedReason(sourceReason);
|
|
313
|
+
if (!reasonEdited.current) setReasonCode(sourceReason);
|
|
314
|
+
}, [sourceReason]);
|
|
315
|
+
const [chosenSectionId, setChosenSectionId] = useState<string | null>(reviewSectionId ?? null);
|
|
316
|
+
const [savedSectionId, setSavedSectionId] = useState<string | null>(reviewSectionId ?? null);
|
|
317
|
+
const sectionEdited = useRef(false);
|
|
318
|
+
useEffect(() => {
|
|
319
|
+
setSavedSectionId(reviewSectionId ?? null);
|
|
320
|
+
if (!sectionEdited.current) setChosenSectionId(reviewSectionId ?? null);
|
|
321
|
+
}, [reviewSectionId]);
|
|
278
322
|
const status = normalizeReferenceCurationStatus(reference.curationStatus);
|
|
279
323
|
const url = referenceUrl(reference);
|
|
280
|
-
const
|
|
281
|
-
const
|
|
282
|
-
const
|
|
324
|
+
const locked = disabled || busy;
|
|
325
|
+
const acceptDisabled = locked || status === "accepted";
|
|
326
|
+
const rejectDisabled = locked || status === "rejected";
|
|
327
|
+
const archiveDisabled = locked || status === "archived";
|
|
328
|
+
|
|
329
|
+
async function save(action: ReferenceCurationAction, review?: RelevanceCuration) {
|
|
330
|
+
if (disabled || saving.current) return;
|
|
331
|
+
const rejectionReason = review?.reasonCode ?? reasonCode;
|
|
332
|
+
if (action === "reject" && !rejectionReason) {
|
|
333
|
+
setReviewError("Choose a rejection reason before saving. An explanation is optional.");
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
saving.current = true;
|
|
337
|
+
setBusy(true);
|
|
338
|
+
setSaved(false);
|
|
339
|
+
setReviewError(null);
|
|
340
|
+
try {
|
|
341
|
+
if (review && onRelevanceReview) await onRelevanceReview({ ...review, ...(action === "accept" && chosenSectionId ? { sectionId: chosenSectionId } : {}) });
|
|
342
|
+
else await onReview(action, {
|
|
343
|
+
note: note.trim(),
|
|
344
|
+
reasonCode: action === "reject" ? reasonCode || null : null,
|
|
345
|
+
...(action === "accept" && chosenSectionId ? { sectionId: chosenSectionId } : {}),
|
|
346
|
+
...(decision ? { decisionRelationId: decision.decisionRelationId, shareable: false } : {}),
|
|
347
|
+
});
|
|
348
|
+
if (review) {
|
|
349
|
+
setNote(review.note ?? "");
|
|
350
|
+
setReasonCode((review.reasonCode as ReferenceRejectionReasonCode) ?? "");
|
|
351
|
+
}
|
|
352
|
+
setSavedNote(review ? review.note ?? "" : note.trim());
|
|
353
|
+
setSavedReason(action === "reject" ? rejectionReason as ReferenceRejectionReasonCode : "");
|
|
354
|
+
setSavedSectionId(action === "accept" ? chosenSectionId : null);
|
|
355
|
+
noteEdited.current = false;
|
|
356
|
+
reasonEdited.current = false;
|
|
357
|
+
sectionEdited.current = false;
|
|
358
|
+
setSaved(true);
|
|
359
|
+
} catch (error) {
|
|
360
|
+
setReviewError(error instanceof Error ? error.message : "Review could not be saved. Try again.");
|
|
361
|
+
} finally {
|
|
362
|
+
saving.current = false;
|
|
363
|
+
setBusy(false);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
283
366
|
|
|
284
367
|
return (
|
|
285
368
|
<div
|
|
@@ -304,8 +387,8 @@ function ReferenceDetailPanel({
|
|
|
304
387
|
<div className="space-y-3" data-reference-relevance-decision={lineageId}>
|
|
305
388
|
<ReferenceSuggestionBlock
|
|
306
389
|
decision={decision}
|
|
307
|
-
disabled={
|
|
308
|
-
onCurate={onRelevanceReview}
|
|
390
|
+
disabled={locked}
|
|
391
|
+
onCurate={onRelevanceReview ? (review) => { void save(review.action, { ...review, note: note.trim() || null, reasonCode: review.action === "reject" ? reasonCode || null : null }); } : undefined}
|
|
309
392
|
referenceLineageId={lineageId}
|
|
310
393
|
settled={status !== "pending"}
|
|
311
394
|
statusLabel={referenceStatusLabel(status)}
|
|
@@ -317,31 +400,54 @@ function ReferenceDetailPanel({
|
|
|
317
400
|
<div className="mt-2">
|
|
318
401
|
<ReferenceRelevanceReview
|
|
319
402
|
decision={decision}
|
|
320
|
-
disabled={
|
|
321
|
-
onCurate={
|
|
403
|
+
disabled={locked}
|
|
404
|
+
onCurate={(review) => save(review.action, review)}
|
|
322
405
|
referenceLineageId={lineageId}
|
|
323
406
|
/>
|
|
324
407
|
</div>
|
|
325
408
|
</details>
|
|
326
409
|
) : null}
|
|
327
410
|
</div>
|
|
411
|
+
) : predictionState === "ready" ? (
|
|
412
|
+
<section aria-label="Publication prediction" className="space-y-1 rounded-md border p-3">
|
|
413
|
+
<h3 className="text-sm font-semibold">No prediction recorded</h3>
|
|
414
|
+
<p className="text-sm text-muted-foreground">No publication relevance prediction was returned for this reference. You can still review it. Pending is its editorial status, not a prediction status.</p>
|
|
415
|
+
</section>
|
|
328
416
|
) : null}
|
|
329
|
-
{status === "pending" &&
|
|
330
|
-
<
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
417
|
+
{sectionSuggestion || ((status === "pending" || status === "accepted") && sections.length) ? (
|
|
418
|
+
<details className="rounded-md border p-3 text-sm">
|
|
419
|
+
<summary className="cursor-pointer font-semibold">Section placement (optional)</summary>
|
|
420
|
+
<div className="mt-3 space-y-3">
|
|
421
|
+
{sectionSuggestion ? <SectionSuggestionBlock agreement={sectionAgreement} referenceLineageId={lineageId} sections={sections} suggestion={sectionSuggestion} /> : null}
|
|
422
|
+
{(status === "pending" || status === "accepted") && sections.length ? <SectionPicker
|
|
334
423
|
agreement={sectionAgreement}
|
|
335
424
|
chosenSectionId={chosenSectionId}
|
|
336
|
-
disabled={
|
|
337
|
-
onChoose={setChosenSectionId}
|
|
425
|
+
disabled={locked}
|
|
426
|
+
onChoose={(sectionId) => { setChosenSectionId(sectionId); sectionEdited.current = true; setSaved(false); }}
|
|
338
427
|
referenceLineageId={lineageId}
|
|
339
428
|
sections={sections}
|
|
340
429
|
suggestedSectionId={sectionSuggestion?.sectionId ?? null}
|
|
341
|
-
|
|
430
|
+
/> : null}
|
|
431
|
+
</div>
|
|
432
|
+
</details>
|
|
342
433
|
) : null}
|
|
343
434
|
{delegated ? <DelegatedCurationNote delegated={delegated} referenceLineageId={lineageId} /> : countsAsTrainingLabel ? <CountsAsTrainingLabelNote referenceLineageId={lineageId} /> : null}
|
|
344
435
|
|
|
436
|
+
<section aria-label="Editor feedback" className="space-y-3">
|
|
437
|
+
<h3 className="text-sm font-semibold">Editor feedback</h3>
|
|
438
|
+
{disabled ? <p className="text-sm text-muted-foreground">Editor access is required to change this reference.</p> : null}
|
|
439
|
+
<label className="block text-sm">
|
|
440
|
+
Review explanation (optional)
|
|
441
|
+
<textarea aria-label="Review explanation (optional)" className="mt-1 block min-h-20 w-full rounded-md border bg-background p-2" disabled={locked} value={note} onChange={(event) => { setNote(event.target.value); noteEdited.current = true; setSaved(false); }} />
|
|
442
|
+
</label>
|
|
443
|
+
<label className="block text-sm">
|
|
444
|
+
Rejection reason
|
|
445
|
+
<select aria-label="Rejection reason" className="mt-1 block w-full rounded-md border bg-background p-2" disabled={locked} value={reasonCode} onChange={(event) => { setReasonCode(event.target.value as ReferenceRejectionReasonCode | ""); reasonEdited.current = true; setSaved(false); }}>
|
|
446
|
+
<option value="">Choose a reason when rejecting</option>
|
|
447
|
+
{REFERENCE_REJECTION_REASON_CODES.map((code) => <option key={code} value={code}>{code.charAt(0).toUpperCase() + code.slice(1).replaceAll("_", " ")}</option>)}
|
|
448
|
+
</select>
|
|
449
|
+
</label>
|
|
450
|
+
<p className="text-xs text-muted-foreground">Only out of scope and policy exclusion are negative relevance labels. Other rejection reasons do not teach relevance.</p>
|
|
345
451
|
<div
|
|
346
452
|
className="flex flex-wrap items-center gap-2"
|
|
347
453
|
data-news-desk-reference-curation-cluster
|
|
@@ -352,7 +458,7 @@ function ReferenceDetailPanel({
|
|
|
352
458
|
aria-pressed={status === "accepted"}
|
|
353
459
|
data-news-desk-reference-accept
|
|
354
460
|
disabled={acceptDisabled}
|
|
355
|
-
onClick={() =>
|
|
461
|
+
onClick={() => { void save("accept"); }}
|
|
356
462
|
size="sm"
|
|
357
463
|
type="button"
|
|
358
464
|
variant={status === "accepted" ? "default" : "outline"}
|
|
@@ -365,7 +471,7 @@ function ReferenceDetailPanel({
|
|
|
365
471
|
aria-pressed={status === "rejected"}
|
|
366
472
|
data-news-desk-reference-reject
|
|
367
473
|
disabled={rejectDisabled}
|
|
368
|
-
onClick={() =>
|
|
474
|
+
onClick={() => { void save("reject"); }}
|
|
369
475
|
size="sm"
|
|
370
476
|
type="button"
|
|
371
477
|
variant={status === "rejected" ? "destructive" : "outline"}
|
|
@@ -376,7 +482,7 @@ function ReferenceDetailPanel({
|
|
|
376
482
|
<Button
|
|
377
483
|
aria-label="Archive reference"
|
|
378
484
|
disabled={archiveDisabled}
|
|
379
|
-
onClick={() =>
|
|
485
|
+
onClick={() => { void save("archive"); }}
|
|
380
486
|
size="sm"
|
|
381
487
|
type="button"
|
|
382
488
|
variant="outline"
|
|
@@ -384,7 +490,14 @@ function ReferenceDetailPanel({
|
|
|
384
490
|
<ArchiveIcon className="size-4" />
|
|
385
491
|
Archive
|
|
386
492
|
</Button>
|
|
493
|
+
{status === "accepted" || status === "rejected" ? (
|
|
494
|
+
<Button disabled={locked || predictionState !== "ready" || (note.trim() === savedNote.trim() && (status !== "rejected" || reasonCode === savedReason) && (status !== "accepted" || chosenSectionId === savedSectionId))} onClick={() => { void save(status === "accepted" ? "accept" : "reject"); }} size="sm" type="button" variant="outline">Save feedback</Button>
|
|
495
|
+
) : null}
|
|
387
496
|
</div>
|
|
497
|
+
{status !== "pending" && predictionState !== "ready" ? <p className="text-sm text-muted-foreground">Load the review details before revising saved feedback.</p> : null}
|
|
498
|
+
{busy ? <p role="status" className="text-sm">Saving review…</p> : saved ? <p role="status" className="text-sm">Review saved.</p> : null}
|
|
499
|
+
{reviewError ? <p role="alert" className="text-sm text-destructive">{reviewError}</p> : null}
|
|
500
|
+
</section>
|
|
388
501
|
|
|
389
502
|
<Separator />
|
|
390
503
|
|
|
@@ -398,7 +511,7 @@ function ReferenceDetailPanel({
|
|
|
398
511
|
<dt className="text-xs font-medium uppercase tracking-wide text-muted-foreground">Why</dt>
|
|
399
512
|
<dd className="mt-1 text-foreground">
|
|
400
513
|
{reference.curationStatusReason?.trim()
|
|
401
|
-
|| "
|
|
514
|
+
|| "No explanation recorded."}
|
|
402
515
|
</dd>
|
|
403
516
|
</div>
|
|
404
517
|
{url ? (
|
|
@@ -476,6 +589,11 @@ export function NewsroomReferencesView({
|
|
|
476
589
|
demo = false,
|
|
477
590
|
disabled = false,
|
|
478
591
|
onRelevanceReview,
|
|
592
|
+
predictionState = "ready",
|
|
593
|
+
predictionError,
|
|
594
|
+
reviewReasons,
|
|
595
|
+
reviewSectionIds,
|
|
596
|
+
onRetryPredictions,
|
|
479
597
|
sections = [],
|
|
480
598
|
sectionSuggestions,
|
|
481
599
|
sectionAgreement = null,
|
|
@@ -485,12 +603,14 @@ export function NewsroomReferencesView({
|
|
|
485
603
|
references,
|
|
486
604
|
}: NewsroomReferencesViewProps) {
|
|
487
605
|
const pathname = usePathname();
|
|
606
|
+
const sessionImport = useReferenceImport(disabled);
|
|
607
|
+
const [importedCount, setImportedCount] = useState(0);
|
|
488
608
|
const isMobileDetail = useMediaQuery("(max-width: 767px)");
|
|
489
609
|
const pathnameLineageId = useMemo(
|
|
490
610
|
() => parseReferenceLineageIdFromNewsroomPathname(pathname),
|
|
491
611
|
[pathname],
|
|
492
612
|
);
|
|
493
|
-
const routeLineageId =
|
|
613
|
+
const routeLineageId = pathname ? pathnameLineageId ?? "" : initialReferenceLineageId ?? "";
|
|
494
614
|
|
|
495
615
|
const canonicalReferences = useMemo(() => selectCanonicalReferenceRecords(references), [references]);
|
|
496
616
|
const statusCounts = useMemo(() => countReferencesByStatus(canonicalReferences), [canonicalReferences]);
|
|
@@ -529,17 +649,21 @@ export function NewsroomReferencesView({
|
|
|
529
649
|
|
|
530
650
|
const syncStatusUrl = useCallback((nextStatus: ReferenceListFilter) => {
|
|
531
651
|
if (demo) return;
|
|
532
|
-
|
|
652
|
+
const filters = {
|
|
533
653
|
status: nextStatus === "all" ? "" : nextStatus,
|
|
534
654
|
processing: "",
|
|
535
|
-
order: "published",
|
|
536
|
-
}
|
|
537
|
-
|
|
655
|
+
order: "published" as const,
|
|
656
|
+
};
|
|
657
|
+
if (selectedLineageId && typeof window !== "undefined") {
|
|
658
|
+
window.history.replaceState(null, "", `${buildReferenceDetailPath(selectedLineageId)}${buildReferencesIndexQuery(filters)}`);
|
|
659
|
+
} else {
|
|
660
|
+
syncBrowserNewsroomIndexUrl("references", filters, { replace: true });
|
|
661
|
+
}
|
|
662
|
+
}, [demo, selectedLineageId]);
|
|
538
663
|
|
|
539
664
|
useEffect(() => {
|
|
540
|
-
if (!routeLineageId) return;
|
|
541
665
|
setSelectedLineageId(routeLineageId);
|
|
542
|
-
if (isMobileDetail) setMobileDetailOpen(
|
|
666
|
+
if (isMobileDetail) setMobileDetailOpen(Boolean(routeLineageId));
|
|
543
667
|
}, [isMobileDetail, routeLineageId]);
|
|
544
668
|
|
|
545
669
|
useEffect(() => {
|
|
@@ -569,7 +693,7 @@ export function NewsroomReferencesView({
|
|
|
569
693
|
|
|
570
694
|
const runReview = (action: ReferenceCurationAction, options?: ReferenceReviewOptions) => {
|
|
571
695
|
if (!selectedReference) return;
|
|
572
|
-
onReview(selectedReference, action, options);
|
|
696
|
+
return onReview(selectedReference, action, options);
|
|
573
697
|
};
|
|
574
698
|
|
|
575
699
|
const emptyLabel = canonicalReferences.length
|
|
@@ -589,23 +713,34 @@ export function NewsroomReferencesView({
|
|
|
589
713
|
Review source intake before it becomes accepted evidence.
|
|
590
714
|
</p>
|
|
591
715
|
</div>
|
|
592
|
-
<
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
<
|
|
598
|
-
labels={cyclotronPriming.labels}
|
|
599
|
-
onRequestPriming={cyclotronPriming.onRequest}
|
|
600
|
-
requests={cyclotronPriming.requests}
|
|
601
|
-
/>
|
|
716
|
+
{predictionState === "loading" ? <p role="status">Loading predictions…</p> : null}
|
|
717
|
+
{predictionState === "error" ? (
|
|
718
|
+
<div role="alert" className="space-y-2 rounded-md border p-3">
|
|
719
|
+
<p>Predictions unavailable. {predictionError}</p>
|
|
720
|
+
<p className="text-sm">You can still review references. Existing suggestions may be out of date.</p>
|
|
721
|
+
{onRetryPredictions ? <Button onClick={onRetryPredictions} size="sm" type="button" variant="outline">Retry predictions</Button> : null}
|
|
602
722
|
</div>
|
|
603
723
|
) : null}
|
|
724
|
+
<details className="shrink-0 overflow-y-auto rounded-md border p-3 text-sm" style={{ maxHeight: "35dvh" }}>
|
|
725
|
+
<summary className="cursor-pointer font-semibold">Add a reference and prediction activity</summary>
|
|
726
|
+
<div className="mt-3 space-y-4">
|
|
727
|
+
<ReferenceLiveAgreement agreement={shadowAgreement} />
|
|
728
|
+
<ReferenceAddEntry
|
|
729
|
+
importOptions={disabled ? null : priming ?? sessionImport?.panel}
|
|
730
|
+
key={sessionImport?.sessionKey ?? "no-session"}
|
|
731
|
+
onImported={() => setImportedCount((count) => count + 1)}
|
|
732
|
+
url={cyclotronPriming && !disabled
|
|
733
|
+
? { labels: cyclotronPriming.labels, onRequest: cyclotronPriming.onRequest, requests: cyclotronPriming.requests }
|
|
734
|
+
: null}
|
|
735
|
+
/>
|
|
736
|
+
<ReferenceCurationControls disabled={disabled} refreshSignal={importedCount} />
|
|
604
737
|
{cyclotronStatus ? (
|
|
605
738
|
<div className="shrink-0">
|
|
606
739
|
<ReferenceCyclotronStatus onRequestRate={disabled ? undefined : onRequestReviewRate} status={cyclotronStatus} />
|
|
607
740
|
</div>
|
|
608
741
|
) : null}
|
|
742
|
+
</div>
|
|
743
|
+
</details>
|
|
609
744
|
|
|
610
745
|
<Tabs
|
|
611
746
|
className="shrink-0"
|
|
@@ -717,6 +852,10 @@ export function NewsroomReferencesView({
|
|
|
717
852
|
<ScrollArea className="min-h-0 flex-1">
|
|
718
853
|
{selectedReference ? (
|
|
719
854
|
<ReferenceDetailPanel
|
|
855
|
+
key={referenceLineageId(selectedReference)}
|
|
856
|
+
predictionState={predictionState}
|
|
857
|
+
reviewReason={reviewReasons?.get(referenceLineageId(selectedReference))}
|
|
858
|
+
reviewSectionId={reviewSectionIds?.get(referenceLineageId(selectedReference))}
|
|
720
859
|
countsAsTrainingLabel={humanCuratedReferenceLineageIds?.has(referenceLineageId(selectedReference))}
|
|
721
860
|
delegated={delegatedCurations?.get(referenceLineageId(selectedReference))}
|
|
722
861
|
decision={decisions?.get(referenceLineageId(selectedReference))}
|
|
@@ -753,6 +892,10 @@ export function NewsroomReferencesView({
|
|
|
753
892
|
{selectedReference ? (
|
|
754
893
|
<ScrollArea className="max-h-[75dvh]">
|
|
755
894
|
<ReferenceDetailPanel
|
|
895
|
+
key={referenceLineageId(selectedReference)}
|
|
896
|
+
predictionState={predictionState}
|
|
897
|
+
reviewReason={reviewReasons?.get(referenceLineageId(selectedReference))}
|
|
898
|
+
reviewSectionId={reviewSectionIds?.get(referenceLineageId(selectedReference))}
|
|
756
899
|
countsAsTrainingLabel={humanCuratedReferenceLineageIds?.has(referenceLineageId(selectedReference))}
|
|
757
900
|
delegated={delegatedCurations?.get(referenceLineageId(selectedReference))}
|
|
758
901
|
decision={decisions?.get(referenceLineageId(selectedReference))}
|