@aglyn/plugins-marketplace 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/package.json +14 -14
  2. package/src/lib/components/listing-detail-editor.component.js +26 -26
  3. package/src/lib/components/listing-detail-editor.component.js.map +1 -1
  4. package/src/lib/components/plugin-review-detail.component.js +17 -3
  5. package/src/lib/components/plugin-review-detail.component.js.map +1 -1
  6. package/src/lib/components/plugin-reviews-queue.component.js +88 -12
  7. package/src/lib/components/plugin-reviews-queue.component.js.map +1 -1
  8. package/src/lib/components/site-starter-review-detail.component.d.ts +115 -0
  9. package/src/lib/components/site-starter-review-detail.component.js +785 -0
  10. package/src/lib/components/site-starter-review-detail.component.js.map +1 -0
  11. package/src/lib/components/starter-picker-shelf.component.d.ts +7 -0
  12. package/src/lib/components/starter-picker-shelf.component.js +75 -1
  13. package/src/lib/components/starter-picker-shelf.component.js.map +1 -1
  14. package/src/lib/hooks/use-starter-answers.d.ts +41 -0
  15. package/src/lib/hooks/use-starter-answers.js +75 -0
  16. package/src/lib/hooks/use-starter-answers.js.map +1 -0
  17. package/src/lib/model/listing-query.d.ts +20 -2
  18. package/src/lib/model/listing-query.js +55 -0
  19. package/src/lib/model/listing-query.js.map +1 -1
  20. package/src/lib/model/plugin-rejection-categories.d.ts +17 -2
  21. package/src/lib/model/plugin-rejection-categories.js +48 -4
  22. package/src/lib/model/plugin-rejection-categories.js.map +1 -1
  23. package/src/lib/model/plugin-review-checklist.d.ts +38 -8
  24. package/src/lib/model/plugin-review-checklist.js +60 -11
  25. package/src/lib/model/plugin-review-checklist.js.map +1 -1
  26. package/src/lib/model/plugin-review-status.d.ts +8 -0
  27. package/src/lib/model/plugin-review-status.js +34 -0
  28. package/src/lib/model/plugin-review-status.js.map +1 -1
  29. package/src/lib/model/starter-category.d.ts +58 -0
  30. package/src/lib/model/starter-category.js +79 -0
  31. package/src/lib/model/starter-category.js.map +1 -0
  32. package/src/lib/model/starter-query.d.ts +27 -0
  33. package/src/lib/model/starter-query.js +42 -0
  34. package/src/lib/model/starter-query.js.map +1 -1
  35. package/src/lib/server/admin-reviews.js +294 -45
  36. package/src/lib/server/admin-reviews.js.map +1 -1
  37. package/src/lib/server/publish-plugin.js +46 -4
  38. package/src/lib/server/publish-plugin.js.map +1 -1
  39. package/src/lib/server/publish-starter.js +4 -0
  40. package/src/lib/server/publish-starter.js.map +1 -1
  41. package/src/lib/server/publisher-review-email.d.ts +5 -0
  42. package/src/lib/server/publisher-review-email.js +2 -1
  43. package/src/lib/server/publisher-review-email.js.map +1 -1
  44. package/src/lib/server/starters.d.ts +4 -1
  45. package/src/lib/server/starters.js +128 -28
  46. package/src/lib/server/starters.js.map +1 -1
  47. package/src/lib/server.js +12 -1
  48. package/src/lib/server.js.map +1 -1
