@aglyn/plugins-marketplace 1.0.0 → 1.2.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.
- package/package.json +14 -14
- package/src/lib/components/listing-detail-editor.component.js +26 -26
- package/src/lib/components/listing-detail-editor.component.js.map +1 -1
- package/src/lib/components/plugin-review-detail.component.js +17 -3
- package/src/lib/components/plugin-review-detail.component.js.map +1 -1
- package/src/lib/components/plugin-reviews-queue.component.js +88 -12
- package/src/lib/components/plugin-reviews-queue.component.js.map +1 -1
- package/src/lib/components/site-starter-review-detail.component.d.ts +115 -0
- package/src/lib/components/site-starter-review-detail.component.js +785 -0
- package/src/lib/components/site-starter-review-detail.component.js.map +1 -0
- package/src/lib/components/starter-picker-shelf.component.d.ts +7 -0
- package/src/lib/components/starter-picker-shelf.component.js +75 -1
- package/src/lib/components/starter-picker-shelf.component.js.map +1 -1
- package/src/lib/hooks/use-starter-answers.d.ts +41 -0
- package/src/lib/hooks/use-starter-answers.js +75 -0
- package/src/lib/hooks/use-starter-answers.js.map +1 -0
- package/src/lib/model/listing-query.d.ts +20 -2
- package/src/lib/model/listing-query.js +55 -0
- package/src/lib/model/listing-query.js.map +1 -1
- package/src/lib/model/plugin-rejection-categories.d.ts +17 -2
- package/src/lib/model/plugin-rejection-categories.js +48 -4
- package/src/lib/model/plugin-rejection-categories.js.map +1 -1
- package/src/lib/model/plugin-review-checklist.d.ts +38 -8
- package/src/lib/model/plugin-review-checklist.js +60 -11
- package/src/lib/model/plugin-review-checklist.js.map +1 -1
- package/src/lib/model/plugin-review-status.d.ts +8 -0
- package/src/lib/model/plugin-review-status.js +34 -0
- package/src/lib/model/plugin-review-status.js.map +1 -1
- package/src/lib/model/starter-category.d.ts +58 -0
- package/src/lib/model/starter-category.js +79 -0
- package/src/lib/model/starter-category.js.map +1 -0
- package/src/lib/model/starter-query.d.ts +27 -0
- package/src/lib/model/starter-query.js +42 -0
- package/src/lib/model/starter-query.js.map +1 -1
- package/src/lib/server/admin-reviews.js +294 -45
- package/src/lib/server/admin-reviews.js.map +1 -1
- package/src/lib/server/publish-plugin.js +46 -4
- package/src/lib/server/publish-plugin.js.map +1 -1
- package/src/lib/server/publish-starter.js +4 -0
- package/src/lib/server/publish-starter.js.map +1 -1
- package/src/lib/server/publisher-review-email.d.ts +5 -0
- package/src/lib/server/publisher-review-email.js +2 -1
- package/src/lib/server/publisher-review-email.js.map +1 -1
- package/src/lib/server/starters.d.ts +4 -1
- package/src/lib/server/starters.js +128 -28
- package/src/lib/server/starters.js.map +1 -1
- package/src/lib/server.js +12 -1
- package/src/lib/server.js.map +1 -1
|
@@ -25,7 +25,7 @@ import { useCallback, useEffect, useMemo, useState } from "react";
|
|
|
25
25
|
import { useUser } from "@aglyn/tenant-feature-instance";
|
|
26
26
|
import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
|
|
27
27
|
import { pluginDocsHelp } from "@aglyn/aglyn";
|
|
28
|
-
import { reviewStatusMeaning } from "../model/plugin-review-status.js";
|
|
28
|
+
import { reviewStatusMeaning, starterReviewStatusMeaning } from "../model/plugin-review-status.js";
|
|
29
29
|
import { REVIEW_QUEUE_QUERY } from "../model/listing-query.js";
|
|
30
30
|
const STATUS_FILTERS = [
|
|
31
31
|
{
|
|
@@ -48,6 +48,12 @@ const STATUS_FILTERS = [
|
|
|
48
48
|
value: 'verified',
|
|
49
49
|
label: 'Verified'
|
|
50
50
|
},
|
|
51
|
+
// A rejected site starter stays rejected until its publisher publishes it
|
|
52
|
+
// again (AGL-4049), so the Starters section needs a way to find it.
|
|
53
|
+
{
|
|
54
|
+
value: 'rejected',
|
|
55
|
+
label: 'Rejected'
|
|
56
|
+
},
|
|
51
57
|
{
|
|
52
58
|
value: 'hidden',
|
|
53
59
|
label: 'Taken down'
|
|
@@ -65,13 +71,16 @@ const QUEUE_OPTIONS = {
|
|
|
65
71
|
const NO_MORE = {
|
|
66
72
|
queue: false,
|
|
67
73
|
listed: false,
|
|
68
|
-
verification: false
|
|
74
|
+
verification: false,
|
|
75
|
+
starters: false
|
|
69
76
|
};
|
|
70
77
|
const FIRST_PAGES = {
|
|
71
78
|
queue: 0,
|
|
72
79
|
listed: 0,
|
|
73
|
-
verification: 0
|
|
80
|
+
verification: 0,
|
|
81
|
+
starters: 0
|
|
74
82
|
};
|
|
83
|
+
const plural = (count, one)=>`${count} ${one}${count === 1 ? '' : 's'}`;
|
|
75
84
|
/**
|
|
76
85
|
* Staff marketplace review index (AGL-961).
|
|
77
86
|
*
|
|
@@ -94,6 +103,7 @@ const FIRST_PAGES = {
|
|
|
94
103
|
const [queue, setQueue] = useState([]);
|
|
95
104
|
const [listed, setListed] = useState([]);
|
|
96
105
|
const [verificationRequests, setVerificationRequests] = useState([]);
|
|
106
|
+
const [starters, setStarters] = useState([]);
|
|
97
107
|
const [publishers, setPublishers] = useState({});
|
|
98
108
|
const [loaded, setLoaded] = useState(false);
|
|
99
109
|
const [loadError, setLoadError] = useState(null);
|
|
@@ -128,20 +138,21 @@ const FIRST_PAGES = {
|
|
|
128
138
|
const response = await authorizedFetch(user, `/api/marketplace/admin/reviews${suffix ? `?${suffix}` : ''}`);
|
|
129
139
|
const payload = await response.json().catch(()=>({}));
|
|
130
140
|
if (response.ok) {
|
|
131
|
-
var _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6;
|
|
141
|
+
var _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7;
|
|
132
142
|
setLoadError(null);
|
|
133
143
|
setQueue((_ref = payload == null ? void 0 : payload.queue) != null ? _ref : []);
|
|
134
144
|
setListed((_ref1 = payload == null ? void 0 : payload.listed) != null ? _ref1 : []);
|
|
135
145
|
setVerificationRequests((_ref2 = payload == null ? void 0 : payload.verificationRequests) != null ? _ref2 : []);
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
146
|
+
setStarters((_ref3 = payload == null ? void 0 : payload.starters) != null ? _ref3 : []);
|
|
147
|
+
setPublishers((_ref4 = payload == null ? void 0 : payload.publishers) != null ? _ref4 : {});
|
|
148
|
+
setMore(_extends({}, NO_MORE, (_ref5 = payload == null ? void 0 : payload.more) != null ? _ref5 : {}));
|
|
149
|
+
setRefused((_ref6 = payload == null ? void 0 : payload.refused) != null ? _ref6 : []);
|
|
150
|
+
setNotices((_ref7 = payload == null ? void 0 : payload.notices) != null ? _ref7 : []);
|
|
140
151
|
} else {
|
|
141
|
-
var
|
|
152
|
+
var _ref8;
|
|
142
153
|
// Named, not swallowed. An empty queue and a queue that could not be
|
|
143
154
|
// read look identical, and only one of them means there is no work.
|
|
144
|
-
setLoadError((
|
|
155
|
+
setLoadError((_ref8 = payload == null ? void 0 : payload.error) != null ? _ref8 : `Loading the queue failed (${response.status})`);
|
|
145
156
|
}
|
|
146
157
|
setLoaded(true);
|
|
147
158
|
}, [
|
|
@@ -168,10 +179,12 @@ const FIRST_PAGES = {
|
|
|
168
179
|
const visibleQueue = pageOf('queue', queue);
|
|
169
180
|
const visibleListed = pageOf('listed', listed);
|
|
170
181
|
const visibleVerification = pageOf('verification', verificationRequests);
|
|
182
|
+
const visibleStarters = pageOf('starters', starters);
|
|
171
183
|
const total = {
|
|
172
184
|
queue: queue.length,
|
|
173
185
|
listed: listed.length,
|
|
174
|
-
verification: verificationRequests.length
|
|
186
|
+
verification: verificationRequests.length,
|
|
187
|
+
starters: starters.length
|
|
175
188
|
};
|
|
176
189
|
const filtering = asked.length > 0 || status !== 'all';
|
|
177
190
|
const refusals = useMemo(()=>listQueryRefusals(refused, {
|
|
@@ -251,7 +264,7 @@ const FIRST_PAGES = {
|
|
|
251
264
|
children: [
|
|
252
265
|
/*#__PURE__*/ _jsx(TextField, {
|
|
253
266
|
size: "small",
|
|
254
|
-
placeholder: "Search plugin names",
|
|
267
|
+
placeholder: "Search plugin and starter names",
|
|
255
268
|
value: search,
|
|
256
269
|
onChange: (event)=>setSearch(event.target.value),
|
|
257
270
|
sx: {
|
|
@@ -389,6 +402,69 @@ const FIRST_PAGES = {
|
|
|
389
402
|
})
|
|
390
403
|
]
|
|
391
404
|
}),
|
|
405
|
+
/*#__PURE__*/ _jsxs(CardDisplay, {
|
|
406
|
+
header: `${status === 'all' ? 'Site starters awaiting review' : 'Site starters'} (${total.starters}${more.starters ? '+' : ''})`,
|
|
407
|
+
help: pluginDocsHelp('staffConsole', {
|
|
408
|
+
anchor: '#plugin-reviews-site-starters'
|
|
409
|
+
}),
|
|
410
|
+
contentGutterX: true,
|
|
411
|
+
contentGutterY: true,
|
|
412
|
+
children: [
|
|
413
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
414
|
+
variant: "caption",
|
|
415
|
+
color: "text.secondary",
|
|
416
|
+
sx: {
|
|
417
|
+
display: 'block',
|
|
418
|
+
mb: 1
|
|
419
|
+
},
|
|
420
|
+
children: 'Nobody but its publisher can create a site from a ' + 'starter until it is listed. Pick a status above to see ' + 'listed, rejected or taken-down starters.'
|
|
421
|
+
}),
|
|
422
|
+
visibleStarters.length ? /*#__PURE__*/ _jsxs(Stack, {
|
|
423
|
+
children: [
|
|
424
|
+
visibleStarters.map((entry)=>{
|
|
425
|
+
const meaning = starterReviewStatusMeaning(entry.reviewStatus);
|
|
426
|
+
return row(`starter-${entry.listingId}`, entry.listingId, entry.displayName, entry.profileId, /*#__PURE__*/ _jsxs(_Fragment, {
|
|
427
|
+
children: [
|
|
428
|
+
/*#__PURE__*/ _jsx(Chip, {
|
|
429
|
+
size: "small",
|
|
430
|
+
color: meaning.color,
|
|
431
|
+
label: meaning.label
|
|
432
|
+
}),
|
|
433
|
+
/*#__PURE__*/ _jsx(Chip, {
|
|
434
|
+
size: "small",
|
|
435
|
+
variant: "outlined",
|
|
436
|
+
label: `v${entry.version || '—'}`
|
|
437
|
+
}),
|
|
438
|
+
entry.reviewedVersion && entry.reviewedVersion !== entry.version ? /*#__PURE__*/ _jsx(Chip, {
|
|
439
|
+
size: "small",
|
|
440
|
+
color: "warning",
|
|
441
|
+
label: `v${entry.version} since review (v${entry.reviewedVersion})`
|
|
442
|
+
}) : null,
|
|
443
|
+
entry.official ? /*#__PURE__*/ _jsx(Chip, {
|
|
444
|
+
size: "small",
|
|
445
|
+
variant: "outlined",
|
|
446
|
+
label: "Official"
|
|
447
|
+
}) : null,
|
|
448
|
+
entry.hidden ? /*#__PURE__*/ _jsx(Chip, {
|
|
449
|
+
size: "small",
|
|
450
|
+
color: "error",
|
|
451
|
+
label: "Taken down"
|
|
452
|
+
}) : null
|
|
453
|
+
]
|
|
454
|
+
}), [
|
|
455
|
+
plural(entry.pages, 'page'),
|
|
456
|
+
entry.priceUsd > 0 ? `$${entry.priceUsd}` : 'Free',
|
|
457
|
+
entry.submittedAt ? `Submitted ${new Date(entry.submittedAt).toLocaleDateString()}` : ''
|
|
458
|
+
].filter(Boolean).join(' · '));
|
|
459
|
+
}),
|
|
460
|
+
pager('starters', visibleStarters.length)
|
|
461
|
+
]
|
|
462
|
+
}) : /*#__PURE__*/ _jsx(Alert, {
|
|
463
|
+
severity: filtering ? 'info' : 'success',
|
|
464
|
+
children: filtering ? 'No site starters match this filter.' : 'No site starters waiting for review.'
|
|
465
|
+
})
|
|
466
|
+
]
|
|
467
|
+
}),
|
|
392
468
|
/*#__PURE__*/ _jsxs(CardDisplay, {
|
|
393
469
|
header: `Listed plugins (${total.listed}${more.listed ? '+' : ''})`,
|
|
394
470
|
help: pluginDocsHelp('manifestAndEnvs', {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/components/plugin-reviews-queue.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { PageHeaderHelp } from '@aglyn/aglyn'\nimport { AppLink, CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport ListQueryNotices, {\n listQueryRefusals,\n} from '@aglyn/shared-ui-jsx/components/list-query-notices.component'\nimport type { ListFilterClause } from '@aglyn/shared-ui-jsx/const/list-grid-filter'\nimport {\n Alert,\n Chip,\n MenuItem,\n Skeleton,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { reviewStatusMeaning } from '../model/plugin-review-status'\nimport {\n REVIEW_QUEUE_QUERY,\n type ReviewQueueSection,\n} from '../model/listing-query'\n\ninterface QueueRow {\n listingId: string\n displayName: string\n description: string\n license: string\n categories: string[]\n profileId: string\n reviewStatus: string\n priceUsd: number\n version: string\n hidden: boolean\n /** Private plugin (AGL-968): reviewed identically, never listed. */\n private: boolean\n /** The publisher's standing ask for the Verified badge (AGL-1217). */\n verificationRequest?: { state?: string; requestedAt?: unknown } | null\n}\n\ninterface ListedRow {\n listingId: string\n displayName: string\n reviewStatus: string\n profileId: string\n latestVersion: string\n hidden: boolean\n hiddenReason: string\n realmVersions: number\n versionCount: number\n private: boolean\n}\n\nconst STATUS_FILTERS = [\n { value: 'all', label: 'All statuses' },\n { value: 'submitted', label: 'Submitted' },\n { value: 'in_review', label: 'In review' },\n { value: 'listed', label: 'Listed' },\n { value: 'verified', label: 'Verified' },\n { value: 'hidden', label: 'Taken down' },\n]\n\n/** How the queue's clauses read in a refusal. */\nconst QUEUE_HEADERS: Readonly<Record<string, string>> = {\n reviewStatus: 'Status',\n takenDown: 'Taken down',\n}\nconst QUEUE_OPTIONS = {\n reviewStatus: STATUS_FILTERS.filter(\n (option) => option.value !== 'all' && option.value !== 'hidden',\n ),\n}\n\n/** Rows per page of each section. */\nconst QUEUE_PAGE = 50\n/** How long the search box waits for typing to stop before it asks again. */\nconst SEARCH_SETTLE_MS = 300\n\nconst NO_MORE: Record<ReviewQueueSection, boolean> = {\n queue: false,\n listed: false,\n verification: false,\n}\nconst FIRST_PAGES: Record<ReviewQueueSection, number> = {\n queue: 0,\n listed: 0,\n verification: 0,\n}\n\n/**\n * Staff marketplace review index (AGL-961).\n *\n * Scanning surface only: rows carry just enough to pick the right listing,\n * and every consequential action — verdicts, realm trust, takedown — lives\n * on the detail page. The previous version stacked all of it inline, which\n * meant the most destructive controls in the platform sat as same-weight\n * text buttons in a wall of caption text.\n *\n * The search box and the Status select are served by the route's QUERY\n * (AGL-3321): each section asks Firestore for its rows with the status and\n * the searched name word on it, so a plugin past the first hundred is found.\n * They used to be matched here over the hundred the route had read. Search\n * reads the listing name; a refusal or a one-word notice from the plan is\n * shown above the sections. Each section pages: the route reads every section\n * out to the furthest page asked plus one row, which is how a section knows\n * there is a next page (the window `usePagedCollection` reads, over a route).\n */\nexport function PluginReviewsQueue({ basePath }: { basePath: string }) {\n const { data: user } = useUser()\n const [queue, setQueue] = useState<QueueRow[]>([])\n const [listed, setListed] = useState<ListedRow[]>([])\n const [verificationRequests, setVerificationRequests] = useState<QueueRow[]>(\n [],\n )\n const [publishers, setPublishers] = useState<Record<string, string>>({})\n const [loaded, setLoaded] = useState(false)\n const [loadError, setLoadError] = useState<string | null>(null)\n const [search, setSearch] = useState('')\n const [asked, setAsked] = useState('')\n const [status, setStatus] = useState('all')\n const [pages, setPages] =\n useState<Record<ReviewQueueSection, number>>(FIRST_PAGES)\n /** Every section is read out to the furthest page any of them is on. */\n const limit = QUEUE_PAGE * (Math.max(...Object.values(pages)) + 1)\n const [more, setMore] = useState<Record<ReviewQueueSection, boolean>>(NO_MORE)\n const [refused, setRefused] = useState<\n Array<{ clause: ListFilterClause | 'search'; reason: string }>\n >([])\n const [notices, setNotices] = useState<string[]>([])\n\n // The search is asked once typing settles, not per keystroke.\n useEffect(() => {\n const timer = setTimeout(() => setAsked(search.trim()), SEARCH_SETTLE_MS)\n return () => clearTimeout(timer)\n }, [search])\n // A new question starts from the first page.\n useEffect(() => {\n setPages(FIRST_PAGES)\n }, [asked, status])\n\n const refresh = useCallback(async () => {\n const params = new URLSearchParams()\n if (asked) params.set('q', asked)\n if (status !== 'all') params.set('status', status)\n params.set('limit', String(limit))\n const suffix = params.toString()\n const response = await authorizedFetch(\n user,\n `/api/marketplace/admin/reviews${suffix ? `?${suffix}` : ''}`,\n )\n const payload = await response.json().catch(() => ({}))\n if (response.ok) {\n setLoadError(null)\n setQueue(payload?.queue ?? [])\n setListed(payload?.listed ?? [])\n setVerificationRequests(payload?.verificationRequests ?? [])\n setPublishers(payload?.publishers ?? {})\n setMore({ ...NO_MORE, ...(payload?.more ?? {}) })\n setRefused(payload?.refused ?? [])\n setNotices(payload?.notices ?? [])\n } else {\n // Named, not swallowed. An empty queue and a queue that could not be\n // read look identical, and only one of them means there is no work.\n setLoadError(\n payload?.error ?? `Loading the queue failed (${response.status})`,\n )\n }\n setLoaded(true)\n }, [user, asked, status, limit])\n\n useEffect(() => {\n if (user) void refresh()\n }, [user, refresh])\n\n const publisherName = useCallback(\n (profileId: string) => publishers[profileId] ?? profileId,\n [publishers],\n )\n\n // Every section is already what the query answered: nothing is matched\n // here, only the page on screen sliced out of the window read.\n const pageOf = <T,>(section: ReviewQueueSection, rows: T[]): T[] =>\n rows.slice(pages[section] * QUEUE_PAGE, (pages[section] + 1) * QUEUE_PAGE)\n const visibleQueue = pageOf('queue', queue)\n const visibleListed = pageOf('listed', listed)\n const visibleVerification = pageOf('verification', verificationRequests)\n const total: Record<ReviewQueueSection, number> = {\n queue: queue.length,\n listed: listed.length,\n verification: verificationRequests.length,\n }\n const filtering = asked.length > 0 || status !== 'all'\n const refusals = useMemo(\n () =>\n listQueryRefusals(refused, {\n fields: REVIEW_QUEUE_QUERY.fields,\n headers: QUEUE_HEADERS,\n options: QUEUE_OPTIONS,\n }),\n [refused],\n )\n const pager = (section: ReviewQueueSection, shown: number) => {\n const hasMore =\n total[section] > (pages[section] + 1) * QUEUE_PAGE || more[section]\n return pages[section] > 0 || hasMore ? (\n <ListPagination\n page={pages[section]}\n pageSize={QUEUE_PAGE}\n rowCount={shown}\n hasMore={hasMore}\n onPageChange={(page) =>\n setPages((previous) => ({ ...previous, [section]: page }))\n }\n />\n ) : null\n }\n\n const row = (\n key: string,\n listingId: string,\n name: string,\n profileId: string,\n chips: React.ReactNode,\n caption: string,\n ) => (\n <Stack\n key={key}\n spacing={0.25}\n sx={{\n py: 1,\n borderBottom: 1,\n borderColor: 'divider',\n '&:last-of-type': { borderBottom: 0 },\n }}\n >\n <Stack\n useFlexGap\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center', flexWrap: 'wrap' }}\n >\n <AppLink href={`${basePath}/${encodeURIComponent(listingId)}`}>\n <Typography variant=\"subtitle2\" component=\"span\">\n {name}\n </Typography>\n </AppLink>\n {chips}\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${publisherName(profileId)} · ${caption}`}\n </Typography>\n </Stack>\n )\n\n return (\n <>\n {/*\n The staff console's own topic, anchored. A `staffPages` entry carries\n one `docsTopic` and no anchor, and the staff console page is long\n enough that landing at the top of it is the AGL-2200 shape.\n */}\n <PageHeaderHelp topic=\"staffConsole\" anchor=\"#plugin-reviews\" />\n {/*\n The staff gate is the shell's: the generic staff route renders every\n plugin page inside `StaffOnly`, which renders nothing while the claim\n resolves and 404s a non-holder. Without it a non-staff visitor was\n told \"No plugin submissions waiting for review\" — the queue fetch\n 403s and the empty result reads as good news rather than a refusal\n (AGL-760).\n */}\n <Stack spacing={3}>\n <Stack\n useFlexGap\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center', flexWrap: 'wrap' }}\n >\n <TextField\n size=\"small\"\n placeholder=\"Search plugin names\"\n value={search}\n onChange={(event) => setSearch(event.target.value)}\n sx={{ minWidth: 320 }}\n />\n <TextField\n size=\"small\"\n select\n value={status}\n onChange={(event) => setStatus(event.target.value)}\n sx={{ minWidth: 180 }}\n >\n {STATUS_FILTERS.map((option) => (\n <MenuItem key={option.value} value={option.value}>\n {option.label}\n </MenuItem>\n ))}\n </TextField>\n </Stack>\n\n {loadError ? (\n <Alert severity=\"error\">{loadError}</Alert>\n ) : null}\n <ListQueryNotices refused={refusals} notices={notices} />\n\n {!loaded ? (\n <Stack spacing={2}>\n <Skeleton variant=\"rounded\" height={140} />\n <Skeleton variant=\"rounded\" height={200} />\n </Stack>\n ) : (\n <>\n {/* Its own card, above the review queue (AGL-1217). A\n verification request is a different question from\n \"have these bytes been read\" — it is about the\n publisher, and it is answered by a different action.\n Folded into Awaiting review it would be invisible: a\n listing whose bytes are already approved does not\n appear there at all. Hidden when empty, so it costs\n nothing on the common day. */}\n {visibleVerification.length ? (\n <CardDisplay\n header={`Verification requested (${total.verification}${more.verification ? '+' : ''})`}\n help={pluginDocsHelp('manifestAndEnvs', {\n anchor: '#verification-requests',\n })}\n contentGutterX\n contentGutterY\n >\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', mb: 1 }}\n >\n {'These plugins are already live. The publisher has ' +\n 'asked us to vouch for who they are — granting adds ' +\n 'the badge and changes nothing about installability.'}\n </Typography>\n <Stack>\n {visibleVerification.map((entry) =>\n row(\n `verify-${entry.listingId}`,\n entry.listingId,\n entry.displayName,\n entry.profileId,\n <>\n <Chip\n size=\"small\"\n color=\"info\"\n label=\"Verification requested\"\n />\n <Chip\n size=\"small\"\n color={reviewStatusMeaning(entry.reviewStatus).color}\n label={reviewStatusMeaning(entry.reviewStatus).label}\n />\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label={`v${entry.version || '—'}`}\n />\n </>,\n 'Awaiting a verification decision',\n ),\n )}\n {pager('verification', visibleVerification.length)}\n </Stack>\n </CardDisplay>\n ) : null}\n <CardDisplay\n header={`Awaiting review (${total.queue}${more.queue ? '+' : ''})`}\n help={pluginDocsHelp('manifestAndEnvs', {\n anchor: '#review-queue',\n })}\n contentGutterX\n contentGutterY\n >\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', mb: 1 }}\n >\n {'Submitted and In review are not installable by anyone.'}\n </Typography>\n {visibleQueue.length ? (\n <Stack>\n {visibleQueue.map((entry) =>\n row(\n entry.listingId,\n entry.listingId,\n entry.displayName,\n entry.profileId,\n <>\n <Chip\n size=\"small\"\n color={reviewStatusMeaning(entry.reviewStatus).color}\n label={reviewStatusMeaning(entry.reviewStatus).label}\n />\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label={`v${entry.version || '—'}`}\n />\n {/* Same bar, smaller audience (AGL-968/995).\n Worth flagging so a reviewer knows the\n blast radius is one workspace — never so\n they review it more loosely. */}\n {entry.private ? (\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label=\"Private\"\n />\n ) : null}\n {/* A private plugin has no marketplace listing\n page, so \"no license\" is not a finding. */}\n {entry.license || entry.private ? null : (\n <Chip\n size=\"small\"\n color=\"warning\"\n label=\"No license\"\n />\n )}\n </>,\n entry.priceUsd > 0 ? `$${entry.priceUsd}` : 'Free',\n ),\n )}\n {pager('queue', visibleQueue.length)}\n </Stack>\n ) : (\n <Alert severity={filtering ? 'info' : 'success'}>\n {filtering\n ? 'No submissions match this filter.'\n : 'No plugin submissions waiting for review.'}\n </Alert>\n )}\n </CardDisplay>\n\n <CardDisplay\n header={`Listed plugins (${total.listed}${more.listed ? '+' : ''})`}\n help={pluginDocsHelp('manifestAndEnvs', {\n anchor: '#listed-plugins',\n })}\n contentGutterX\n contentGutterY\n >\n {/* Listed vs Verified is the distinction reviewers get\n wrong (AGL-966): both are LIVE. Verified only adds a\n badge — it does not change who can install. */}\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', mb: 1 }}\n >\n {'Both states are live — installable by every workspace. ' +\n 'Verified additionally carries the reviewed badge on ' +\n 'its listing page; it does not change installability. ' +\n // The sentence above is false for a private row\n // (AGL-968/995), and it sits directly over the rows\n // it would misdescribe.\n 'Rows marked Private are the exception: approved and ' +\n 'live, but only for the org that published them.'}\n </Typography>\n {visibleListed.length ? (\n <Stack>\n {visibleListed.map((entry) =>\n row(\n entry.listingId,\n entry.listingId,\n entry.displayName,\n entry.profileId,\n <>\n <Chip\n size=\"small\"\n color={reviewStatusMeaning(entry.reviewStatus).color}\n label={reviewStatusMeaning(entry.reviewStatus).label}\n />\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label={`v${entry.latestVersion || '—'}`}\n />\n {entry.private ? (\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label=\"Private\"\n />\n ) : null}\n {entry.realmVersions ? (\n <Chip\n size=\"small\"\n color=\"success\"\n label={`${entry.realmVersions} realm-trusted`}\n />\n ) : null}\n {entry.hidden ? (\n <Chip\n size=\"small\"\n color=\"error\"\n label=\"Taken down\"\n />\n ) : null}\n </>,\n `${entry.versionCount} version${\n entry.versionCount === 1 ? '' : 's'\n }${entry.hidden && entry.hiddenReason ? ` · ${entry.hiddenReason}` : ''}`,\n ),\n )}\n {pager('listed', visibleListed.length)}\n </Stack>\n ) : (\n <Alert severity=\"info\">\n {filtering\n ? 'No listed plugins match this filter.'\n : 'No listed plugins yet.'}\n </Alert>\n )}\n </CardDisplay>\n </>\n )}\n </Stack>\n </>\n )\n}\n\nexport default PluginReviewsQueue\n"],"names":["PageHeaderHelp","AppLink","CardDisplay","ListPagination","ListQueryNotices","listQueryRefusals","Alert","Chip","MenuItem","Skeleton","Stack","TextField","Typography","useCallback","useEffect","useMemo","useState","useUser","authorizedFetch","pluginDocsHelp","reviewStatusMeaning","REVIEW_QUEUE_QUERY","STATUS_FILTERS","value","label","QUEUE_HEADERS","reviewStatus","takenDown","QUEUE_OPTIONS","filter","option","QUEUE_PAGE","SEARCH_SETTLE_MS","NO_MORE","queue","listed","verification","FIRST_PAGES","PluginReviewsQueue","basePath","data","user","setQueue","setListed","verificationRequests","setVerificationRequests","publishers","setPublishers","loaded","setLoaded","loadError","setLoadError","search","setSearch","asked","setAsked","status","setStatus","pages","setPages","limit","Math","max","Object","values","more","setMore","refused","setRefused","notices","setNotices","timer","setTimeout","trim","clearTimeout","refresh","params","URLSearchParams","set","String","suffix","toString","response","payload","json","catch","ok","error","publisherName","profileId","pageOf","section","rows","slice","visibleQueue","visibleListed","visibleVerification","total","length","filtering","refusals","fields","headers","options","pager","shown","hasMore","page","pageSize","rowCount","onPageChange","previous","row","key","listingId","name","chips","caption","spacing","sx","py","borderBottom","borderColor","useFlexGap","direction","alignItems","flexWrap","href","encodeURIComponent","variant","component","color","topic","anchor","size","placeholder","onChange","event","target","minWidth","select","map","severity","height","header","help","contentGutterX","contentGutterY","display","mb","entry","displayName","version","private","license","priceUsd","latestVersion","realmVersions","hidden","versionCount","hiddenReason"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/components/plugin-reviews-queue.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { PageHeaderHelp } from '@aglyn/aglyn'\nimport { AppLink, CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport ListQueryNotices, {\n listQueryRefusals,\n} from '@aglyn/shared-ui-jsx/components/list-query-notices.component'\nimport type { ListFilterClause } from '@aglyn/shared-ui-jsx/const/list-grid-filter'\nimport {\n Alert,\n Chip,\n MenuItem,\n Skeleton,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport {\n reviewStatusMeaning,\n starterReviewStatusMeaning,\n} from '../model/plugin-review-status'\nimport {\n REVIEW_QUEUE_QUERY,\n type ReviewQueueSection,\n} from '../model/listing-query'\n\ninterface QueueRow {\n listingId: string\n displayName: string\n description: string\n license: string\n categories: string[]\n profileId: string\n reviewStatus: string\n priceUsd: number\n version: string\n hidden: boolean\n /** Private plugin (AGL-968): reviewed identically, never listed. */\n private: boolean\n /** The publisher's standing ask for the Verified badge (AGL-1217). */\n verificationRequest?: { state?: string; requestedAt?: unknown } | null\n}\n\ninterface ListedRow {\n listingId: string\n displayName: string\n reviewStatus: string\n profileId: string\n latestVersion: string\n hidden: boolean\n hiddenReason: string\n realmVersions: number\n versionCount: number\n private: boolean\n}\n\n/** A site starter's row (AGL-4049): what a reviewer scans a starter by. */\ninterface StarterRow {\n listingId: string\n displayName: string\n profileId: string\n reviewStatus: string\n priceUsd: number\n pages: number\n version: string\n /** The version the last verdict was given on, or null before one. */\n reviewedVersion: string | null\n submittedAt: string | null\n hidden: boolean\n official: boolean\n}\n\nconst STATUS_FILTERS = [\n { value: 'all', label: 'All statuses' },\n { value: 'submitted', label: 'Submitted' },\n { value: 'in_review', label: 'In review' },\n { value: 'listed', label: 'Listed' },\n { value: 'verified', label: 'Verified' },\n // A rejected site starter stays rejected until its publisher publishes it\n // again (AGL-4049), so the Starters section needs a way to find it.\n { value: 'rejected', label: 'Rejected' },\n { value: 'hidden', label: 'Taken down' },\n]\n\n/** How the queue's clauses read in a refusal. */\nconst QUEUE_HEADERS: Readonly<Record<string, string>> = {\n reviewStatus: 'Status',\n takenDown: 'Taken down',\n}\nconst QUEUE_OPTIONS = {\n reviewStatus: STATUS_FILTERS.filter(\n (option) => option.value !== 'all' && option.value !== 'hidden',\n ),\n}\n\n/** Rows per page of each section. */\nconst QUEUE_PAGE = 50\n/** How long the search box waits for typing to stop before it asks again. */\nconst SEARCH_SETTLE_MS = 300\n\nconst NO_MORE: Record<ReviewQueueSection, boolean> = {\n queue: false,\n listed: false,\n verification: false,\n starters: false,\n}\nconst FIRST_PAGES: Record<ReviewQueueSection, number> = {\n queue: 0,\n listed: 0,\n verification: 0,\n starters: 0,\n}\n\nconst plural = (count: number, one: string) =>\n `${count} ${one}${count === 1 ? '' : 's'}`\n\n/**\n * Staff marketplace review index (AGL-961).\n *\n * Scanning surface only: rows carry just enough to pick the right listing,\n * and every consequential action — verdicts, realm trust, takedown — lives\n * on the detail page. The previous version stacked all of it inline, which\n * meant the most destructive controls in the platform sat as same-weight\n * text buttons in a wall of caption text.\n *\n * The search box and the Status select are served by the route's QUERY\n * (AGL-3321): each section asks Firestore for its rows with the status and\n * the searched name word on it, so a plugin past the first hundred is found.\n * They used to be matched here over the hundred the route had read. Search\n * reads the listing name; a refusal or a one-word notice from the plan is\n * shown above the sections. Each section pages: the route reads every section\n * out to the furthest page asked plus one row, which is how a section knows\n * there is a next page (the window `usePagedCollection` reads, over a route).\n */\nexport function PluginReviewsQueue({ basePath }: { basePath: string }) {\n const { data: user } = useUser()\n const [queue, setQueue] = useState<QueueRow[]>([])\n const [listed, setListed] = useState<ListedRow[]>([])\n const [verificationRequests, setVerificationRequests] = useState<QueueRow[]>(\n [],\n )\n const [starters, setStarters] = useState<StarterRow[]>([])\n const [publishers, setPublishers] = useState<Record<string, string>>({})\n const [loaded, setLoaded] = useState(false)\n const [loadError, setLoadError] = useState<string | null>(null)\n const [search, setSearch] = useState('')\n const [asked, setAsked] = useState('')\n const [status, setStatus] = useState('all')\n const [pages, setPages] =\n useState<Record<ReviewQueueSection, number>>(FIRST_PAGES)\n /** Every section is read out to the furthest page any of them is on. */\n const limit = QUEUE_PAGE * (Math.max(...Object.values(pages)) + 1)\n const [more, setMore] = useState<Record<ReviewQueueSection, boolean>>(NO_MORE)\n const [refused, setRefused] = useState<\n Array<{ clause: ListFilterClause | 'search'; reason: string }>\n >([])\n const [notices, setNotices] = useState<string[]>([])\n\n // The search is asked once typing settles, not per keystroke.\n useEffect(() => {\n const timer = setTimeout(() => setAsked(search.trim()), SEARCH_SETTLE_MS)\n return () => clearTimeout(timer)\n }, [search])\n // A new question starts from the first page.\n useEffect(() => {\n setPages(FIRST_PAGES)\n }, [asked, status])\n\n const refresh = useCallback(async () => {\n const params = new URLSearchParams()\n if (asked) params.set('q', asked)\n if (status !== 'all') params.set('status', status)\n params.set('limit', String(limit))\n const suffix = params.toString()\n const response = await authorizedFetch(\n user,\n `/api/marketplace/admin/reviews${suffix ? `?${suffix}` : ''}`,\n )\n const payload = await response.json().catch(() => ({}))\n if (response.ok) {\n setLoadError(null)\n setQueue(payload?.queue ?? [])\n setListed(payload?.listed ?? [])\n setVerificationRequests(payload?.verificationRequests ?? [])\n setStarters(payload?.starters ?? [])\n setPublishers(payload?.publishers ?? {})\n setMore({ ...NO_MORE, ...(payload?.more ?? {}) })\n setRefused(payload?.refused ?? [])\n setNotices(payload?.notices ?? [])\n } else {\n // Named, not swallowed. An empty queue and a queue that could not be\n // read look identical, and only one of them means there is no work.\n setLoadError(\n payload?.error ?? `Loading the queue failed (${response.status})`,\n )\n }\n setLoaded(true)\n }, [user, asked, status, limit])\n\n useEffect(() => {\n if (user) void refresh()\n }, [user, refresh])\n\n const publisherName = useCallback(\n (profileId: string) => publishers[profileId] ?? profileId,\n [publishers],\n )\n\n // Every section is already what the query answered: nothing is matched\n // here, only the page on screen sliced out of the window read.\n const pageOf = <T,>(section: ReviewQueueSection, rows: T[]): T[] =>\n rows.slice(pages[section] * QUEUE_PAGE, (pages[section] + 1) * QUEUE_PAGE)\n const visibleQueue = pageOf('queue', queue)\n const visibleListed = pageOf('listed', listed)\n const visibleVerification = pageOf('verification', verificationRequests)\n const visibleStarters = pageOf('starters', starters)\n const total: Record<ReviewQueueSection, number> = {\n queue: queue.length,\n listed: listed.length,\n verification: verificationRequests.length,\n starters: starters.length,\n }\n const filtering = asked.length > 0 || status !== 'all'\n const refusals = useMemo(\n () =>\n listQueryRefusals(refused, {\n fields: REVIEW_QUEUE_QUERY.fields,\n headers: QUEUE_HEADERS,\n options: QUEUE_OPTIONS,\n }),\n [refused],\n )\n const pager = (section: ReviewQueueSection, shown: number) => {\n const hasMore =\n total[section] > (pages[section] + 1) * QUEUE_PAGE || more[section]\n return pages[section] > 0 || hasMore ? (\n <ListPagination\n page={pages[section]}\n pageSize={QUEUE_PAGE}\n rowCount={shown}\n hasMore={hasMore}\n onPageChange={(page) =>\n setPages((previous) => ({ ...previous, [section]: page }))\n }\n />\n ) : null\n }\n\n const row = (\n key: string,\n listingId: string,\n name: string,\n profileId: string,\n chips: React.ReactNode,\n caption: string,\n ) => (\n <Stack\n key={key}\n spacing={0.25}\n sx={{\n py: 1,\n borderBottom: 1,\n borderColor: 'divider',\n '&:last-of-type': { borderBottom: 0 },\n }}\n >\n <Stack\n useFlexGap\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center', flexWrap: 'wrap' }}\n >\n <AppLink href={`${basePath}/${encodeURIComponent(listingId)}`}>\n <Typography variant=\"subtitle2\" component=\"span\">\n {name}\n </Typography>\n </AppLink>\n {chips}\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${publisherName(profileId)} · ${caption}`}\n </Typography>\n </Stack>\n )\n\n return (\n <>\n {/*\n The staff console's own topic, anchored. A `staffPages` entry carries\n one `docsTopic` and no anchor, and the staff console page is long\n enough that landing at the top of it is the AGL-2200 shape.\n */}\n <PageHeaderHelp topic=\"staffConsole\" anchor=\"#plugin-reviews\" />\n {/*\n The staff gate is the shell's: the generic staff route renders every\n plugin page inside `StaffOnly`, which renders nothing while the claim\n resolves and 404s a non-holder. Without it a non-staff visitor was\n told \"No plugin submissions waiting for review\" — the queue fetch\n 403s and the empty result reads as good news rather than a refusal\n (AGL-760).\n */}\n <Stack spacing={3}>\n <Stack\n useFlexGap\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center', flexWrap: 'wrap' }}\n >\n <TextField\n size=\"small\"\n placeholder=\"Search plugin and starter names\"\n value={search}\n onChange={(event) => setSearch(event.target.value)}\n sx={{ minWidth: 320 }}\n />\n <TextField\n size=\"small\"\n select\n value={status}\n onChange={(event) => setStatus(event.target.value)}\n sx={{ minWidth: 180 }}\n >\n {STATUS_FILTERS.map((option) => (\n <MenuItem key={option.value} value={option.value}>\n {option.label}\n </MenuItem>\n ))}\n </TextField>\n </Stack>\n\n {loadError ? (\n <Alert severity=\"error\">{loadError}</Alert>\n ) : null}\n <ListQueryNotices refused={refusals} notices={notices} />\n\n {!loaded ? (\n <Stack spacing={2}>\n <Skeleton variant=\"rounded\" height={140} />\n <Skeleton variant=\"rounded\" height={200} />\n </Stack>\n ) : (\n <>\n {/* Its own card, above the review queue (AGL-1217). A\n verification request is a different question from\n \"have these bytes been read\" — it is about the\n publisher, and it is answered by a different action.\n Folded into Awaiting review it would be invisible: a\n listing whose bytes are already approved does not\n appear there at all. Hidden when empty, so it costs\n nothing on the common day. */}\n {visibleVerification.length ? (\n <CardDisplay\n header={`Verification requested (${total.verification}${more.verification ? '+' : ''})`}\n help={pluginDocsHelp('manifestAndEnvs', {\n anchor: '#verification-requests',\n })}\n contentGutterX\n contentGutterY\n >\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', mb: 1 }}\n >\n {'These plugins are already live. The publisher has ' +\n 'asked us to vouch for who they are — granting adds ' +\n 'the badge and changes nothing about installability.'}\n </Typography>\n <Stack>\n {visibleVerification.map((entry) =>\n row(\n `verify-${entry.listingId}`,\n entry.listingId,\n entry.displayName,\n entry.profileId,\n <>\n <Chip\n size=\"small\"\n color=\"info\"\n label=\"Verification requested\"\n />\n <Chip\n size=\"small\"\n color={reviewStatusMeaning(entry.reviewStatus).color}\n label={reviewStatusMeaning(entry.reviewStatus).label}\n />\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label={`v${entry.version || '—'}`}\n />\n </>,\n 'Awaiting a verification decision',\n ),\n )}\n {pager('verification', visibleVerification.length)}\n </Stack>\n </CardDisplay>\n ) : null}\n <CardDisplay\n header={`Awaiting review (${total.queue}${more.queue ? '+' : ''})`}\n help={pluginDocsHelp('manifestAndEnvs', {\n anchor: '#review-queue',\n })}\n contentGutterX\n contentGutterY\n >\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', mb: 1 }}\n >\n {'Submitted and In review are not installable by anyone.'}\n </Typography>\n {visibleQueue.length ? (\n <Stack>\n {visibleQueue.map((entry) =>\n row(\n entry.listingId,\n entry.listingId,\n entry.displayName,\n entry.profileId,\n <>\n <Chip\n size=\"small\"\n color={reviewStatusMeaning(entry.reviewStatus).color}\n label={reviewStatusMeaning(entry.reviewStatus).label}\n />\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label={`v${entry.version || '—'}`}\n />\n {/* Same bar, smaller audience (AGL-968/995).\n Worth flagging so a reviewer knows the\n blast radius is one workspace — never so\n they review it more loosely. */}\n {entry.private ? (\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label=\"Private\"\n />\n ) : null}\n {/* A private plugin has no marketplace listing\n page, so \"no license\" is not a finding. */}\n {entry.license || entry.private ? null : (\n <Chip\n size=\"small\"\n color=\"warning\"\n label=\"No license\"\n />\n )}\n </>,\n entry.priceUsd > 0 ? `$${entry.priceUsd}` : 'Free',\n ),\n )}\n {pager('queue', visibleQueue.length)}\n </Stack>\n ) : (\n <Alert severity={filtering ? 'info' : 'success'}>\n {filtering\n ? 'No submissions match this filter.'\n : 'No plugin submissions waiting for review.'}\n </Alert>\n )}\n </CardDisplay>\n\n {/* Site starters (AGL-4049), their own card: a starter is a\n whole site someone creates the moment they pick it, not\n code, so a row says what it is made of and costs rather\n than a version's review state. With All statuses it holds\n the ones waiting; a status names the rest. */}\n <CardDisplay\n header={`${status === 'all' ? 'Site starters awaiting review' : 'Site starters'} (${total.starters}${more.starters ? '+' : ''})`}\n help={pluginDocsHelp('staffConsole', {\n anchor: '#plugin-reviews-site-starters',\n })}\n contentGutterX\n contentGutterY\n >\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', mb: 1 }}\n >\n {'Nobody but its publisher can create a site from a ' +\n 'starter until it is listed. Pick a status above to see ' +\n 'listed, rejected or taken-down starters.'}\n </Typography>\n {visibleStarters.length ? (\n <Stack>\n {visibleStarters.map((entry) => {\n const meaning = starterReviewStatusMeaning(entry.reviewStatus)\n return row(\n `starter-${entry.listingId}`,\n entry.listingId,\n entry.displayName,\n entry.profileId,\n <>\n <Chip size=\"small\" color={meaning.color} label={meaning.label} />\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label={`v${entry.version || '—'}`}\n />\n {/* Listed stays listed when it is published again,\n so a newer version than the one reviewed is\n what a reviewer looks for under Listed. */}\n {entry.reviewedVersion &&\n entry.reviewedVersion !== entry.version ? (\n <Chip\n size=\"small\"\n color=\"warning\"\n label={`v${entry.version} since review (v${entry.reviewedVersion})`}\n />\n ) : null}\n {entry.official ? (\n <Chip size=\"small\" variant=\"outlined\" label=\"Official\" />\n ) : null}\n {entry.hidden ? (\n <Chip size=\"small\" color=\"error\" label=\"Taken down\" />\n ) : null}\n </>,\n [\n plural(entry.pages, 'page'),\n entry.priceUsd > 0 ? `$${entry.priceUsd}` : 'Free',\n entry.submittedAt\n ? `Submitted ${new Date(entry.submittedAt).toLocaleDateString()}`\n : '',\n ]\n .filter(Boolean)\n .join(' · '),\n )\n })}\n {pager('starters', visibleStarters.length)}\n </Stack>\n ) : (\n <Alert severity={filtering ? 'info' : 'success'}>\n {filtering\n ? 'No site starters match this filter.'\n : 'No site starters waiting for review.'}\n </Alert>\n )}\n </CardDisplay>\n\n <CardDisplay\n header={`Listed plugins (${total.listed}${more.listed ? '+' : ''})`}\n help={pluginDocsHelp('manifestAndEnvs', {\n anchor: '#listed-plugins',\n })}\n contentGutterX\n contentGutterY\n >\n {/* Listed vs Verified is the distinction reviewers get\n wrong (AGL-966): both are LIVE. Verified only adds a\n badge — it does not change who can install. */}\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', mb: 1 }}\n >\n {'Both states are live — installable by every workspace. ' +\n 'Verified additionally carries the reviewed badge on ' +\n 'its listing page; it does not change installability. ' +\n // The sentence above is false for a private row\n // (AGL-968/995), and it sits directly over the rows\n // it would misdescribe.\n 'Rows marked Private are the exception: approved and ' +\n 'live, but only for the org that published them.'}\n </Typography>\n {visibleListed.length ? (\n <Stack>\n {visibleListed.map((entry) =>\n row(\n entry.listingId,\n entry.listingId,\n entry.displayName,\n entry.profileId,\n <>\n <Chip\n size=\"small\"\n color={reviewStatusMeaning(entry.reviewStatus).color}\n label={reviewStatusMeaning(entry.reviewStatus).label}\n />\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label={`v${entry.latestVersion || '—'}`}\n />\n {entry.private ? (\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label=\"Private\"\n />\n ) : null}\n {entry.realmVersions ? (\n <Chip\n size=\"small\"\n color=\"success\"\n label={`${entry.realmVersions} realm-trusted`}\n />\n ) : null}\n {entry.hidden ? (\n <Chip\n size=\"small\"\n color=\"error\"\n label=\"Taken down\"\n />\n ) : null}\n </>,\n `${entry.versionCount} version${\n entry.versionCount === 1 ? '' : 's'\n }${entry.hidden && entry.hiddenReason ? ` · ${entry.hiddenReason}` : ''}`,\n ),\n )}\n {pager('listed', visibleListed.length)}\n </Stack>\n ) : (\n <Alert severity=\"info\">\n {filtering\n ? 'No listed plugins match this filter.'\n : 'No listed plugins yet.'}\n </Alert>\n )}\n </CardDisplay>\n </>\n )}\n </Stack>\n </>\n )\n}\n\nexport default PluginReviewsQueue\n"],"names":["PageHeaderHelp","AppLink","CardDisplay","ListPagination","ListQueryNotices","listQueryRefusals","Alert","Chip","MenuItem","Skeleton","Stack","TextField","Typography","useCallback","useEffect","useMemo","useState","useUser","authorizedFetch","pluginDocsHelp","reviewStatusMeaning","starterReviewStatusMeaning","REVIEW_QUEUE_QUERY","STATUS_FILTERS","value","label","QUEUE_HEADERS","reviewStatus","takenDown","QUEUE_OPTIONS","filter","option","QUEUE_PAGE","SEARCH_SETTLE_MS","NO_MORE","queue","listed","verification","starters","FIRST_PAGES","plural","count","one","PluginReviewsQueue","basePath","data","user","setQueue","setListed","verificationRequests","setVerificationRequests","setStarters","publishers","setPublishers","loaded","setLoaded","loadError","setLoadError","search","setSearch","asked","setAsked","status","setStatus","pages","setPages","limit","Math","max","Object","values","more","setMore","refused","setRefused","notices","setNotices","timer","setTimeout","trim","clearTimeout","refresh","params","URLSearchParams","set","String","suffix","toString","response","payload","json","catch","ok","error","publisherName","profileId","pageOf","section","rows","slice","visibleQueue","visibleListed","visibleVerification","visibleStarters","total","length","filtering","refusals","fields","headers","options","pager","shown","hasMore","page","pageSize","rowCount","onPageChange","previous","row","key","listingId","name","chips","caption","spacing","sx","py","borderBottom","borderColor","useFlexGap","direction","alignItems","flexWrap","href","encodeURIComponent","variant","component","color","topic","anchor","size","placeholder","onChange","event","target","minWidth","select","map","severity","height","header","help","contentGutterX","contentGutterY","display","mb","entry","displayName","version","private","license","priceUsd","meaning","reviewedVersion","official","hidden","submittedAt","Date","toLocaleDateString","Boolean","join","latestVersion","realmVersions","versionCount","hiddenReason"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;;AAEA,SAASA,cAAc,QAAQ,eAAc;AAC7C,SAASC,OAAO,EAAEC,WAAW,QAAQ,uBAAsB;AAC3D,SAASC,cAAc,QAAQ,4DAA2D;AAC1F,OAAOC,oBACLC,iBAAiB,QACZ,+DAA8D;AAErE,SACEC,KAAK,EACLC,IAAI,EACJC,QAAQ,EACRC,QAAQ,EACRC,KAAK,EACLC,SAAS,EACTC,UAAU,QACL,gBAAe;AACtB,SAASC,WAAW,EAAEC,SAAS,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAO;AACjE,SAASC,OAAO,QAAQ,iCAAgC;AACxD,SAASC,eAAe,QAAQ,2CAA0C;AAC1E,SAASC,cAAc,QAAQ,eAAc;AAC7C,SACEC,mBAAmB,EACnBC,0BAA0B,QACrB,mCAA+B;AACtC,SACEC,kBAAkB,QAEb,4BAAwB;AAgD/B,MAAMC,iBAAiB;IACrB;QAAEC,OAAO;QAAOC,OAAO;IAAe;IACtC;QAAED,OAAO;QAAaC,OAAO;IAAY;IACzC;QAAED,OAAO;QAAaC,OAAO;IAAY;IACzC;QAAED,OAAO;QAAUC,OAAO;IAAS;IACnC;QAAED,OAAO;QAAYC,OAAO;IAAW;IACvC,0EAA0E;IAC1E,oEAAoE;IACpE;QAAED,OAAO;QAAYC,OAAO;IAAW;IACvC;QAAED,OAAO;QAAUC,OAAO;IAAa;CACxC;AAED,+CAA+C,GAC/C,MAAMC,gBAAkD;IACtDC,cAAc;IACdC,WAAW;AACb;AACA,MAAMC,gBAAgB;IACpBF,cAAcJ,eAAeO,MAAM,CACjC,CAACC,SAAWA,OAAOP,KAAK,KAAK,SAASO,OAAOP,KAAK,KAAK;AAE3D;AAEA,mCAAmC,GACnC,MAAMQ,aAAa;AACnB,2EAA2E,GAC3E,MAAMC,mBAAmB;AAEzB,MAAMC,UAA+C;IACnDC,OAAO;IACPC,QAAQ;IACRC,cAAc;IACdC,UAAU;AACZ;AACA,MAAMC,cAAkD;IACtDJ,OAAO;IACPC,QAAQ;IACRC,cAAc;IACdC,UAAU;AACZ;AAEA,MAAME,SAAS,CAACC,OAAeC,MAC7B,GAAGD,MAAM,CAAC,EAAEC,MAAMD,UAAU,IAAI,KAAK,KAAK;AAE5C;;;;;;;;;;;;;;;;;CAiBC,GACD,OAAO,SAASE,mBAAmB,EAAEC,QAAQ,EAAwB;IACnE,MAAM,EAAEC,MAAMC,IAAI,EAAE,GAAG7B;IACvB,MAAM,CAACkB,OAAOY,SAAS,GAAG/B,SAAqB,EAAE;IACjD,MAAM,CAACoB,QAAQY,UAAU,GAAGhC,SAAsB,EAAE;IACpD,MAAM,CAACiC,sBAAsBC,wBAAwB,GAAGlC,SACtD,EAAE;IAEJ,MAAM,CAACsB,UAAUa,YAAY,GAAGnC,SAAuB,EAAE;IACzD,MAAM,CAACoC,YAAYC,cAAc,GAAGrC,SAAiC,CAAC;IACtE,MAAM,CAACsC,QAAQC,UAAU,GAAGvC,SAAS;IACrC,MAAM,CAACwC,WAAWC,aAAa,GAAGzC,SAAwB;IAC1D,MAAM,CAAC0C,QAAQC,UAAU,GAAG3C,SAAS;IACrC,MAAM,CAAC4C,OAAOC,SAAS,GAAG7C,SAAS;IACnC,MAAM,CAAC8C,QAAQC,UAAU,GAAG/C,SAAS;IACrC,MAAM,CAACgD,OAAOC,SAAS,GACrBjD,SAA6CuB;IAC/C,sEAAsE,GACtE,MAAM2B,QAAQlC,aAAcmC,CAAAA,KAAKC,GAAG,IAAIC,OAAOC,MAAM,CAACN,UAAU,CAAA;IAChE,MAAM,CAACO,MAAMC,QAAQ,GAAGxD,SAA8CkB;IACtE,MAAM,CAACuC,SAASC,WAAW,GAAG1D,SAE5B,EAAE;IACJ,MAAM,CAAC2D,SAASC,WAAW,GAAG5D,SAAmB,EAAE;IAEnD,8DAA8D;IAC9DF,UAAU;QACR,MAAM+D,QAAQC,WAAW,IAAMjB,SAASH,OAAOqB,IAAI,KAAK9C;QACxD,OAAO,IAAM+C,aAAaH;IAC5B,GAAG;QAACnB;KAAO;IACX,6CAA6C;IAC7C5C,UAAU;QACRmD,SAAS1B;IACX,GAAG;QAACqB;QAAOE;KAAO;IAElB,MAAMmB,UAAUpE,YAAY;QAC1B,MAAMqE,SAAS,IAAIC;QACnB,IAAIvB,OAAOsB,OAAOE,GAAG,CAAC,KAAKxB;QAC3B,IAAIE,WAAW,OAAOoB,OAAOE,GAAG,CAAC,UAAUtB;QAC3CoB,OAAOE,GAAG,CAAC,SAASC,OAAOnB;QAC3B,MAAMoB,SAASJ,OAAOK,QAAQ;QAC9B,MAAMC,WAAW,MAAMtE,gBACrB4B,MACA,CAAC,8BAA8B,EAAEwC,SAAS,CAAC,CAAC,EAAEA,QAAQ,GAAG,IAAI;QAE/D,MAAMG,UAAU,MAAMD,SAASE,IAAI,GAAGC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;QACpD,IAAIH,SAASI,EAAE,EAAE;;YACfnC,aAAa;YACbV,iBAAS0C,2BAAAA,QAAStD,KAAK,mBAAI,EAAE;YAC7Ba,mBAAUyC,2BAAAA,QAASrD,MAAM,oBAAI,EAAE;YAC/Bc,iCAAwBuC,2BAAAA,QAASxC,oBAAoB,oBAAI,EAAE;YAC3DE,qBAAYsC,2BAAAA,QAASnD,QAAQ,oBAAI,EAAE;YACnCe,uBAAcoC,2BAAAA,QAASrC,UAAU,oBAAI,CAAC;YACtCoB,QAAQ,aAAKtC,kBAAauD,2BAAAA,QAASlB,IAAI,oBAAI,CAAC;YAC5CG,oBAAWe,2BAAAA,QAAShB,OAAO,oBAAI,EAAE;YACjCG,oBAAWa,2BAAAA,QAASd,OAAO,oBAAI,EAAE;QACnC,OAAO;;YACL,qEAAqE;YACrE,oEAAoE;YACpElB,sBACEgC,2BAAAA,QAASI,KAAK,oBAAI,CAAC,0BAA0B,EAAEL,SAAS1B,MAAM,CAAC,CAAC,CAAC;QAErE;QACAP,UAAU;IACZ,GAAG;QAACT;QAAMc;QAAOE;QAAQI;KAAM;IAE/BpD,UAAU;QACR,IAAIgC,MAAM,KAAKmC;IACjB,GAAG;QAACnC;QAAMmC;KAAQ;IAElB,MAAMa,gBAAgBjF,YACpB,CAACkF;YAAsB3C;gBAAAA,wBAAAA,UAAU,CAAC2C,UAAU,YAArB3C,wBAAyB2C;OAChD;QAAC3C;KAAW;IAGd,uEAAuE;IACvE,+DAA+D;IAC/D,MAAM4C,SAAS,CAAKC,SAA6BC,OAC/CA,KAAKC,KAAK,CAACnC,KAAK,CAACiC,QAAQ,GAAGjE,YAAY,AAACgC,CAAAA,KAAK,CAACiC,QAAQ,GAAG,CAAA,IAAKjE;IACjE,MAAMoE,eAAeJ,OAAO,SAAS7D;IACrC,MAAMkE,gBAAgBL,OAAO,UAAU5D;IACvC,MAAMkE,sBAAsBN,OAAO,gBAAgB/C;IACnD,MAAMsD,kBAAkBP,OAAO,YAAY1D;IAC3C,MAAMkE,QAA4C;QAChDrE,OAAOA,MAAMsE,MAAM;QACnBrE,QAAQA,OAAOqE,MAAM;QACrBpE,cAAcY,qBAAqBwD,MAAM;QACzCnE,UAAUA,SAASmE,MAAM;IAC3B;IACA,MAAMC,YAAY9C,MAAM6C,MAAM,GAAG,KAAK3C,WAAW;IACjD,MAAM6C,WAAW5F,QACf,IACEV,kBAAkBoE,SAAS;YACzBmC,QAAQtF,mBAAmBsF,MAAM;YACjCC,SAASnF;YACToF,SAASjF;QACX,IACF;QAAC4C;KAAQ;IAEX,MAAMsC,QAAQ,CAACd,SAA6Be;QAC1C,MAAMC,UACJT,KAAK,CAACP,QAAQ,GAAG,AAACjC,CAAAA,KAAK,CAACiC,QAAQ,GAAG,CAAA,IAAKjE,cAAcuC,IAAI,CAAC0B,QAAQ;QACrE,OAAOjC,KAAK,CAACiC,QAAQ,GAAG,KAAKgB,wBAC3B,KAAC9G;YACC+G,MAAMlD,KAAK,CAACiC,QAAQ;YACpBkB,UAAUnF;YACVoF,UAAUJ;YACVC,SAASA;YACTI,cAAc,CAACH,OACbjD,SAAS,CAACqD,WAAc,aAAKA;wBAAU,CAACrB,QAAQ,EAAEiB;;aAGpD;IACN;IAEA,MAAMK,MAAM,CACVC,KACAC,WACAC,MACA3B,WACA4B,OACAC,wBAEA,MAAClH;YAECmH,SAAS;YACTC,IAAI;gBACFC,IAAI;gBACJC,cAAc;gBACdC,aAAa;gBACb,kBAAkB;oBAAED,cAAc;gBAAE;YACtC;;8BAEA,MAACtH;oBACCwH,UAAU;oBACVC,WAAU;oBACVN,SAAS;oBACTC,IAAI;wBAAEM,YAAY;wBAAUC,UAAU;oBAAO;;sCAE7C,KAACpI;4BAAQqI,MAAM,GAAG1F,SAAS,CAAC,EAAE2F,mBAAmBd,YAAY;sCAC3D,cAAA,KAAC7G;gCAAW4H,SAAQ;gCAAYC,WAAU;0CACvCf;;;wBAGJC;;;8BAEH,KAAC/G;oBAAW4H,SAAQ;oBAAUE,OAAM;8BACjC,GAAG5C,cAAcC,WAAW,GAAG,EAAE6B,SAAS;;;WAvBxCJ;IA4BT,qBACE;;0BAME,KAACxH;gBAAe2I,OAAM;gBAAeC,QAAO;;0BASxC,MAAClI;gBAAMmH,SAAS;;kCACd,MAACnH;wBACCwH,UAAU;wBACVC,WAAU;wBACVN,SAAS;wBACTC,IAAI;4BAAEM,YAAY;4BAAUC,UAAU;wBAAO;;0CAE7C,KAAC1H;gCACCkI,MAAK;gCACLC,aAAY;gCACZtH,OAAOkC;gCACPqF,UAAU,CAACC,QAAUrF,UAAUqF,MAAMC,MAAM,CAACzH,KAAK;gCACjDsG,IAAI;oCAAEoB,UAAU;gCAAI;;0CAEtB,KAACvI;gCACCkI,MAAK;gCACLM,MAAM;gCACN3H,OAAOsC;gCACPiF,UAAU,CAACC,QAAUjF,UAAUiF,MAAMC,MAAM,CAACzH,KAAK;gCACjDsG,IAAI;oCAAEoB,UAAU;gCAAI;0CAEnB3H,eAAe6H,GAAG,CAAC,CAACrH,uBACnB,KAACvB;wCAA4BgB,OAAOO,OAAOP,KAAK;kDAC7CO,OAAON,KAAK;uCADAM,OAAOP,KAAK;;;;oBAOhCgC,0BACC,KAAClD;wBAAM+I,UAAS;kCAAS7F;yBACvB;kCACJ,KAACpD;wBAAiBqE,SAASkC;wBAAUhC,SAASA;;oBAE7C,CAACrB,uBACA,MAAC5C;wBAAMmH,SAAS;;0CACd,KAACpH;gCAAS+H,SAAQ;gCAAUc,QAAQ;;0CACpC,KAAC7I;gCAAS+H,SAAQ;gCAAUc,QAAQ;;;uCAGtC;;4BASGhD,oBAAoBG,MAAM,iBACzB,MAACvG;gCACCqJ,QAAQ,CAAC,wBAAwB,EAAE/C,MAAMnE,YAAY,GAAGkC,KAAKlC,YAAY,GAAG,MAAM,GAAG,CAAC,CAAC;gCACvFmH,MAAMrI,eAAe,mBAAmB;oCACtCyH,QAAQ;gCACV;gCACAa,cAAc;gCACdC,cAAc;;kDAEd,KAAC9I;wCACC4H,SAAQ;wCACRE,OAAM;wCACNZ,IAAI;4CAAE6B,SAAS;4CAASC,IAAI;wCAAE;kDAE7B,uDACC,wDACA;;kDAEJ,MAAClJ;;4CACE4F,oBAAoB8C,GAAG,CAAC,CAACS,QACxBtC,IACE,CAAC,OAAO,EAAEsC,MAAMpC,SAAS,EAAE,EAC3BoC,MAAMpC,SAAS,EACfoC,MAAMC,WAAW,EACjBD,MAAM9D,SAAS,gBACf;;sEACE,KAACxF;4DACCsI,MAAK;4DACLH,OAAM;4DACNjH,OAAM;;sEAER,KAAClB;4DACCsI,MAAK;4DACLH,OAAOtH,oBAAoByI,MAAMlI,YAAY,EAAE+G,KAAK;4DACpDjH,OAAOL,oBAAoByI,MAAMlI,YAAY,EAAEF,KAAK;;sEAEtD,KAAClB;4DACCsI,MAAK;4DACLL,SAAQ;4DACR/G,OAAO,CAAC,CAAC,EAAEoI,MAAME,OAAO,IAAI,KAAK;;;oDAGrC;4CAGHhD,MAAM,gBAAgBT,oBAAoBG,MAAM;;;;iCAGnD;0CACJ,MAACvG;gCACCqJ,QAAQ,CAAC,iBAAiB,EAAE/C,MAAMrE,KAAK,GAAGoC,KAAKpC,KAAK,GAAG,MAAM,GAAG,CAAC,CAAC;gCAClEqH,MAAMrI,eAAe,mBAAmB;oCACtCyH,QAAQ;gCACV;gCACAa,cAAc;gCACdC,cAAc;;kDAEd,KAAC9I;wCACC4H,SAAQ;wCACRE,OAAM;wCACNZ,IAAI;4CAAE6B,SAAS;4CAASC,IAAI;wCAAE;kDAE7B;;oCAEFxD,aAAaK,MAAM,iBAClB,MAAC/F;;4CACE0F,aAAagD,GAAG,CAAC,CAACS,QACjBtC,IACEsC,MAAMpC,SAAS,EACfoC,MAAMpC,SAAS,EACfoC,MAAMC,WAAW,EACjBD,MAAM9D,SAAS,gBACf;;sEACE,KAACxF;4DACCsI,MAAK;4DACLH,OAAOtH,oBAAoByI,MAAMlI,YAAY,EAAE+G,KAAK;4DACpDjH,OAAOL,oBAAoByI,MAAMlI,YAAY,EAAEF,KAAK;;sEAEtD,KAAClB;4DACCsI,MAAK;4DACLL,SAAQ;4DACR/G,OAAO,CAAC,CAAC,EAAEoI,MAAME,OAAO,IAAI,KAAK;;wDAMlCF,MAAMG,OAAO,iBACZ,KAACzJ;4DACCsI,MAAK;4DACLL,SAAQ;4DACR/G,OAAM;6DAEN;wDAGHoI,MAAMI,OAAO,IAAIJ,MAAMG,OAAO,GAAG,qBAChC,KAACzJ;4DACCsI,MAAK;4DACLH,OAAM;4DACNjH,OAAM;;;oDAIZoI,MAAMK,QAAQ,GAAG,IAAI,CAAC,CAAC,EAAEL,MAAMK,QAAQ,EAAE,GAAG;4CAG/CnD,MAAM,SAASX,aAAaK,MAAM;;uDAGrC,KAACnG;wCAAM+I,UAAU3C,YAAY,SAAS;kDACnCA,YACG,sCACA;;;;0CAUV,MAACxG;gCACCqJ,QAAQ,GAAGzF,WAAW,QAAQ,kCAAkC,gBAAgB,EAAE,EAAE0C,MAAMlE,QAAQ,GAAGiC,KAAKjC,QAAQ,GAAG,MAAM,GAAG,CAAC,CAAC;gCAChIkH,MAAMrI,eAAe,gBAAgB;oCACnCyH,QAAQ;gCACV;gCACAa,cAAc;gCACdC,cAAc;;kDAEd,KAAC9I;wCACC4H,SAAQ;wCACRE,OAAM;wCACNZ,IAAI;4CAAE6B,SAAS;4CAASC,IAAI;wCAAE;kDAE7B,uDACC,4DACA;;oCAEHrD,gBAAgBE,MAAM,iBACrB,MAAC/F;;4CACE6F,gBAAgB6C,GAAG,CAAC,CAACS;gDACpB,MAAMM,UAAU9I,2BAA2BwI,MAAMlI,YAAY;gDAC7D,OAAO4F,IACL,CAAC,QAAQ,EAAEsC,MAAMpC,SAAS,EAAE,EAC5BoC,MAAMpC,SAAS,EACfoC,MAAMC,WAAW,EACjBD,MAAM9D,SAAS,gBACf;;sEACE,KAACxF;4DAAKsI,MAAK;4DAAQH,OAAOyB,QAAQzB,KAAK;4DAAEjH,OAAO0I,QAAQ1I,KAAK;;sEAC7D,KAAClB;4DACCsI,MAAK;4DACLL,SAAQ;4DACR/G,OAAO,CAAC,CAAC,EAAEoI,MAAME,OAAO,IAAI,KAAK;;wDAKlCF,MAAMO,eAAe,IACtBP,MAAMO,eAAe,KAAKP,MAAME,OAAO,iBACrC,KAACxJ;4DACCsI,MAAK;4DACLH,OAAM;4DACNjH,OAAO,CAAC,CAAC,EAAEoI,MAAME,OAAO,CAAC,gBAAgB,EAAEF,MAAMO,eAAe,CAAC,CAAC,CAAC;6DAEnE;wDACHP,MAAMQ,QAAQ,iBACb,KAAC9J;4DAAKsI,MAAK;4DAAQL,SAAQ;4DAAW/G,OAAM;6DAC1C;wDACHoI,MAAMS,MAAM,iBACX,KAAC/J;4DAAKsI,MAAK;4DAAQH,OAAM;4DAAQjH,OAAM;6DACrC;;oDAEN;oDACEe,OAAOqH,MAAM7F,KAAK,EAAE;oDACpB6F,MAAMK,QAAQ,GAAG,IAAI,CAAC,CAAC,EAAEL,MAAMK,QAAQ,EAAE,GAAG;oDAC5CL,MAAMU,WAAW,GACb,CAAC,UAAU,EAAE,IAAIC,KAAKX,MAAMU,WAAW,EAAEE,kBAAkB,IAAI,GAC/D;iDACL,CACE3I,MAAM,CAAC4I,SACPC,IAAI,CAAC;4CAEZ;4CACC5D,MAAM,YAAYR,gBAAgBE,MAAM;;uDAG3C,KAACnG;wCAAM+I,UAAU3C,YAAY,SAAS;kDACnCA,YACG,wCACA;;;;0CAKV,MAACxG;gCACCqJ,QAAQ,CAAC,gBAAgB,EAAE/C,MAAMpE,MAAM,GAAGmC,KAAKnC,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC;gCACnEoH,MAAMrI,eAAe,mBAAmB;oCACtCyH,QAAQ;gCACV;gCACAa,cAAc;gCACdC,cAAc;;kDAKd,KAAC9I;wCACC4H,SAAQ;wCACRE,OAAM;wCACNZ,IAAI;4CAAE6B,SAAS;4CAASC,IAAI;wCAAE;kDAE7B,4DACC,yDACA,0DACA,gDAAgD;wCAChD,oDAAoD;wCACpD,wBAAwB;wCACxB,yDACA;;oCAEHvD,cAAcI,MAAM,iBACnB,MAAC/F;;4CACE2F,cAAc+C,GAAG,CAAC,CAACS,QAClBtC,IACEsC,MAAMpC,SAAS,EACfoC,MAAMpC,SAAS,EACfoC,MAAMC,WAAW,EACjBD,MAAM9D,SAAS,gBACf;;sEACE,KAACxF;4DACCsI,MAAK;4DACLH,OAAOtH,oBAAoByI,MAAMlI,YAAY,EAAE+G,KAAK;4DACpDjH,OAAOL,oBAAoByI,MAAMlI,YAAY,EAAEF,KAAK;;sEAEtD,KAAClB;4DACCsI,MAAK;4DACLL,SAAQ;4DACR/G,OAAO,CAAC,CAAC,EAAEoI,MAAMe,aAAa,IAAI,KAAK;;wDAExCf,MAAMG,OAAO,iBACZ,KAACzJ;4DACCsI,MAAK;4DACLL,SAAQ;4DACR/G,OAAM;6DAEN;wDACHoI,MAAMgB,aAAa,iBAClB,KAACtK;4DACCsI,MAAK;4DACLH,OAAM;4DACNjH,OAAO,GAAGoI,MAAMgB,aAAa,CAAC,cAAc,CAAC;6DAE7C;wDACHhB,MAAMS,MAAM,iBACX,KAAC/J;4DACCsI,MAAK;4DACLH,OAAM;4DACNjH,OAAM;6DAEN;;oDAEN,GAAGoI,MAAMiB,YAAY,CAAC,QAAQ,EAC5BjB,MAAMiB,YAAY,KAAK,IAAI,KAAK,MAC/BjB,MAAMS,MAAM,IAAIT,MAAMkB,YAAY,GAAG,CAAC,GAAG,EAAElB,MAAMkB,YAAY,EAAE,GAAG,IAAI;4CAG5EhE,MAAM,UAAUV,cAAcI,MAAM;;uDAGvC,KAACnG;wCAAM+I,UAAS;kDACb3C,YACG,yCACA;;;;;;;;;;AAS1B;AAEA,eAAe/D,mBAAkB"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { type ConsoleStaffPagePaths } from '@aglyn/aglyn';
|
|
18
|
+
/** One site starter, as the review route answers for its page (AGL-4049). */
|
|
19
|
+
export interface SiteStarterReviewDetail {
|
|
20
|
+
artifactType: 'siteStarter';
|
|
21
|
+
listingId: string;
|
|
22
|
+
displayName: string;
|
|
23
|
+
description: string;
|
|
24
|
+
category: string | null;
|
|
25
|
+
previewImageUrl: string | null;
|
|
26
|
+
priceUsd: number;
|
|
27
|
+
official: boolean;
|
|
28
|
+
reviewStatus: string;
|
|
29
|
+
rejectionReason: string;
|
|
30
|
+
rejectionCategory: string;
|
|
31
|
+
/** The version the last List or Reject was given on. */
|
|
32
|
+
reviewedVersion: string | null;
|
|
33
|
+
hidden: boolean;
|
|
34
|
+
hiddenReason: string;
|
|
35
|
+
unpublished: boolean;
|
|
36
|
+
latestVersion: string;
|
|
37
|
+
/** The version the pages, theme and checklist below are read from. */
|
|
38
|
+
reviewVersion: string;
|
|
39
|
+
mode: 'base' | 'ai';
|
|
40
|
+
facets: {
|
|
41
|
+
kind: string | null;
|
|
42
|
+
base: string | null;
|
|
43
|
+
fonts: string | null;
|
|
44
|
+
pages: number;
|
|
45
|
+
mode: string;
|
|
46
|
+
};
|
|
47
|
+
pages: Array<{
|
|
48
|
+
name: string;
|
|
49
|
+
slug: string | null;
|
|
50
|
+
published: boolean;
|
|
51
|
+
}>;
|
|
52
|
+
layout: {
|
|
53
|
+
name: string;
|
|
54
|
+
} | null;
|
|
55
|
+
theme: {
|
|
56
|
+
kind: 'builtin';
|
|
57
|
+
base: string;
|
|
58
|
+
fonts: string | null;
|
|
59
|
+
brand: {
|
|
60
|
+
light: Record<string, string>;
|
|
61
|
+
dark?: Record<string, string>;
|
|
62
|
+
};
|
|
63
|
+
} | {
|
|
64
|
+
kind: 'full';
|
|
65
|
+
} | null;
|
|
66
|
+
publisherId: string;
|
|
67
|
+
publisherName: string;
|
|
68
|
+
publisherSlug: string | null;
|
|
69
|
+
publisherAgreement: {
|
|
70
|
+
version: string | null;
|
|
71
|
+
required: string;
|
|
72
|
+
state: 'none' | 'outdated' | 'current';
|
|
73
|
+
};
|
|
74
|
+
sourceSite: {
|
|
75
|
+
hostId: string;
|
|
76
|
+
name: string | null;
|
|
77
|
+
subdomain: string | null;
|
|
78
|
+
cname: string | null;
|
|
79
|
+
} | null;
|
|
80
|
+
versions: Array<{
|
|
81
|
+
version: string;
|
|
82
|
+
publishedAt: string | null;
|
|
83
|
+
pages: number;
|
|
84
|
+
}>;
|
|
85
|
+
checklist: Record<string, {
|
|
86
|
+
by: string | null;
|
|
87
|
+
}>;
|
|
88
|
+
checklistOutstanding: string[];
|
|
89
|
+
}
|
|
90
|
+
export interface SiteStarterReviewBodyProps {
|
|
91
|
+
detail: SiteStarterReviewDetail;
|
|
92
|
+
busy: boolean;
|
|
93
|
+
/** Sends one action to the review route, then reads the page again. */
|
|
94
|
+
post: (payload: Record<string, unknown>, success: string) => Promise<void>;
|
|
95
|
+
/** Reads the page for another version. */
|
|
96
|
+
onSelectVersion: (version: string) => void;
|
|
97
|
+
staffPaths?: ConsoleStaffPagePaths;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* A site starter's review page (AGL-4049): what a site created from it gets,
|
|
101
|
+
* the starter checklist, and its two verdicts.
|
|
102
|
+
*
|
|
103
|
+
* A starter is not code. Nothing on the plugin page — manifest, verifier,
|
|
104
|
+
* per-version approval, realm trust — has anything to act on in it, so this
|
|
105
|
+
* page reads what a person's new site is made of instead: every page, with a
|
|
106
|
+
* link to it on the site it was published from, the layout they sit in, the
|
|
107
|
+
* theme and its brand colors in both schemes, the picture and facets a search
|
|
108
|
+
* shows. List waits for every checklist item on the newest version; Reject
|
|
109
|
+
* takes one of a starter's own reasons, which its publisher is told.
|
|
110
|
+
*/
|
|
111
|
+
export declare function SiteStarterReviewBody({ detail, busy, post, onSelectVersion, staffPaths, }: SiteStarterReviewBodyProps): import("react").JSX.Element;
|
|
112
|
+
export declare namespace SiteStarterReviewBody {
|
|
113
|
+
var displayName: string;
|
|
114
|
+
}
|
|
115
|
+
export default SiteStarterReviewBody;
|