@@ -0,0 +1,785 @@
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
+ */ 'use client';
17
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
+ import { pluginDocsHelp } from "@aglyn/aglyn";
19
+ import { buildRoute, Route } from "@aglyn/aglyn/app-utils/console-routes";
20
+ import { SITE_FONT_PAIRINGS } from "@aglyn/aglyn/app-utils/site-font-pairings";
21
+ import { siteLiveUrlForSlug } from "@aglyn/aglyn/app-utils/site-live-url";
22
+ import { SITE_STARTER_BRAND_KEYS } from "@aglyn/aglyn/app-utils/site-starter-theme";
23
+ import { siteStyleOf } from "@aglyn/aglyn/app-utils/site-styles";
24
+ import { AppLink, CardDisplay } from "@aglyn/shared-ui-jsx";
25
+ import { Alert, Box, Button, Checkbox, Chip, Divider, FormControlLabel, Link as MuiLink, MenuItem, Stack, TextField, Tooltip, Typography } from "@mui/material";
26
+ import { useState } from "react";
27
+ import { orgMarketplacePath, publisherPath } from "../model/marketplace-paths.js";
28
+ import { rejectionCategoriesFor, rejectionHeadline, rejectionInputError, pluginRejectionCategory } from "../model/plugin-rejection-categories.js";
29
+ import { SITE_STARTER_REVIEW_CHECKLIST } from "../model/plugin-review-checklist.js";
30
+ import { starterReviewStatusMeaning } from "../model/plugin-review-status.js";
31
+ const plural = (count, one)=>`${count} ${one}${count === 1 ? '' : 's'}`;
32
+ /** A font pairing as a reviewer reads it: its heading face over its text face. */ function fontsLabel(id) {
33
+ if (!id) return 'The base theme’s own fonts';
34
+ const pairing = SITE_FONT_PAIRINGS.find((entry)=>entry.id === id);
35
+ return pairing ? `${pairing.heading.family} headings, ${pairing.body.family} text` : id;
36
+ }
37
+ /** One brand color, drawn from the publisher's value with the theme's border around it. */ function Swatch({ scheme, name, value }) {
38
+ return /*#__PURE__*/ _jsxs(Stack, {
39
+ direction: "row",
40
+ spacing: 1,
41
+ sx: {
42
+ alignItems: 'center'
43
+ },
44
+ children: [
45
+ /*#__PURE__*/ _jsx(Box, {
46
+ role: "img",
47
+ "aria-label": `${scheme} ${name} ${value}`,
48
+ sx: {
49
+ width: (theme)=>theme.spacing(3),
50
+ height: (theme)=>theme.spacing(3),
51
+ borderRadius: 1,
52
+ border: 1,
53
+ borderColor: 'divider',
54
+ // The publisher's own color, as their starter stores it: data, not style.
55
+ bgcolor: value
56
+ }
57
+ }),
58
+ /*#__PURE__*/ _jsx(Typography, {
59
+ variant: "caption",
60
+ color: "text.secondary",
61
+ children: `${name} ${value}`
62
+ })
63
+ ]
64
+ });
65
+ }
66
+ /**
67
+ * A site starter's review page (AGL-4049): what a site created from it gets,
68
+ * the starter checklist, and its two verdicts.
69
+ *
70
+ * A starter is not code. Nothing on the plugin page — manifest, verifier,
71
+ * per-version approval, realm trust — has anything to act on in it, so this
72
+ * page reads what a person's new site is made of instead: every page, with a
73
+ * link to it on the site it was published from, the layout they sit in, the
74
+ * theme and its brand colors in both schemes, the picture and facets a search
75
+ * shows. List waits for every checklist item on the newest version; Reject
76
+ * takes one of a starter's own reasons, which its publisher is told.
77
+ */ export function SiteStarterReviewBody({ detail, busy, post, onSelectVersion, staffPaths }) {
78
+ var _ref, _ref1;
79
+ var _pluginRejectionCategory, _detail_layout, _detail_theme, _detail_theme1;
80
+ const [rejectCategory, setRejectCategory] = useState('');
81
+ const [reason, setReason] = useState('');
82
+ const [takedownReason, setTakedownReason] = useState('');
83
+ const status = starterReviewStatusMeaning(detail.reviewStatus);
84
+ const outstanding = detail.checklistOutstanding.length;
85
+ // List is a verdict on the newest version, so reading an older one holds it.
86
+ const readingOlder = detail.reviewVersion !== detail.latestVersion;
87
+ const blocked = outstanding > 0 || readingOlder;
88
+ const newerSinceReview = Boolean(detail.reviewedVersion) && detail.reviewedVersion !== detail.latestVersion;
89
+ const rejectBlocked = rejectionInputError(rejectCategory, reason, 'siteStarter');
90
+ const needsComment = Boolean((_pluginRejectionCategory = pluginRejectionCategory(rejectCategory)) == null ? void 0 : _pluginRejectionCategory.requiresComment);
91
+ const style = siteStyleOf(detail.facets.kind);
92
+ const site = detail.sourceSite;
93
+ const siteName = (_ref = site == null ? void 0 : site.name) != null ? _ref : 'the site it came from';
94
+ const pageUrl = (slug)=>(site == null ? void 0 : site.subdomain) || (site == null ? void 0 : site.cname) ? siteLiveUrlForSlug({
95
+ subdomain: site.subdomain,
96
+ cname: site.cname
97
+ }, slug) : undefined;
98
+ const ticked = SITE_STARTER_REVIEW_CHECKLIST.filter((item)=>{
99
+ var _detail_checklist;
100
+ return (_detail_checklist = detail.checklist) == null ? void 0 : _detail_checklist[item.id];
101
+ }).length;
102
+ const blockedReason = readingOlder ? `List reviews the newest version, v${detail.latestVersion}. Pick it under Versions.` : `Complete the review checklist first — ${plural(outstanding, 'required item')} outstanding for v${detail.reviewVersion}`;
103
+ const checklistLink = (id)=>{
104
+ if (id === 'starter-pages' && site) {
105
+ return /*#__PURE__*/ _jsx(AppLink, {
106
+ href: buildRoute(Route.ADMIN_SITE_DETAIL, {
107
+ hostId: site.hostId
108
+ }),
109
+ children: site.name ? `${site.name}’s staff page` : 'The site’s staff page'
110
+ });
111
+ }
112
+ if (id === 'publisher') {
113
+ const href = staffPaths == null ? void 0 : staffPaths.orgDetail(detail.publisherId);
114
+ return href ? /*#__PURE__*/ _jsx(AppLink, {
115
+ href: href,
116
+ children: `${detail.publisherName}’s staff page`
117
+ }) : null;
118
+ }
119
+ return null;
120
+ };
121
+ return /*#__PURE__*/ _jsxs(Stack, {
122
+ spacing: 3,
123
+ children: [
124
+ /*#__PURE__*/ _jsx(CardDisplay, {
125
+ header: "Status",
126
+ help: pluginDocsHelp('staffConsole', {
127
+ anchor: '#plugin-review-starter-status'
128
+ }),
129
+ contentGutterX: true,
130
+ contentGutterY: true,
131
+ children: /*#__PURE__*/ _jsxs(Stack, {
132
+ spacing: 1.5,
133
+ children: [
134
+ /*#__PURE__*/ _jsxs(Stack, {
135
+ useFlexGap: true,
136
+ direction: "row",
137
+ spacing: 1,
138
+ sx: {
139
+ alignItems: 'center',
140
+ flexWrap: 'wrap'
141
+ },
142
+ children: [
143
+ /*#__PURE__*/ _jsx(Chip, {
144
+ size: "small",
145
+ color: status.color,
146
+ label: status.label
147
+ }),
148
+ /*#__PURE__*/ _jsx(Chip, {
149
+ size: "small",
150
+ variant: "outlined",
151
+ label: `v${detail.latestVersion || '—'}`
152
+ }),
153
+ /*#__PURE__*/ _jsx(Chip, {
154
+ size: "small",
155
+ variant: "outlined",
156
+ label: detail.priceUsd > 0 ? `$${detail.priceUsd}` : 'Free'
157
+ }),
158
+ detail.official ? /*#__PURE__*/ _jsx(Chip, {
159
+ size: "small",
160
+ variant: "outlined",
161
+ label: "Official"
162
+ }) : null,
163
+ detail.hidden ? /*#__PURE__*/ _jsx(Chip, {
164
+ size: "small",
165
+ color: "error",
166
+ label: "Taken down"
167
+ }) : null,
168
+ detail.unpublished ? /*#__PURE__*/ _jsx(Chip, {
169
+ size: "small",
170
+ color: "warning",
171
+ label: "Unpublished by the publisher"
172
+ }) : null
173
+ ]
174
+ }),
175
+ /*#__PURE__*/ _jsx(Typography, {
176
+ variant: "caption",
177
+ color: "text.secondary",
178
+ children: status.meaning
179
+ }),
180
+ /*#__PURE__*/ _jsxs(Typography, {
181
+ variant: "body2",
182
+ color: "text.secondary",
183
+ children: [
184
+ 'Publisher: ',
185
+ detail.publisherSlug ? /*#__PURE__*/ _jsx(AppLink, {
186
+ href: publisherPath(orgMarketplacePath(detail.publisherSlug), detail.publisherId),
187
+ children: detail.publisherName
188
+ }) : detail.publisherName,
189
+ ` · ${detail.listingId}`
190
+ ]
191
+ }),
192
+ detail.publisherAgreement.state !== 'current' ? /*#__PURE__*/ _jsx(Alert, {
193
+ severity: "warning",
194
+ children: detail.publisherAgreement.state === 'none' ? 'This publisher has not accepted the Marketplace Publisher Agreement.' : `This publisher accepted an older Marketplace Publisher Agreement (${detail.publisherAgreement.version}); ${detail.publisherAgreement.required} is in force.`
195
+ }) : null,
196
+ newerSinceReview ? /*#__PURE__*/ _jsx(Alert, {
197
+ severity: "info",
198
+ children: `v${detail.latestVersion} was published after the review of v${detail.reviewedVersion}. ` + 'A listed starter stays listed when it is published again: read the new version, and reject it or take it down if it no longer passes.'
199
+ }) : null,
200
+ detail.rejectionReason || detail.rejectionCategory ? /*#__PURE__*/ _jsx(Alert, {
201
+ severity: "error",
202
+ children: `Rejected: ${rejectionHeadline(detail.rejectionCategory, detail.rejectionReason)}${detail.rejectionReason && pluginRejectionCategory(detail.rejectionCategory) ? ` — ${detail.rejectionReason}` : ''}`
203
+ }) : null,
204
+ detail.hidden ? /*#__PURE__*/ _jsx(Alert, {
205
+ severity: "error",
206
+ children: detail.hiddenReason ? `Taken down: ${detail.hiddenReason}` : 'Taken down (no reason recorded)'
207
+ }) : null
208
+ ]
209
+ })
210
+ }),
211
+ /*#__PURE__*/ _jsx(CardDisplay, {
212
+ header: "Overview",
213
+ help: pluginDocsHelp('staffConsole', {
214
+ anchor: '#plugin-review-starter-overview'
215
+ }),
216
+ contentGutterX: true,
217
+ contentGutterY: true,
218
+ children: /*#__PURE__*/ _jsxs(Stack, {
219
+ spacing: 1.5,
220
+ children: [
221
+ detail.previewImageUrl ? /*#__PURE__*/ _jsx(Box, {
222
+ component: "img",
223
+ src: detail.previewImageUrl,
224
+ alt: `The picture ${detail.displayName} is shown with`,
225
+ sx: {
226
+ width: '100%',
227
+ maxWidth: (theme)=>theme.spacing(60),
228
+ borderRadius: 1,
229
+ border: 1,
230
+ borderColor: 'divider'
231
+ }
232
+ }) : /*#__PURE__*/ _jsx(Alert, {
233
+ severity: "warning",
234
+ children: 'No picture: the starter shows without one in the marketplace.'
235
+ }),
236
+ /*#__PURE__*/ _jsx(Typography, {
237
+ variant: "body2",
238
+ children: detail.description || 'No description.'
239
+ }),
240
+ /*#__PURE__*/ _jsxs(Stack, {
241
+ useFlexGap: true,
242
+ direction: "row",
243
+ spacing: 1,
244
+ sx: {
245
+ alignItems: 'center',
246
+ flexWrap: 'wrap'
247
+ },
248
+ children: [
249
+ detail.category ? /*#__PURE__*/ _jsx(Chip, {
250
+ size: "small",
251
+ label: detail.category
252
+ }) : null,
253
+ style ? /*#__PURE__*/ _jsx(Chip, {
254
+ size: "small",
255
+ variant: "outlined",
256
+ label: `Style: ${style.name}`
257
+ }) : null,
258
+ /*#__PURE__*/ _jsx(Chip, {
259
+ size: "small",
260
+ variant: "outlined",
261
+ label: plural(detail.facets.pages, 'page')
262
+ }),
263
+ detail.mode === 'ai' ? /*#__PURE__*/ _jsx(Chip, {
264
+ size: "small",
265
+ variant: "outlined",
266
+ label: "AI starter"
267
+ }) : null
268
+ ]
269
+ })
270
+ ]
271
+ })
272
+ }),
273
+ /*#__PURE__*/ _jsx(CardDisplay, {
274
+ header: `Pages (${detail.pages.length})`,
275
+ help: pluginDocsHelp('staffConsole', {
276
+ anchor: '#plugin-review-starter-pages'
277
+ }),
278
+ contentGutterX: true,
279
+ contentGutterY: true,
280
+ children: /*#__PURE__*/ _jsxs(Stack, {
281
+ spacing: 1.5,
282
+ children: [
283
+ /*#__PURE__*/ _jsx(Typography, {
284
+ variant: "body2",
285
+ color: "text.secondary",
286
+ children: `What a site created from v${detail.reviewVersion} starts with. Each published page links to the same page on ${siteName}, as that site is now.`
287
+ }),
288
+ /*#__PURE__*/ _jsx(Stack, {
289
+ divider: /*#__PURE__*/ _jsx(Divider, {
290
+ flexItem: true
291
+ }),
292
+ spacing: 1,
293
+ children: detail.pages.map((page, index)=>{
294
+ var _page_slug;
295
+ const href = page.published && page.slug ? pageUrl(page.slug) : undefined;
296
+ return /*#__PURE__*/ _jsxs(Stack, {
297
+ useFlexGap: true,
298
+ direction: "row",
299
+ spacing: 1,
300
+ sx: {
301
+ alignItems: 'center',
302
+ flexWrap: 'wrap'
303
+ },
304
+ children: [
305
+ /*#__PURE__*/ _jsx(Typography, {
306
+ variant: "body2",
307
+ children: page.name
308
+ }),
309
+ page.published && page.slug ? /*#__PURE__*/ _jsx(Typography, {
310
+ variant: "caption",
311
+ color: "text.secondary",
312
+ children: page.slug
313
+ }) : /*#__PURE__*/ _jsx(Chip, {
314
+ size: "small",
315
+ variant: "outlined",
316
+ label: "Not published"
317
+ }),
318
+ href ? /*#__PURE__*/ _jsx(Typography, {
319
+ variant: "caption",
320
+ children: /*#__PURE__*/ _jsx(MuiLink, {
321
+ href: href,
322
+ target: "_blank",
323
+ rel: "noopener noreferrer",
324
+ children: `Open on ${siteName} ↗`
325
+ })
326
+ }) : null
327
+ ]
328
+ }, `${(_page_slug = page.slug) != null ? _page_slug : ''}-${index}`);
329
+ })
330
+ }),
331
+ /*#__PURE__*/ _jsx(Divider, {}),
332
+ /*#__PURE__*/ _jsxs(Stack, {
333
+ spacing: 0.5,
334
+ children: [
335
+ /*#__PURE__*/ _jsx(Typography, {
336
+ variant: "subtitle2",
337
+ children: 'Shared layout'
338
+ }),
339
+ /*#__PURE__*/ _jsx(Typography, {
340
+ variant: "body2",
341
+ children: (_ref1 = (_detail_layout = detail.layout) == null ? void 0 : _detail_layout.name) != null ? _ref1 : 'None'
342
+ })
343
+ ]
344
+ }),
345
+ site && !site.subdomain && !site.cname ? /*#__PURE__*/ _jsx(Alert, {
346
+ severity: "warning",
347
+ children: 'The site it was published from is gone, so its pages can only be read here.'
348
+ }) : null
349
+ ]
350
+ })
351
+ }),
352
+ /*#__PURE__*/ _jsx(CardDisplay, {
353
+ header: "Theme",
354
+ help: pluginDocsHelp('staffConsole', {
355
+ anchor: '#plugin-review-starter-theme'
356
+ }),
357
+ contentGutterX: true,
358
+ contentGutterY: true,
359
+ children: ((_detail_theme = detail.theme) == null ? void 0 : _detail_theme.kind) === 'builtin' ? /*#__PURE__*/ _jsxs(Stack, {
360
+ spacing: 1.5,
361
+ children: [
362
+ /*#__PURE__*/ _jsx(Typography, {
363
+ variant: "body2",
364
+ children: 'Built-in theme with its brand colors'
365
+ }),
366
+ /*#__PURE__*/ _jsxs(Stack, {
367
+ useFlexGap: true,
368
+ direction: "row",
369
+ spacing: 1,
370
+ sx: {
371
+ alignItems: 'center',
372
+ flexWrap: 'wrap'
373
+ },
374
+ children: [
375
+ /*#__PURE__*/ _jsx(Typography, {
376
+ variant: "caption",
377
+ color: "text.secondary",
378
+ children: 'Base theme'
379
+ }),
380
+ /*#__PURE__*/ _jsx(Chip, {
381
+ size: "small",
382
+ variant: "outlined",
383
+ label: detail.theme.base
384
+ })
385
+ ]
386
+ }),
387
+ /*#__PURE__*/ _jsx(Typography, {
388
+ variant: "body2",
389
+ color: "text.secondary",
390
+ children: fontsLabel(detail.theme.fonts)
391
+ }),
392
+ [
393
+ 'light',
394
+ 'dark'
395
+ ].map((scheme)=>{
396
+ var _ref, _ref1;
397
+ var _detail_theme;
398
+ const builtin = ((_detail_theme = detail.theme) == null ? void 0 : _detail_theme.kind) === 'builtin' ? detail.theme : null;
399
+ const colors = scheme === 'dark' ? (_ref = builtin == null ? void 0 : builtin.brand.dark) != null ? _ref : null : (_ref1 = builtin == null ? void 0 : builtin.brand.light) != null ? _ref1 : {};
400
+ const label = scheme === 'dark' ? 'Dark' : 'Light';
401
+ return /*#__PURE__*/ _jsxs(Stack, {
402
+ spacing: 0.5,
403
+ children: [
404
+ /*#__PURE__*/ _jsx(Typography, {
405
+ variant: "subtitle2",
406
+ children: label
407
+ }),
408
+ colors ? /*#__PURE__*/ _jsx(Stack, {
409
+ useFlexGap: true,
410
+ direction: "row",
411
+ spacing: 2,
412
+ sx: {
413
+ flexWrap: 'wrap'
414
+ },
415
+ children: SITE_STARTER_BRAND_KEYS.filter((key)=>colors[key]).map((key)=>/*#__PURE__*/ _jsx(Swatch, {
416
+ scheme: label,
417
+ name: key,
418
+ value: colors[key]
419
+ }, key))
420
+ }) : /*#__PURE__*/ _jsx(Typography, {
421
+ variant: "caption",
422
+ color: "text.secondary",
423
+ children: 'Uses the light colors.'
424
+ })
425
+ ]
426
+ }, scheme);
427
+ })
428
+ ]
429
+ }) : ((_detail_theme1 = detail.theme) == null ? void 0 : _detail_theme1.kind) === 'full' ? /*#__PURE__*/ _jsx(Typography, {
430
+ variant: "body2",
431
+ children: 'The site’s own full theme. Read it on the pages, in light and in dark.'
432
+ }) : /*#__PURE__*/ _jsx(Alert, {
433
+ severity: "warning",
434
+ children: 'No theme is stored with this version.'
435
+ })
436
+ }),
437
+ /*#__PURE__*/ _jsx(CardDisplay, {
438
+ header: `Review checklist — v${detail.reviewVersion} (${ticked}/${SITE_STARTER_REVIEW_CHECKLIST.length})`,
439
+ help: pluginDocsHelp('staffConsole', {
440
+ anchor: '#plugin-review-starter-checklist'
441
+ }),
442
+ contentGutterX: true,
443
+ contentGutterY: true,
444
+ children: /*#__PURE__*/ _jsxs(Stack, {
445
+ spacing: 1,
446
+ children: [
447
+ /*#__PURE__*/ _jsx(Typography, {
448
+ variant: "body2",
449
+ color: "text.secondary",
450
+ children: 'Every item is required before the starter is listed. Ticks are recorded against this version and start again when it is published again.'
451
+ }),
452
+ outstanding ? /*#__PURE__*/ _jsx(Alert, {
453
+ severity: "info",
454
+ children: `${plural(outstanding, 'required item')} outstanding — List stays blocked until they are done. Rejecting never needs the checklist.`
455
+ }) : /*#__PURE__*/ _jsx(Alert, {
456
+ severity: "success",
457
+ children: 'Every required item is recorded for this version.'
458
+ }),
459
+ SITE_STARTER_REVIEW_CHECKLIST.map((item)=>{
460
+ var _detail_checklist;
461
+ const link = checklistLink(item.id);
462
+ return /*#__PURE__*/ _jsxs(Stack, {
463
+ spacing: 0.25,
464
+ sx: {
465
+ pl: 0.5
466
+ },
467
+ children: [
468
+ /*#__PURE__*/ _jsx(FormControlLabel, {
469
+ control: /*#__PURE__*/ _jsx(Checkbox, {
470
+ size: "small",
471
+ checked: Boolean((_detail_checklist = detail.checklist) == null ? void 0 : _detail_checklist[item.id]),
472
+ disabled: busy,
473
+ onChange: (event)=>void post({
474
+ action: 'checklist',
475
+ version: detail.reviewVersion,
476
+ itemId: item.id,
477
+ checked: event.target.checked
478
+ }, event.target.checked ? 'Recorded' : 'Cleared')
479
+ }),
480
+ label: /*#__PURE__*/ _jsxs(Stack, {
481
+ useFlexGap: true,
482
+ direction: "row",
483
+ spacing: 1,
484
+ sx: {
485
+ alignItems: 'center',
486
+ flexWrap: 'wrap'
487
+ },
488
+ children: [
489
+ /*#__PURE__*/ _jsx(Typography, {
490
+ variant: "body2",
491
+ children: item.label
492
+ }),
493
+ item.required ? /*#__PURE__*/ _jsx(Chip, {
494
+ size: "small",
495
+ label: "Required"
496
+ }) : null
497
+ ]
498
+ })
499
+ }),
500
+ /*#__PURE__*/ _jsx(Typography, {
501
+ variant: "caption",
502
+ color: "text.secondary",
503
+ sx: {
504
+ pl: 4
505
+ },
506
+ children: item.detail
507
+ }),
508
+ link ? /*#__PURE__*/ _jsx(Typography, {
509
+ variant: "caption",
510
+ sx: {
511
+ pl: 4
512
+ },
513
+ children: link
514
+ }) : null
515
+ ]
516
+ }, item.id);
517
+ })
518
+ ]
519
+ })
520
+ }),
521
+ /*#__PURE__*/ _jsx(CardDisplay, {
522
+ header: "Review verdict",
523
+ help: pluginDocsHelp('staffConsole', {
524
+ anchor: '#plugin-review-starter-verdict'
525
+ }),
526
+ contentGutterX: true,
527
+ contentGutterY: true,
528
+ children: /*#__PURE__*/ _jsxs(Stack, {
529
+ spacing: 2,
530
+ children: [
531
+ /*#__PURE__*/ _jsxs(Stack, {
532
+ useFlexGap: true,
533
+ direction: "row",
534
+ spacing: 1,
535
+ sx: {
536
+ alignItems: 'center',
537
+ flexWrap: 'wrap'
538
+ },
539
+ children: [
540
+ /*#__PURE__*/ _jsx(Typography, {
541
+ variant: "body2",
542
+ children: 'Currently:'
543
+ }),
544
+ /*#__PURE__*/ _jsx(Chip, {
545
+ size: "small",
546
+ color: status.color,
547
+ label: status.label
548
+ }),
549
+ status.live ? /*#__PURE__*/ _jsx(Chip, {
550
+ size: "small",
551
+ color: "warning",
552
+ label: "Anyone can choose it"
553
+ }) : /*#__PURE__*/ _jsx(Chip, {
554
+ size: "small",
555
+ variant: "outlined",
556
+ label: "Its publisher only"
557
+ })
558
+ ]
559
+ }),
560
+ !status.live || newerSinceReview ? /*#__PURE__*/ _jsxs(Stack, {
561
+ spacing: 0.5,
562
+ children: [
563
+ /*#__PURE__*/ _jsx(Stack, {
564
+ useFlexGap: true,
565
+ direction: "row",
566
+ spacing: 1,
567
+ sx: {
568
+ alignItems: 'center',
569
+ flexWrap: 'wrap'
570
+ },
571
+ children: /*#__PURE__*/ _jsx(Tooltip, {
572
+ title: blocked ? blockedReason : 'Lists it in the marketplace, where anyone creating a site can choose it, and tells its publisher.',
573
+ children: /*#__PURE__*/ _jsx("span", {
574
+ children: /*#__PURE__*/ _jsx(Button, {
575
+ size: "small",
576
+ color: "warning",
577
+ variant: "outlined",
578
+ disabled: busy || blocked,
579
+ onClick: ()=>void post({
580
+ action: 'list'
581
+ }, 'Listed — anyone creating a site can choose it'),
582
+ children: 'List in marketplace'
583
+ })
584
+ })
585
+ })
586
+ }),
587
+ blocked ? /*#__PURE__*/ _jsx(Alert, {
588
+ severity: "info",
589
+ sx: {
590
+ mt: 0.5
591
+ },
592
+ children: readingOlder ? blockedReason : `Blocked: ${plural(outstanding, 'required checklist item')} outstanding for v${detail.reviewVersion}.`
593
+ }) : null
594
+ ]
595
+ }) : null,
596
+ /*#__PURE__*/ _jsx(Divider, {}),
597
+ /*#__PURE__*/ _jsxs(Stack, {
598
+ spacing: 0.5,
599
+ children: [
600
+ /*#__PURE__*/ _jsx(Typography, {
601
+ variant: "subtitle2",
602
+ children: 'Reject'
603
+ }),
604
+ /*#__PURE__*/ _jsxs(Stack, {
605
+ useFlexGap: true,
606
+ direction: "row",
607
+ spacing: 1,
608
+ sx: {
609
+ alignItems: 'center',
610
+ flexWrap: 'wrap'
611
+ },
612
+ children: [
613
+ /*#__PURE__*/ _jsxs(TextField, {
614
+ select: true,
615
+ size: "small",
616
+ label: "Rejection reason",
617
+ value: rejectCategory,
618
+ onChange: (event)=>setRejectCategory(event.target.value),
619
+ slotProps: {
620
+ select: {
621
+ displayEmpty: true
622
+ },
623
+ inputLabel: {
624
+ shrink: true
625
+ }
626
+ },
627
+ sx: {
628
+ minWidth: (theme)=>theme.spacing(32)
629
+ },
630
+ children: [
631
+ /*#__PURE__*/ _jsx(MenuItem, {
632
+ value: "",
633
+ children: 'Select a reason…'
634
+ }),
635
+ rejectionCategoriesFor('siteStarter').map((entry)=>/*#__PURE__*/ _jsx(MenuItem, {
636
+ value: entry.id,
637
+ children: entry.label
638
+ }, entry.id))
639
+ ]
640
+ }),
641
+ /*#__PURE__*/ _jsx(TextField, {
642
+ size: "small",
643
+ placeholder: needsComment ? 'Comment (required for “Other”)' : 'Comment (optional)',
644
+ value: reason,
645
+ onChange: (event)=>setReason(event.target.value),
646
+ sx: {
647
+ minWidth: (theme)=>theme.spacing(32)
648
+ }
649
+ }),
650
+ /*#__PURE__*/ _jsx(Button, {
651
+ size: "small",
652
+ color: "error",
653
+ disabled: busy || Boolean(rejectBlocked),
654
+ onClick: ()=>void post({
655
+ action: 'reject',
656
+ category: rejectCategory,
657
+ reason
658
+ }, 'Rejected'),
659
+ children: 'Reject'
660
+ })
661
+ ]
662
+ }),
663
+ rejectBlocked ? /*#__PURE__*/ _jsx(Typography, {
664
+ variant: "caption",
665
+ color: "text.secondary",
666
+ children: rejectBlocked
667
+ }) : null,
668
+ /*#__PURE__*/ _jsx(Typography, {
669
+ variant: "caption",
670
+ color: "text.secondary",
671
+ children: 'Rejecting tells the publisher the reason and what to do about it, and takes a listed starter out of the marketplace. Sites already created from it keep their pages. Publishing it again sends it back here.'
672
+ })
673
+ ]
674
+ })
675
+ ]
676
+ })
677
+ }),
678
+ /*#__PURE__*/ _jsx(CardDisplay, {
679
+ header: "Versions",
680
+ help: pluginDocsHelp('staffConsole', {
681
+ anchor: '#plugin-review-starter-versions'
682
+ }),
683
+ contentGutterX: true,
684
+ contentGutterY: true,
685
+ children: /*#__PURE__*/ _jsx(Stack, {
686
+ divider: /*#__PURE__*/ _jsx(Divider, {
687
+ flexItem: true
688
+ }),
689
+ spacing: 1,
690
+ children: detail.versions.map((entry)=>/*#__PURE__*/ _jsxs(Stack, {
691
+ useFlexGap: true,
692
+ direction: "row",
693
+ spacing: 1,
694
+ sx: {
695
+ alignItems: 'center',
696
+ flexWrap: 'wrap'
697
+ },
698
+ children: [
699
+ /*#__PURE__*/ _jsx(Typography, {
700
+ variant: "body2",
701
+ children: `v${entry.version}`
702
+ }),
703
+ /*#__PURE__*/ _jsx(Typography, {
704
+ variant: "caption",
705
+ color: "text.secondary",
706
+ children: [
707
+ entry.publishedAt ? `Published ${new Date(entry.publishedAt).toLocaleDateString()}` : '',
708
+ plural(entry.pages, 'page')
709
+ ].filter(Boolean).join(' · ')
710
+ }),
711
+ entry.version === detail.reviewedVersion ? /*#__PURE__*/ _jsx(Chip, {
712
+ size: "small",
713
+ variant: "outlined",
714
+ label: "Last reviewed"
715
+ }) : null,
716
+ entry.version === detail.reviewVersion ? /*#__PURE__*/ _jsx(Chip, {
717
+ size: "small",
718
+ color: "info",
719
+ label: "Shown above"
720
+ }) : /*#__PURE__*/ _jsx(Button, {
721
+ size: "small",
722
+ disabled: busy,
723
+ onClick: ()=>onSelectVersion(entry.version),
724
+ children: 'Read this version'
725
+ })
726
+ ]
727
+ }, entry.version))
728
+ })
729
+ }),
730
+ /*#__PURE__*/ _jsx(CardDisplay, {
731
+ header: "Danger zone",
732
+ help: pluginDocsHelp('staffConsole', {
733
+ anchor: '#plugin-review-starter-danger-zone'
734
+ }),
735
+ contentGutterX: true,
736
+ contentGutterY: true,
737
+ children: /*#__PURE__*/ _jsxs(Stack, {
738
+ spacing: 1.5,
739
+ children: [
740
+ /*#__PURE__*/ _jsx(Typography, {
741
+ variant: "body2",
742
+ color: "text.secondary",
743
+ children: 'Taking a starter down takes it out of the marketplace and refuses every new site from it, whatever its review status. Sites already created from it keep their own copy. Restoring returns it to the status it had.'
744
+ }),
745
+ /*#__PURE__*/ _jsxs(Stack, {
746
+ useFlexGap: true,
747
+ direction: "row",
748
+ spacing: 1,
749
+ sx: {
750
+ alignItems: 'center',
751
+ flexWrap: 'wrap'
752
+ },
753
+ children: [
754
+ detail.hidden ? null : /*#__PURE__*/ _jsx(TextField, {
755
+ size: "small",
756
+ placeholder: "Takedown reason",
757
+ value: takedownReason,
758
+ onChange: (event)=>setTakedownReason(event.target.value),
759
+ sx: {
760
+ minWidth: (theme)=>theme.spacing(32)
761
+ }
762
+ }),
763
+ /*#__PURE__*/ _jsx(Button, {
764
+ size: "small",
765
+ variant: detail.hidden ? 'text' : 'outlined',
766
+ color: detail.hidden ? 'success' : 'error',
767
+ disabled: busy || !detail.hidden && !takedownReason.trim(),
768
+ onClick: ()=>void post({
769
+ action: detail.hidden ? 'unhide' : 'hide',
770
+ reason: takedownReason
771
+ }, detail.hidden ? `${detail.displayName} restored` : `${detail.displayName} taken down`).then(()=>setTakedownReason('')),
772
+ children: detail.hidden ? 'Restore listing' : 'Take down'
773
+ })
774
+ ]
775
+ })
776
+ ]
777
+ })
778
+ })
779
+ ]
780
+ });
781
+ }
782
+ SiteStarterReviewBody.displayName = 'SiteStarterReviewBody';
783
+ export default SiteStarterReviewBody;
784
+
785
+ //# sourceMappingURL=site-starter-review-detail.component.js.map