camox 0.72.0 → 0.74.1

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 (36) hide show
  1. package/dist/features/preview/components/PageInfo.js +121 -98
  2. package/dist/features/preview/components/SelectionEditor.js +1 -1
  3. package/dist/features/routes/pageRuntime.js +15 -4
  4. package/dist/features/runtime/ClaimCard.js +192 -0
  5. package/dist/features/runtime/pageApp.js +4 -3
  6. package/dist/features/runtime/runtime.js +26 -5
  7. package/dist/features/runtime/worker.js +2 -2
  8. package/dist/features/runtime/workerRequest.d.ts +6 -0
  9. package/dist/features/runtime/workerRequest.js +13 -1
  10. package/dist/features/runtime/workerRuntime.d.ts +2 -2
  11. package/dist/features/runtime/workerRuntime.js +2 -2
  12. package/dist/features/studio/components/AgentSidebar.js +7 -7
  13. package/dist/features/studio/components/ChatWidget.js +142 -106
  14. package/dist/features/studio/components/ContentFindings.js +127 -230
  15. package/dist/features/studio/components/DeleteDraftDialog.js +112 -0
  16. package/dist/features/studio/components/DraftBar.js +98 -53
  17. package/dist/features/studio/components/DraftsControl.js +203 -190
  18. package/dist/features/studio/components/ReviewDraftDialog.js +670 -0
  19. package/dist/features/studio/components/{Patrol.js → Specialists.js} +291 -330
  20. package/dist/features/studio/components/Squareling.js +5 -5
  21. package/dist/features/studio/components/ThreadComposer.js +106 -127
  22. package/dist/features/studio/components/ThreadMessages.js +94 -69
  23. package/dist/features/studio/findingSentence.js +14 -12
  24. package/dist/features/studio/fixMessage.js +23 -0
  25. package/dist/features/studio/reportSentence.js +1 -1
  26. package/dist/features/studio/{patrollerBio.js → specialistBio.js} +8 -5
  27. package/dist/features/studio/studioStore.js +29 -15
  28. package/dist/features/studio/workingSentence.js +1 -1
  29. package/dist/lib/api-client.js +5 -1
  30. package/dist/lib/queries.js +5 -5
  31. package/dist/lib/studio-reads.d.ts +1 -1
  32. package/dist/lib/studio-reads.js +5 -5
  33. package/dist/package.js +1 -1
  34. package/dist/studio.css +1 -1
  35. package/package.json +4 -4
  36. package/dist/features/studio/components/ReviewDraftSheet.js +0 -1587
@@ -1,1587 +0,0 @@
1
- import { reads, useReadQuery } from "../../../lib/studio-reads.js";
2
- import { cn } from "../../../lib/utils.js";
3
- import { draftMutations, patrolMutations } from "../../../lib/queries.js";
4
- import { previewStore } from "../../preview/previewStore.js";
5
- import { studioStore } from "../studioStore.js";
6
- import { localeLabel } from "../localeOptions.js";
7
- import { askAgentMessage, findingSentence, fixLabel } from "../findingSentence.js";
8
- import { useShowInCanvas } from "../showInCanvas.js";
9
- import { draftLabel, plural, timeAgo } from "../draftLabel.js";
10
- import { useLeaveDraft } from "../viewSwitch.js";
11
- import { c } from "react/compiler-runtime";
12
- import * as React from "react";
13
- import { CHECKS_RUNNING_ERROR, CONFLICTS_CHANGED_ERROR, FINDINGS_OPEN_ERROR, REVISION_CHANGED_ERROR, TRANSLATIONS_PENDING_ERROR } from "@camox/api-contract/drafts";
14
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
15
- import { useMutation } from "@tanstack/react-query";
16
- import { Button } from "@camox/ui/button";
17
- import { Sheet, SheetContent, SheetDescription, SheetTitle } from "@camox/ui/sheet";
18
- import { CircleAlert, CircleCheck, OctagonX, Replace, Trash2, TriangleAlert, Unlink } from "lucide-react";
19
- import { toast } from "@camox/ui/toaster";
20
- import { Skeleton } from "@camox/ui/skeleton";
21
- import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@camox/ui/alert-dialog";
22
- import { Spinner } from "@camox/ui/spinner";
23
-
24
- //#region src/features/studio/components/ReviewDraftSheet.tsx
25
- const dateFormat = new Intl.DateTimeFormat(void 0, {
26
- month: "short",
27
- day: "numeric"
28
- });
29
- const listFormat = new Intl.ListFormat("en", {
30
- style: "long",
31
- type: "conjunction"
32
- });
33
- /** Where a subject sits: its page or layout, or the files, which belong to neither. */
34
- function ownerName(owner, entity) {
35
- if (!owner) return entity === "file" ? "Files" : "Elsewhere";
36
- if (owner.kind === "layout") return `Layout ${owner.name}`;
37
- if (owner.kind === "syncedBlock") return `Synced block ${owner.title}`;
38
- if (owner.kind === "collection") return owner.title;
39
- return owner.nickname || owner.path;
40
- }
41
- /**
42
- * Where to find a problem. One with nowhere to find it, like a definition that differs from
43
- * Live's, names only itself.
44
- */
45
- function problemPlace(problem) {
46
- if (!problem.owner && problem.entity !== "file") return null;
47
- return ownerName(problem.owner, problem.entity);
48
- }
49
- /**
50
- * Where a conflict or lost change sits: its page, layout or collection, and its locale when the
51
- * draft's change is in another than the default.
52
- */
53
- function placeInLocale(subject, defaultLocale) {
54
- const place = ownerName(subject.owner, subject.entity);
55
- if (!subject.locale || subject.locale === defaultLocale) return place;
56
- return `${place} · ${localeLabel(subject.locale)}`;
57
- }
58
- /** Where in the Canvas a blocker is, or null when it sits on no page, like a definition. */
59
- function blockerTarget(problem) {
60
- if (problem.owner?.kind !== "page") return null;
61
- return {
62
- pageId: problem.owner.id,
63
- locale: problem.locale,
64
- blockId: problem.blockId,
65
- itemId: problem.entity === "repeatableItem" ? problem.id : null,
66
- field: problem.blockId && problem.field ? {
67
- name: problem.field,
68
- kind: problem.fieldKind
69
- } : null
70
- };
71
- }
72
- const isImage = (problem) => problem.fieldKind === "Image" || problem.fieldKind === "ImageList";
73
- /** What a blocker's action does, named by the fix where it's obvious. */
74
- function blockerActionLabel(problem) {
75
- switch (problem.code) {
76
- case "emptyRequiredFile": return isImage(problem) ? "Choose an image" : "Choose a file";
77
- case "missingFile":
78
- case "unacceptedFileType": return isImage(problem) ? "Choose another image" : "Choose another file";
79
- case "emptyRequiredReference": return "Choose a record";
80
- case "danglingReference": return "Choose another record";
81
- case "duplicatePath": return "Fix the path";
82
- case "missingMetaTitle": return "Write a meta title";
83
- default: return "Show in Canvas";
84
- }
85
- }
86
- const TONES = {
87
- danger: {
88
- card: "border-destructive/30 bg-destructive/5",
89
- icon: "text-destructive"
90
- },
91
- warning: {
92
- card: "border-amber-500/30 bg-amber-500/5",
93
- icon: "text-amber-600 dark:text-amber-400"
94
- }
95
- };
96
- /** A conflict as Live's version of an entity in a locale, to tell a new one from those shown. */
97
- const conflictKey = (conflict) => JSON.stringify([
98
- conflict.entity,
99
- conflict.id,
100
- conflict.locale,
101
- conflict.liveVersion
102
- ]);
103
- const LOST_REASONS = {
104
- parentGone: "What it belongs to is gone from Live and from this draft, so publishing drops this change.",
105
- writtenAfterDeletion: "This draft deletes what it was added to, so publishing deletes it too."
106
- };
107
- /**
108
- * A card for something to know before publishing: blockers in red; removals, conflicts and lost
109
- * changes in amber.
110
- */
111
- function Card(t0) {
112
- const $ = c(22);
113
- const { tone, icon: Icon, title, action, children } = t0;
114
- const t1 = TONES[tone];
115
- let t2;
116
- if ($[0] !== t1.card) {
117
- t2 = cn("flex items-start gap-2 rounded-lg border p-3", t1.card);
118
- $[0] = t1.card;
119
- $[1] = t2;
120
- } else t2 = $[1];
121
- const t3 = TONES[tone];
122
- let t4;
123
- if ($[2] !== t3.icon) {
124
- t4 = cn("mt-0.5 size-4 shrink-0", t3.icon);
125
- $[2] = t3.icon;
126
- $[3] = t4;
127
- } else t4 = $[3];
128
- let t5;
129
- if ($[4] !== Icon || $[5] !== t4) {
130
- t5 = /* @__PURE__ */ jsx(Icon, { className: t4 });
131
- $[4] = Icon;
132
- $[5] = t4;
133
- $[6] = t5;
134
- } else t5 = $[6];
135
- let t6;
136
- if ($[7] !== title) {
137
- t6 = /* @__PURE__ */ jsx("p", {
138
- className: "text-sm font-medium",
139
- "data-card-title": true,
140
- children: title
141
- });
142
- $[7] = title;
143
- $[8] = t6;
144
- } else t6 = $[8];
145
- let t7;
146
- if ($[9] !== children) {
147
- t7 = children && /* @__PURE__ */ jsx("div", {
148
- className: "text-muted-foreground text-sm",
149
- children
150
- });
151
- $[9] = children;
152
- $[10] = t7;
153
- } else t7 = $[10];
154
- let t8;
155
- if ($[11] !== action) {
156
- t8 = action && /* @__PURE__ */ jsx("div", {
157
- className: "pt-1",
158
- children: action
159
- });
160
- $[11] = action;
161
- $[12] = t8;
162
- } else t8 = $[12];
163
- let t9;
164
- if ($[13] !== t6 || $[14] !== t7 || $[15] !== t8) {
165
- t9 = /* @__PURE__ */ jsxs("div", {
166
- className: "flex min-w-0 flex-1 flex-col gap-1",
167
- children: [
168
- t6,
169
- t7,
170
- t8
171
- ]
172
- });
173
- $[13] = t6;
174
- $[14] = t7;
175
- $[15] = t8;
176
- $[16] = t9;
177
- } else t9 = $[16];
178
- let t10;
179
- if ($[17] !== t2 || $[18] !== t5 || $[19] !== t9 || $[20] !== tone) {
180
- t10 = /* @__PURE__ */ jsxs("li", {
181
- className: t2,
182
- "data-card": tone,
183
- children: [t5, t9]
184
- });
185
- $[17] = t2;
186
- $[18] = t5;
187
- $[19] = t9;
188
- $[20] = tone;
189
- $[21] = t10;
190
- } else t10 = $[21];
191
- return t10;
192
- }
193
- /** From how many problems sharing a message they fold into one card, naming each subject. */
194
- const SHARED_MESSAGE_MIN = 3;
195
- /**
196
- * Warnings the review shows: what the draft's code removes while Live content uses it, which is
197
- * about the draft. Other warnings are about problems already on Live, and stay out (ADR 0009).
198
- */
199
- const isShownWarning = (problem) => problem.code === "removedInUse";
200
- /**
201
- * One card per problem, saying what's wrong and where. Problems sharing a message fold into one
202
- * card naming each: a removed block can sit on dozens of pages, with the same message for each. A problem on a page has an
203
- * action that shows it in the Canvas; a blocker in the draft's code, which only the agent fixes,
204
- * one that opens the draft's thread.
205
- */
206
- function ProblemCards({ problems, tone, icon, onShow, onOpenThread }) {
207
- const byMessage = /* @__PURE__ */ new Map();
208
- for (const problem of problems) byMessage.set(problem.message, [...byMessage.get(problem.message) ?? [], problem]);
209
- return [...byMessage].flatMap(([message, shared]) => {
210
- if (shared.length < SHARED_MESSAGE_MIN) return shared.map((problem) => {
211
- const place = problemPlace(problem);
212
- const target = blockerTarget(problem);
213
- return /* @__PURE__ */ jsx(Card, {
214
- tone,
215
- icon,
216
- title: problem.message,
217
- action: problem.entity === "code" ? /* @__PURE__ */ jsx(Button, {
218
- variant: "outline",
219
- size: "sm",
220
- onClick: onOpenThread,
221
- children: "Open the thread"
222
- }) : target && /* @__PURE__ */ jsx(Button, {
223
- variant: "outline",
224
- size: "sm",
225
- onClick: () => onShow(target),
226
- children: blockerActionLabel(problem)
227
- }),
228
- children: place ? `${problem.label} · ${place}` : problem.label
229
- }, `${problem.code}:${problem.id}:${problem.locale}:${problem.field}`);
230
- });
231
- return [/* @__PURE__ */ jsx(Card, {
232
- tone,
233
- icon,
234
- title: message,
235
- children: /* @__PURE__ */ jsx("ul", {
236
- className: "flex flex-wrap gap-1 pt-0.5",
237
- children: shared.map((problem) => {
238
- const place = problemPlace(problem);
239
- return /* @__PURE__ */ jsxs("li", {
240
- className: "bg-background rounded-md border px-1.5 py-0.5 text-xs",
241
- children: [/* @__PURE__ */ jsx("span", {
242
- className: "text-foreground",
243
- children: problem.label
244
- }), place && ` · ${place}`]
245
- }, `${problem.code}:${problem.id}:${problem.locale}:${problem.field}`);
246
- })
247
- })
248
- }, `shared:${message}`)];
249
- });
250
- }
251
- /** Where the Canvas shows a finding: its field, in its block or item on its page. */
252
- function findingTarget(finding) {
253
- const { place } = finding;
254
- if (place?.kind !== "page") return null;
255
- return {
256
- pageId: place.pageId,
257
- locale: finding.locale,
258
- blockId: place.blockId,
259
- itemId: place.itemId,
260
- field: place.blockId ? {
261
- name: finding.field,
262
- kind: finding.fieldKind
263
- } : null
264
- };
265
- }
266
- /**
267
- * One card per open finding of the draft, which holds its publish (ADR 0033), with the Patrol's
268
- * actions: show it in the Canvas, apply its fix, or dismiss it.
269
- */
270
- function FindingCards(t0) {
271
- const $ = c(19);
272
- const { projectId, findings, onChanged, onShow } = t0;
273
- let t1;
274
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
275
- t1 = patrolMutations.applyFix();
276
- $[0] = t1;
277
- } else t1 = $[0];
278
- let t2;
279
- if ($[1] !== onChanged) {
280
- t2 = {
281
- ...t1,
282
- onSuccess: (t3) => {
283
- const { applied } = t3;
284
- if (!applied) toast.info("The link changed since it was checked, so it's being checked again.");
285
- onChanged();
286
- },
287
- onError: _temp
288
- };
289
- $[1] = onChanged;
290
- $[2] = t2;
291
- } else t2 = $[2];
292
- const applyFix = useMutation(t2);
293
- let t3;
294
- if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
295
- t3 = patrolMutations.dismissFinding();
296
- $[3] = t3;
297
- } else t3 = $[3];
298
- let t4;
299
- if ($[4] !== onChanged) {
300
- t4 = {
301
- ...t3,
302
- onSuccess: onChanged,
303
- onError: _temp2
304
- };
305
- $[4] = onChanged;
306
- $[5] = t4;
307
- } else t4 = $[5];
308
- const dismiss = useMutation(t4);
309
- const busy = applyFix.isPending || dismiss.isPending;
310
- let t5;
311
- if ($[6] !== applyFix || $[7] !== busy || $[8] !== dismiss || $[9] !== findings || $[10] !== onShow || $[11] !== projectId) {
312
- let t6;
313
- if ($[13] !== applyFix || $[14] !== busy || $[15] !== dismiss || $[16] !== onShow || $[17] !== projectId) {
314
- t6 = (finding) => {
315
- const target = findingTarget(finding);
316
- return /* @__PURE__ */ jsx(Card, {
317
- tone: "danger",
318
- icon: CircleAlert,
319
- title: findingSentence(finding),
320
- action: /* @__PURE__ */ jsxs("span", {
321
- className: "flex flex-wrap gap-1",
322
- children: [
323
- target && /* @__PURE__ */ jsx(Button, {
324
- variant: "outline",
325
- size: "sm",
326
- onClick: () => onShow(target),
327
- children: "Show"
328
- }),
329
- finding.fix && /* @__PURE__ */ jsx(Button, {
330
- variant: "outline",
331
- size: "sm",
332
- disabled: busy,
333
- onClick: () => applyFix.mutate({
334
- projectId,
335
- findingId: finding.id
336
- }),
337
- children: fixLabel(finding.fix)
338
- }),
339
- /* @__PURE__ */ jsx(Button, {
340
- variant: "outline",
341
- size: "sm",
342
- onClick: () => studioStore.trigger.askAgent({ text: askAgentMessage(finding, finding.patroller.role) }),
343
- children: "Ask the agent"
344
- }),
345
- /* @__PURE__ */ jsx(Button, {
346
- variant: "ghost",
347
- size: "sm",
348
- disabled: busy,
349
- onClick: () => dismiss.mutate({
350
- projectId,
351
- findingId: finding.id
352
- }),
353
- children: "Dismiss"
354
- })
355
- ]
356
- })
357
- }, finding.id);
358
- };
359
- $[13] = applyFix;
360
- $[14] = busy;
361
- $[15] = dismiss;
362
- $[16] = onShow;
363
- $[17] = projectId;
364
- $[18] = t6;
365
- } else t6 = $[18];
366
- t5 = findings.map(t6);
367
- $[6] = applyFix;
368
- $[7] = busy;
369
- $[8] = dismiss;
370
- $[9] = findings;
371
- $[10] = onShow;
372
- $[11] = projectId;
373
- $[12] = t5;
374
- } else t5 = $[12];
375
- return t5;
376
- }
377
- function _temp2(error_0) {
378
- return toast.error(error_0.message || "Could not dismiss it");
379
- }
380
- function _temp(error) {
381
- return toast.error(error.message || "Could not apply the fix");
382
- }
383
- /** Who made Live's version of a conflict, as a sentence's subject: a member, a release, or none. */
384
- function whoChanged(conflict) {
385
- if (conflict.release) return "A release";
386
- return conflict.publishedBy?.name ?? null;
387
- }
388
- /** Whose edit a conflict replaces, as its card's title: a member's, a release's, or nobody's. */
389
- function conflictTitle(conflict) {
390
- if (conflict.liveVersion === null) return `Brings back the ${conflict.label}`;
391
- if (conflict.release) return `Replaces a release's change to the ${conflict.label}`;
392
- if (conflict.publishedBy) return `Replaces ${conflict.publishedBy.name}'s edit to the ${conflict.label}`;
393
- return `Replaces an edit to the ${conflict.label}`;
394
- }
395
- /** What publishing does to a conflict's entity, and when Live changed it. */
396
- function conflictDetail(conflict, draftDeletes) {
397
- const who = whoChanged(conflict);
398
- const when = conflict.publishedAt ? ` on ${dateFormat.format(conflict.publishedAt)}` : "";
399
- if (conflict.liveVersion === null) return `${who ? `${who} deleted it from Live${when}.` : `Live deleted it${when}.`} Publishing brings it back.`;
400
- const changed = who ? `${who} changed it on Live${when}.` : `Live changed it${when}.`;
401
- return draftDeletes ? `${changed} This draft deletes it, so publishing deletes it anyway.` : `${changed} Publishing replaces it with this draft's version.`;
402
- }
403
- /** Who made Live's version of a conflict and when, labelling Live's values: "On Live now · Ada, Oct 13". */
404
- function liveValuesLabel(conflict) {
405
- const made = [whoChanged(conflict), conflict.publishedAt ? dateFormat.format(conflict.publishedAt) : null].filter((part) => part !== null);
406
- return made.length > 0 ? `On Live now · ${made.join(", ")}` : "On Live now";
407
- }
408
- /**
409
- * The fields a conflict overwrites: Live's value crossed out, above the draft's, and how many
410
- * more fields differ.
411
- */
412
- function ConflictFields(t0) {
413
- const $ = c(12);
414
- const { conflict } = t0;
415
- if (conflict.fields.length === 0) return null;
416
- let t1;
417
- if ($[0] !== conflict) {
418
- t1 = liveValuesLabel(conflict);
419
- $[0] = conflict;
420
- $[1] = t1;
421
- } else t1 = $[1];
422
- const liveLabel = t1;
423
- let t2;
424
- if ($[2] !== conflict.fields || $[3] !== liveLabel) {
425
- let t3;
426
- if ($[5] !== liveLabel) {
427
- t3 = (t4) => {
428
- const { field, live, draft } = t4;
429
- return /* @__PURE__ */ jsxs("div", {
430
- className: "bg-background flex flex-col gap-1 rounded-md border p-2",
431
- "data-conflict-field": true,
432
- children: [
433
- /* @__PURE__ */ jsx("p", {
434
- className: "text-foreground text-xs font-medium",
435
- "data-field-title": true,
436
- children: field
437
- }),
438
- /* @__PURE__ */ jsxs("div", {
439
- className: "flex flex-col",
440
- children: [/* @__PURE__ */ jsx("span", {
441
- className: "text-xs",
442
- children: liveLabel
443
- }), /* @__PURE__ */ jsx("del", {
444
- className: "break-words",
445
- "data-live-value": true,
446
- children: live
447
- })]
448
- }),
449
- /* @__PURE__ */ jsxs("div", {
450
- className: "flex flex-col",
451
- children: [/* @__PURE__ */ jsx("span", {
452
- className: "text-xs",
453
- children: "This draft"
454
- }), /* @__PURE__ */ jsx("span", {
455
- className: "text-foreground break-words",
456
- "data-draft-value": true,
457
- children: draft
458
- })]
459
- })
460
- ]
461
- }, field);
462
- };
463
- $[5] = liveLabel;
464
- $[6] = t3;
465
- } else t3 = $[6];
466
- t2 = conflict.fields.map(t3);
467
- $[2] = conflict.fields;
468
- $[3] = liveLabel;
469
- $[4] = t2;
470
- } else t2 = $[4];
471
- let t3;
472
- if ($[7] !== conflict.moreFields) {
473
- t3 = conflict.moreFields > 0 && /* @__PURE__ */ jsxs("p", {
474
- className: "text-xs",
475
- children: ["And ", plural(conflict.moreFields, "more field")]
476
- });
477
- $[7] = conflict.moreFields;
478
- $[8] = t3;
479
- } else t3 = $[8];
480
- let t4;
481
- if ($[9] !== t2 || $[10] !== t3) {
482
- t4 = /* @__PURE__ */ jsxs("div", {
483
- className: "flex flex-col gap-2 pt-1",
484
- children: [t2, t3]
485
- });
486
- $[9] = t2;
487
- $[10] = t3;
488
- $[11] = t4;
489
- } else t4 = $[11];
490
- return t4;
491
- }
492
- /** Whose version of a conflict's entity Live holds, for its "Use … version instead" action. */
493
- function liveVersionName(conflict) {
494
- if (conflict.release) return "a release's";
495
- if (conflict.publishedBy) return `${conflict.publishedBy.name}'s`;
496
- return "Live's";
497
- }
498
- /**
499
- * Drops the draft's change to a conflict's entity, so the draft reads Live's version again, then
500
- * reads the review again: the conflict is gone, and the preview has a new token.
501
- */
502
- function UseLiveVersionButton(t0) {
503
- const $ = c(20);
504
- const { projectId, conflict, onUsed } = t0;
505
- let t1;
506
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
507
- t1 = draftMutations.revertToLive();
508
- $[0] = t1;
509
- } else t1 = $[0];
510
- let t2;
511
- if ($[1] !== onUsed) {
512
- t2 = (error) => {
513
- toast.error(error.message || "Could not use Live's version");
514
- onUsed();
515
- };
516
- $[1] = onUsed;
517
- $[2] = t2;
518
- } else t2 = $[2];
519
- let t3;
520
- if ($[3] !== onUsed || $[4] !== t2) {
521
- t3 = {
522
- ...t1,
523
- onSuccess: onUsed,
524
- onError: t2
525
- };
526
- $[3] = onUsed;
527
- $[4] = t2;
528
- $[5] = t3;
529
- } else t3 = $[5];
530
- const revert = useMutation(t3);
531
- const t4 = revert.isPending;
532
- let t5;
533
- if ($[6] !== conflict.entity || $[7] !== conflict.id || $[8] !== projectId || $[9] !== revert) {
534
- t5 = () => revert.mutate({
535
- projectId,
536
- entity: conflict.entity,
537
- id: conflict.id
538
- });
539
- $[6] = conflict.entity;
540
- $[7] = conflict.id;
541
- $[8] = projectId;
542
- $[9] = revert;
543
- $[10] = t5;
544
- } else t5 = $[10];
545
- let t6;
546
- if ($[11] !== revert.isPending) {
547
- t6 = revert.isPending ? /* @__PURE__ */ jsx(Spinner, {}) : null;
548
- $[11] = revert.isPending;
549
- $[12] = t6;
550
- } else t6 = $[12];
551
- let t7;
552
- if ($[13] !== conflict) {
553
- t7 = liveVersionName(conflict);
554
- $[13] = conflict;
555
- $[14] = t7;
556
- } else t7 = $[14];
557
- let t8;
558
- if ($[15] !== revert.isPending || $[16] !== t5 || $[17] !== t6 || $[18] !== t7) {
559
- t8 = /* @__PURE__ */ jsxs(Button, {
560
- variant: "outline",
561
- size: "sm",
562
- className: "mt-1",
563
- disabled: t4,
564
- onClick: t5,
565
- children: [
566
- t6,
567
- "Use ",
568
- t7,
569
- " version instead"
570
- ]
571
- });
572
- $[15] = revert.isPending;
573
- $[16] = t5;
574
- $[17] = t6;
575
- $[18] = t7;
576
- $[19] = t8;
577
- } else t8 = $[19];
578
- return t8;
579
- }
580
- /**
581
- * Blockers first, then what the draft's code removes while Live content uses it, then conflicts,
582
- * then lost changes: one card each, with no section heading.
583
- */
584
- function Cards(t0) {
585
- const $ = c(39);
586
- const { projectId, preview, onChanged, onShow, onOpenThread } = t0;
587
- const { blockers, findings, conflicts, lost, changes, defaultLocale } = preview;
588
- let t1;
589
- if ($[0] !== preview.warnings) {
590
- t1 = preview.warnings.filter(isShownWarning);
591
- $[0] = preview.warnings;
592
- $[1] = t1;
593
- } else t1 = $[1];
594
- const warnings = t1;
595
- if (blockers.length + findings.length + warnings.length + conflicts.length + lost.length === 0) return null;
596
- let t2;
597
- if ($[2] !== changes) {
598
- t2 = new Set(changes.filter(_temp3).map(_temp4));
599
- $[2] = changes;
600
- $[3] = t2;
601
- } else t2 = $[3];
602
- const deleted = t2;
603
- let t3;
604
- if ($[4] !== blockers || $[5] !== onOpenThread || $[6] !== onShow) {
605
- t3 = /* @__PURE__ */ jsx(ProblemCards, {
606
- problems: blockers,
607
- tone: "danger",
608
- icon: OctagonX,
609
- onShow,
610
- onOpenThread
611
- });
612
- $[4] = blockers;
613
- $[5] = onOpenThread;
614
- $[6] = onShow;
615
- $[7] = t3;
616
- } else t3 = $[7];
617
- let t4;
618
- if ($[8] !== findings || $[9] !== onChanged || $[10] !== onShow || $[11] !== projectId) {
619
- t4 = /* @__PURE__ */ jsx(FindingCards, {
620
- projectId,
621
- findings,
622
- onChanged,
623
- onShow
624
- });
625
- $[8] = findings;
626
- $[9] = onChanged;
627
- $[10] = onShow;
628
- $[11] = projectId;
629
- $[12] = t4;
630
- } else t4 = $[12];
631
- let t5;
632
- if ($[13] !== onOpenThread || $[14] !== onShow || $[15] !== warnings) {
633
- t5 = /* @__PURE__ */ jsx(ProblemCards, {
634
- problems: warnings,
635
- tone: "warning",
636
- icon: TriangleAlert,
637
- onShow,
638
- onOpenThread
639
- });
640
- $[13] = onOpenThread;
641
- $[14] = onShow;
642
- $[15] = warnings;
643
- $[16] = t5;
644
- } else t5 = $[16];
645
- let t6;
646
- if ($[17] !== conflicts || $[18] !== defaultLocale || $[19] !== deleted || $[20] !== onChanged || $[21] !== projectId) {
647
- let t7;
648
- if ($[23] !== defaultLocale || $[24] !== deleted || $[25] !== onChanged || $[26] !== projectId) {
649
- t7 = (conflict) => /* @__PURE__ */ jsxs(Card, {
650
- tone: "warning",
651
- icon: Replace,
652
- title: conflictTitle(conflict),
653
- children: [
654
- /* @__PURE__ */ jsx("p", { children: placeInLocale(conflict, defaultLocale) }),
655
- /* @__PURE__ */ jsx("p", { children: conflictDetail(conflict, deleted.has(JSON.stringify([
656
- conflict.entity,
657
- conflict.id,
658
- conflict.locale
659
- ]))) }),
660
- /* @__PURE__ */ jsx(ConflictFields, { conflict }),
661
- conflict.revertible && /* @__PURE__ */ jsx(UseLiveVersionButton, {
662
- projectId,
663
- conflict,
664
- onUsed: onChanged
665
- })
666
- ]
667
- }, conflictKey(conflict));
668
- $[23] = defaultLocale;
669
- $[24] = deleted;
670
- $[25] = onChanged;
671
- $[26] = projectId;
672
- $[27] = t7;
673
- } else t7 = $[27];
674
- t6 = conflicts.map(t7);
675
- $[17] = conflicts;
676
- $[18] = defaultLocale;
677
- $[19] = deleted;
678
- $[20] = onChanged;
679
- $[21] = projectId;
680
- $[22] = t6;
681
- } else t6 = $[22];
682
- let t7;
683
- if ($[28] !== defaultLocale || $[29] !== lost) {
684
- let t8;
685
- if ($[31] !== defaultLocale) {
686
- t8 = (change_1) => /* @__PURE__ */ jsxs(Card, {
687
- tone: "warning",
688
- icon: Unlink,
689
- title: change_1.reason === "writtenAfterDeletion" ? change_1.label : `Loses the change to the ${change_1.label}`,
690
- children: [/* @__PURE__ */ jsx("p", { children: placeInLocale(change_1, defaultLocale) }), /* @__PURE__ */ jsx("p", { children: LOST_REASONS[change_1.reason] })]
691
- }, JSON.stringify([
692
- change_1.entity,
693
- change_1.id,
694
- change_1.locale
695
- ]));
696
- $[31] = defaultLocale;
697
- $[32] = t8;
698
- } else t8 = $[32];
699
- t7 = lost.map(t8);
700
- $[28] = defaultLocale;
701
- $[29] = lost;
702
- $[30] = t7;
703
- } else t7 = $[30];
704
- let t8;
705
- if ($[33] !== t3 || $[34] !== t4 || $[35] !== t5 || $[36] !== t6 || $[37] !== t7) {
706
- t8 = /* @__PURE__ */ jsxs("ul", {
707
- className: "flex flex-col gap-2",
708
- children: [
709
- t3,
710
- t4,
711
- t5,
712
- t6,
713
- t7
714
- ]
715
- });
716
- $[33] = t3;
717
- $[34] = t4;
718
- $[35] = t5;
719
- $[36] = t6;
720
- $[37] = t7;
721
- $[38] = t8;
722
- } else t8 = $[38];
723
- return t8;
724
- }
725
- function _temp4(change_0) {
726
- return JSON.stringify([
727
- change_0.entity,
728
- change_0.id,
729
- change_0.locale
730
- ]);
731
- }
732
- function _temp3(change) {
733
- return change.change === "deleted";
734
- }
735
- /** A quiet line saying something is done, with a check, or still running, with a spinner. */
736
- function StatusLine(t0) {
737
- const $ = c(7);
738
- const { done, children } = t0;
739
- let t1;
740
- if ($[0] !== done) {
741
- t1 = done ? /* @__PURE__ */ jsx(CircleCheck, { className: "mt-0.5 size-4 shrink-0" }) : /* @__PURE__ */ jsx(Spinner, {
742
- "aria-hidden": true,
743
- className: "mt-0.5 size-4 shrink-0"
744
- });
745
- $[0] = done;
746
- $[1] = t1;
747
- } else t1 = $[1];
748
- let t2;
749
- if ($[2] !== children) {
750
- t2 = /* @__PURE__ */ jsx("span", { children });
751
- $[2] = children;
752
- $[3] = t2;
753
- } else t2 = $[3];
754
- let t3;
755
- if ($[4] !== t1 || $[5] !== t2) {
756
- t3 = /* @__PURE__ */ jsxs("li", {
757
- className: "text-muted-foreground flex items-start gap-2 text-sm",
758
- "data-status-line": true,
759
- children: [t1, t2]
760
- });
761
- $[4] = t1;
762
- $[5] = t2;
763
- $[6] = t3;
764
- } else t3 = $[6];
765
- return t3;
766
- }
767
- /** What Publish sends: the review's token, and the revision a draft with code shows. */
768
- const publishInput = (projectId, shown) => ({
769
- projectId,
770
- token: shown.token,
771
- ...shown.code?.revision && { revision: shown.code.revision }
772
- });
773
- /** Why a publish with code went back to the review, as the review says it. */
774
- const PUBLISH_ABORTED = {
775
- revisionChanged: "The draft's code changed since this review opened, so the publish stopped. Check the preview, then publish again.",
776
- conflictsChanged: "Live changed while publishing, so the publish stopped and Live is as it was. Check the new list.",
777
- blocked: "Something now needs fixing before publishing, so the publish stopped.",
778
- codeDoesNotMerge: "Live's code changed while publishing, and it doesn't merge with this draft's yet, so the publish stopped. Camox's agent is fixing it in the draft's thread: publish again once it's done.",
779
- liveCodeMoved: "Live's code changed while publishing, and the draft took too long to take it in, so the publish stopped. Try again.",
780
- failed: "The publish couldn't finish on Camox's side, and Live is as it was. Try again."
781
- };
782
- /** The patrollers still checking the draft: "The Link checker is checking the draft." */
783
- function checkingSentence(roles) {
784
- const who = listFormat.format(roles.map((role) => `the ${role}`));
785
- return `${who[0].toUpperCase()}${who.slice(1)} ${roles.length > 1 ? "are" : "is"} checking the draft.`;
786
- }
787
- /**
788
- * What's fine or still running: the draft is up to date with Live, its latest code changes
789
- * building, its translations, its patrollers' checks, and the page SEO being written.
790
- */
791
- function StatusLines(t0) {
792
- const $ = c(36);
793
- const { preview, locales } = t0;
794
- const { conflicts, translating, checking, warnings, code } = preview;
795
- let seoPages;
796
- let t1;
797
- let t2;
798
- let t3;
799
- let t4;
800
- let t5;
801
- let t6;
802
- if ($[0] !== code || $[1] !== conflicts.length || $[2] !== locales || $[3] !== translating || $[4] !== warnings) {
803
- const translations = locales.filter(_temp5).map(_temp6);
804
- let t7;
805
- if ($[12] !== warnings) {
806
- t7 = new Set(warnings.filter(_temp7).map(_temp8));
807
- $[12] = warnings;
808
- $[13] = t7;
809
- } else t7 = $[13];
810
- seoPages = t7.size;
811
- const aborted = code?.publishAborted && !code.publishing ? code.publishAborted : null;
812
- t1 = "flex flex-col gap-1.5";
813
- if ($[14] !== aborted) {
814
- t2 = aborted && /* @__PURE__ */ jsx("li", {
815
- className: "text-sm text-amber-700 dark:text-amber-400",
816
- children: PUBLISH_ABORTED[aborted] ?? PUBLISH_ABORTED.failed
817
- });
818
- $[14] = aborted;
819
- $[15] = t2;
820
- } else t2 = $[15];
821
- if ($[16] !== code?.includesLive || $[17] !== conflicts.length) {
822
- t3 = conflicts.length === 0 && (code?.includesLive ?? true) && /* @__PURE__ */ jsx(StatusLine, {
823
- done: true,
824
- children: "Includes everything published to Live since this draft started"
825
- });
826
- $[16] = code?.includesLive;
827
- $[17] = conflicts.length;
828
- $[18] = t3;
829
- } else t3 = $[18];
830
- if ($[19] !== code?.building) {
831
- t4 = code?.building && /* @__PURE__ */ jsx(StatusLine, {
832
- done: false,
833
- children: "Building the latest changes…"
834
- });
835
- $[19] = code?.building;
836
- $[20] = t4;
837
- } else t4 = $[20];
838
- if ($[21] !== code?.publishing) {
839
- t5 = code?.publishing && /* @__PURE__ */ jsx(StatusLine, {
840
- done: false,
841
- children: "Publishing the new code and content…"
842
- });
843
- $[21] = code?.publishing;
844
- $[22] = t5;
845
- } else t5 = $[22];
846
- t6 = translating.length > 0 ? /* @__PURE__ */ jsxs(StatusLine, {
847
- done: false,
848
- children: [
849
- "Translating into ",
850
- listFormat.format(translating.map(localeLabel)),
851
- ". Publishing waits for it."
852
- ]
853
- }) : translations.length > 0 && /* @__PURE__ */ jsxs(StatusLine, {
854
- done: true,
855
- children: ["Translated into ", listFormat.format(translations.map(localeLabel))]
856
- });
857
- $[0] = code;
858
- $[1] = conflicts.length;
859
- $[2] = locales;
860
- $[3] = translating;
861
- $[4] = warnings;
862
- $[5] = seoPages;
863
- $[6] = t1;
864
- $[7] = t2;
865
- $[8] = t3;
866
- $[9] = t4;
867
- $[10] = t5;
868
- $[11] = t6;
869
- } else {
870
- seoPages = $[5];
871
- t1 = $[6];
872
- t2 = $[7];
873
- t3 = $[8];
874
- t4 = $[9];
875
- t5 = $[10];
876
- t6 = $[11];
877
- }
878
- let t7;
879
- if ($[23] !== checking) {
880
- t7 = checking.length > 0 && /* @__PURE__ */ jsxs(StatusLine, {
881
- done: false,
882
- children: [
883
- checkingSentence(checking.map(_temp9)),
884
- " Publishing waits for",
885
- " ",
886
- checking.length > 1 ? "them" : "it",
887
- "."
888
- ]
889
- });
890
- $[23] = checking;
891
- $[24] = t7;
892
- } else t7 = $[24];
893
- let t8;
894
- if ($[25] !== seoPages) {
895
- t8 = seoPages > 0 && /* @__PURE__ */ jsxs(StatusLine, {
896
- done: false,
897
- children: [
898
- "Writing SEO for ",
899
- plural(seoPages, "page"),
900
- "…"
901
- ]
902
- });
903
- $[25] = seoPages;
904
- $[26] = t8;
905
- } else t8 = $[26];
906
- let t9;
907
- if ($[27] !== t1 || $[28] !== t2 || $[29] !== t3 || $[30] !== t4 || $[31] !== t5 || $[32] !== t6 || $[33] !== t7 || $[34] !== t8) {
908
- t9 = /* @__PURE__ */ jsxs("ul", {
909
- className: t1,
910
- children: [
911
- t2,
912
- t3,
913
- t4,
914
- t5,
915
- t6,
916
- t7,
917
- t8
918
- ]
919
- });
920
- $[27] = t1;
921
- $[28] = t2;
922
- $[29] = t3;
923
- $[30] = t4;
924
- $[31] = t5;
925
- $[32] = t6;
926
- $[33] = t7;
927
- $[34] = t8;
928
- $[35] = t9;
929
- } else t9 = $[35];
930
- return t9;
931
- }
932
- function _temp9(t0) {
933
- const { role } = t0;
934
- return role;
935
- }
936
- function _temp8(warning_0) {
937
- return warning_0.id;
938
- }
939
- function _temp7(warning) {
940
- return warning.code === "metaTitlePending";
941
- }
942
- function _temp6(locale_0) {
943
- return locale_0.tag;
944
- }
945
- function _temp5(locale) {
946
- return !locale.isDefault;
947
- }
948
- /**
949
- * The draft's overview: the bullets AI wrote about its changes, in full, under the headline the
950
- * header shows, saying it's updating while they describe an older version of the draft. While
951
- * it's first written, skeleton lines; once it failed, a Retry and a plain count of the changes,
952
- * so the draft can still be reviewed. Nothing for a draft that gets no overview, as a catch-up
953
- * draft.
954
- */
955
- function DraftOverview(t0) {
956
- const $ = c(35);
957
- const { projectId, preview } = t0;
958
- const { overview, changes } = preview;
959
- let t1;
960
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
961
- t1 = {
962
- ...draftMutations.retryOverview(),
963
- onError: _temp10
964
- };
965
- $[0] = t1;
966
- } else t1 = $[0];
967
- const retry = useMutation(t1);
968
- if (changes.length === 0) {
969
- const t2 = preview.code ? "This draft changes the website's code." : "This draft has no changes.";
970
- let t3;
971
- if ($[1] !== t2) {
972
- t3 = /* @__PURE__ */ jsx("p", {
973
- className: "text-muted-foreground text-sm",
974
- children: t2
975
- });
976
- $[1] = t2;
977
- $[2] = t3;
978
- } else t3 = $[2];
979
- return t3;
980
- }
981
- if (overview.status === "ready") {
982
- let t2;
983
- if ($[3] !== overview.bullets) {
984
- t2 = overview.bullets.map(_temp11);
985
- $[3] = overview.bullets;
986
- $[4] = t2;
987
- } else t2 = $[4];
988
- let t3;
989
- if ($[5] !== t2) {
990
- t3 = /* @__PURE__ */ jsx("ul", {
991
- className: "text-foreground/85 flex list-disc flex-col gap-1.5 pl-5 leading-relaxed",
992
- children: t2
993
- });
994
- $[5] = t2;
995
- $[6] = t3;
996
- } else t3 = $[6];
997
- let t4;
998
- if ($[7] !== overview.stale) {
999
- t4 = overview.stale && /* @__PURE__ */ jsxs("p", {
1000
- className: "text-muted-foreground flex items-center gap-1.5 text-xs",
1001
- children: [/* @__PURE__ */ jsx(Spinner, {
1002
- "aria-hidden": true,
1003
- className: "size-3"
1004
- }), "Updating…"]
1005
- });
1006
- $[7] = overview.stale;
1007
- $[8] = t4;
1008
- } else t4 = $[8];
1009
- let t5;
1010
- if ($[9] !== t3 || $[10] !== t4) {
1011
- t5 = /* @__PURE__ */ jsxs("div", {
1012
- "data-overview": true,
1013
- className: "flex flex-col gap-2",
1014
- children: [t3, t4]
1015
- });
1016
- $[9] = t3;
1017
- $[10] = t4;
1018
- $[11] = t5;
1019
- } else t5 = $[11];
1020
- return t5;
1021
- }
1022
- if (overview.status === "failed") {
1023
- let t2;
1024
- if ($[12] !== changes) {
1025
- t2 = new Set(changes.map(_temp12));
1026
- $[12] = changes;
1027
- $[13] = t2;
1028
- } else t2 = $[13];
1029
- const places = t2.size;
1030
- let t3;
1031
- if ($[14] === Symbol.for("react.memo_cache_sentinel")) {
1032
- t3 = /* @__PURE__ */ jsx("p", {
1033
- className: "text-sm font-medium",
1034
- children: "Couldn't summarize this draft"
1035
- });
1036
- $[14] = t3;
1037
- } else t3 = $[14];
1038
- let t4;
1039
- if ($[15] !== projectId || $[16] !== retry) {
1040
- t4 = () => retry.mutate({ projectId });
1041
- $[15] = projectId;
1042
- $[16] = retry;
1043
- $[17] = t4;
1044
- } else t4 = $[17];
1045
- let t5;
1046
- if ($[18] !== retry.isPending) {
1047
- t5 = retry.isPending ? /* @__PURE__ */ jsx(Spinner, {}) : null;
1048
- $[18] = retry.isPending;
1049
- $[19] = t5;
1050
- } else t5 = $[19];
1051
- let t6;
1052
- if ($[20] !== retry.isPending || $[21] !== t4 || $[22] !== t5) {
1053
- t6 = /* @__PURE__ */ jsxs("div", {
1054
- className: "flex items-center gap-3",
1055
- children: [t3, /* @__PURE__ */ jsxs(Button, {
1056
- variant: "outline",
1057
- size: "sm",
1058
- className: "ml-auto",
1059
- disabled: retry.isPending,
1060
- onClick: t4,
1061
- children: [t5, "Retry"]
1062
- })]
1063
- });
1064
- $[20] = retry.isPending;
1065
- $[21] = t4;
1066
- $[22] = t5;
1067
- $[23] = t6;
1068
- } else t6 = $[23];
1069
- let t7;
1070
- if ($[24] !== changes.length) {
1071
- t7 = plural(changes.length, "change");
1072
- $[24] = changes.length;
1073
- $[25] = t7;
1074
- } else t7 = $[25];
1075
- let t8;
1076
- if ($[26] !== places) {
1077
- t8 = plural(places, "place");
1078
- $[26] = places;
1079
- $[27] = t8;
1080
- } else t8 = $[27];
1081
- let t9;
1082
- if ($[28] !== t7 || $[29] !== t8) {
1083
- t9 = /* @__PURE__ */ jsxs("p", {
1084
- className: "text-muted-foreground text-sm",
1085
- children: [
1086
- t7,
1087
- " in ",
1088
- t8
1089
- ]
1090
- });
1091
- $[28] = t7;
1092
- $[29] = t8;
1093
- $[30] = t9;
1094
- } else t9 = $[30];
1095
- let t10;
1096
- if ($[31] !== t6 || $[32] !== t9) {
1097
- t10 = /* @__PURE__ */ jsxs("div", {
1098
- "data-overview": true,
1099
- className: "flex flex-col gap-2",
1100
- children: [t6, t9]
1101
- });
1102
- $[31] = t6;
1103
- $[32] = t9;
1104
- $[33] = t10;
1105
- } else t10 = $[33];
1106
- return t10;
1107
- }
1108
- if (overview.status === "none") return null;
1109
- let t2;
1110
- if ($[34] === Symbol.for("react.memo_cache_sentinel")) {
1111
- t2 = /* @__PURE__ */ jsxs("div", {
1112
- "data-overview": true,
1113
- className: "flex flex-col gap-2",
1114
- children: [
1115
- /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-11/12" }),
1116
- /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-4/5" }),
1117
- /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-2/3" }),
1118
- /* @__PURE__ */ jsx("p", {
1119
- className: "text-muted-foreground text-sm",
1120
- children: "Summarizing this draft…"
1121
- })
1122
- ]
1123
- });
1124
- $[34] = t2;
1125
- } else t2 = $[34];
1126
- return t2;
1127
- }
1128
- function _temp12(change) {
1129
- return change.entity === "locale" ? "Languages" : ownerName(change.owner, change.entity);
1130
- }
1131
- function _temp11(bullet, index) {
1132
- return /* @__PURE__ */ jsx("li", { children: bullet }, index);
1133
- }
1134
- function _temp10(error) {
1135
- return toast.error(error.message || "Could not summarize the draft");
1136
- }
1137
- /**
1138
- * Reviews a draft before publishing it whole, or deletes it (ADR 0009). Publishing sends back
1139
- * the token of the preview shown; when Live changed since, nothing is published and the new
1140
- * preview is shown. Once the draft ends, the studio switches to Live.
1141
- */
1142
- function ReviewDraftSheet(t0) {
1143
- const $ = c(74);
1144
- const { projectId, draftId, open, onOpenChange } = t0;
1145
- const [confirmingDelete, setConfirmingDelete] = React.useState(false);
1146
- let t1;
1147
- if ($[0] !== draftId || $[1] !== projectId) {
1148
- t1 = reads.publishPreview({
1149
- projectId,
1150
- draftId
1151
- });
1152
- $[0] = draftId;
1153
- $[1] = projectId;
1154
- $[2] = t1;
1155
- } else t1 = $[2];
1156
- let t2;
1157
- if ($[3] !== open) {
1158
- t2 = { enabled: open };
1159
- $[3] = open;
1160
- $[4] = t2;
1161
- } else t2 = $[4];
1162
- const preview = useReadQuery(t1, t2);
1163
- let t3;
1164
- if ($[5] !== draftId || $[6] !== projectId) {
1165
- t3 = reads.draft({
1166
- projectId,
1167
- draftId
1168
- });
1169
- $[5] = draftId;
1170
- $[6] = projectId;
1171
- $[7] = t3;
1172
- } else t3 = $[7];
1173
- let t4;
1174
- if ($[8] !== open) {
1175
- t4 = { enabled: open };
1176
- $[8] = open;
1177
- $[9] = t4;
1178
- } else t4 = $[9];
1179
- const draft = useReadQuery(t3, t4);
1180
- let t5;
1181
- if ($[10] !== projectId) {
1182
- t5 = reads.localeList({ projectId });
1183
- $[10] = projectId;
1184
- $[11] = t5;
1185
- } else t5 = $[11];
1186
- let t6;
1187
- if ($[12] !== open) {
1188
- t6 = { enabled: open };
1189
- $[12] = open;
1190
- $[13] = t6;
1191
- } else t6 = $[13];
1192
- const locales = useReadQuery(t5, t6);
1193
- const leaveDraft = useLeaveDraft();
1194
- const showInCanvas = useShowInCanvas();
1195
- const popup = React.useRef(null);
1196
- let t7;
1197
- if ($[14] !== draft.data?.translatingLocales) {
1198
- t7 = draft.data?.translatingLocales.join(",");
1199
- $[14] = draft.data?.translatingLocales;
1200
- $[15] = t7;
1201
- } else t7 = $[15];
1202
- const pending = t7;
1203
- const seenPending = React.useRef(pending);
1204
- const { refetch } = preview;
1205
- let t8;
1206
- let t9;
1207
- if ($[16] !== pending || $[17] !== refetch) {
1208
- t8 = () => {
1209
- if (seenPending.current !== void 0 && seenPending.current !== pending) refetch();
1210
- seenPending.current = pending;
1211
- };
1212
- t9 = [pending, refetch];
1213
- $[16] = pending;
1214
- $[17] = refetch;
1215
- $[18] = t8;
1216
- $[19] = t9;
1217
- } else {
1218
- t8 = $[18];
1219
- t9 = $[19];
1220
- }
1221
- React.useEffect(t8, t9);
1222
- let t10;
1223
- if ($[20] !== leaveDraft || $[21] !== onOpenChange) {
1224
- t10 = (ended) => {
1225
- onOpenChange(false);
1226
- leaveDraft(ended);
1227
- };
1228
- $[20] = leaveDraft;
1229
- $[21] = onOpenChange;
1230
- $[22] = t10;
1231
- } else t10 = $[22];
1232
- const leave = t10;
1233
- let t11;
1234
- if ($[23] === Symbol.for("react.memo_cache_sentinel")) {
1235
- t11 = draftMutations.publish();
1236
- $[23] = t11;
1237
- } else t11 = $[23];
1238
- let t12;
1239
- if ($[24] !== leave || $[25] !== preview) {
1240
- t12 = (result) => {
1241
- if ("publishing" in result && result.publishing) {
1242
- preview.refetch();
1243
- return;
1244
- }
1245
- const { empty, ended: ended_0 } = result;
1246
- if (!empty) return leave(ended_0);
1247
- toast.info("This draft has no changes, so there is nothing to publish.");
1248
- preview.refetch();
1249
- };
1250
- $[24] = leave;
1251
- $[25] = preview;
1252
- $[26] = t12;
1253
- } else t12 = $[26];
1254
- let t13;
1255
- if ($[27] !== preview) {
1256
- t13 = (error) => {
1257
- if (error.code === CONFLICTS_CHANGED_ERROR) {
1258
- toast.error("Live changed since you opened this review. Check the new list.");
1259
- preview.refetch();
1260
- return;
1261
- }
1262
- if (error.code === REVISION_CHANGED_ERROR) {
1263
- toast.error(error.message || "The draft changed since you opened this review.");
1264
- preview.refetch();
1265
- return;
1266
- }
1267
- if (error.code === TRANSLATIONS_PENDING_ERROR) {
1268
- toast.info("Translations are still running. Publishing waits for them.");
1269
- preview.refetch();
1270
- return;
1271
- }
1272
- const code = error.code;
1273
- if (code === FINDINGS_OPEN_ERROR || code === CHECKS_RUNNING_ERROR) {
1274
- toast.info(error.message);
1275
- preview.refetch();
1276
- return;
1277
- }
1278
- toast.error(error.message || "Could not publish the draft");
1279
- preview.refetch();
1280
- };
1281
- $[27] = preview;
1282
- $[28] = t13;
1283
- } else t13 = $[28];
1284
- let t14;
1285
- if ($[29] !== t12 || $[30] !== t13) {
1286
- t14 = {
1287
- ...t11,
1288
- onSuccess: t12,
1289
- onError: t13
1290
- };
1291
- $[29] = t12;
1292
- $[30] = t13;
1293
- $[31] = t14;
1294
- } else t14 = $[31];
1295
- const publish = useMutation(t14);
1296
- const data = preview.data;
1297
- const headline = data?.overview.status === "ready" ? data.overview.headline : null;
1298
- const busy = publish.isPending;
1299
- const ready = !!data && data.blockers.length === 0 && data.translating.length === 0 && data.findings.length === 0 && data.checking.length === 0 && !data.code?.building && !data.code?.publishing && !busy && !preview.isFetching;
1300
- let t15;
1301
- if ($[32] !== draft.data || $[33] !== headline) {
1302
- t15 = /* @__PURE__ */ jsx("div", {
1303
- className: "flex flex-col gap-1 border-b p-4 pr-12",
1304
- children: headline ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SheetDescription, {
1305
- className: "flex min-w-0 items-center gap-1",
1306
- children: draft.data && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
1307
- className: "truncate",
1308
- children: draftLabel(draft.data)
1309
- }), /* @__PURE__ */ jsxs("span", {
1310
- className: "shrink-0",
1311
- children: [
1312
- "· ",
1313
- draft.data.createdBy.name,
1314
- ", started ",
1315
- timeAgo(draft.data.createdAt)
1316
- ]
1317
- })] })
1318
- }), /* @__PURE__ */ jsx(SheetTitle, {
1319
- className: "text-lg leading-snug font-semibold",
1320
- children: headline
1321
- })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SheetTitle, {
1322
- className: "truncate text-base",
1323
- children: draft.data ? draftLabel(draft.data) : "Draft"
1324
- }), /* @__PURE__ */ jsx(SheetDescription, { children: draft.data ? `${draft.data.createdBy.name} · started ${timeAgo(draft.data.createdAt)}` : "Publishing applies this whole draft to Live." })] })
1325
- });
1326
- $[32] = draft.data;
1327
- $[33] = headline;
1328
- $[34] = t15;
1329
- } else t15 = $[34];
1330
- let t16;
1331
- if ($[35] !== data || $[36] !== locales || $[37] !== onOpenChange || $[38] !== preview || $[39] !== projectId || $[40] !== showInCanvas) {
1332
- t16 = data ? /* @__PURE__ */ jsxs("div", {
1333
- className: "flex min-h-0 flex-1 flex-col gap-6 overflow-y-auto p-4",
1334
- children: [
1335
- /* @__PURE__ */ jsx(DraftOverview, {
1336
- projectId,
1337
- preview: data
1338
- }),
1339
- /* @__PURE__ */ jsx(Cards, {
1340
- projectId,
1341
- preview: data,
1342
- onChanged: () => void preview.refetch(),
1343
- onShow: (target) => {
1344
- onOpenChange(false);
1345
- showInCanvas(target);
1346
- },
1347
- onOpenThread: () => {
1348
- onOpenChange(false);
1349
- previewStore.send({ type: "showCanvas" });
1350
- }
1351
- }),
1352
- /* @__PURE__ */ jsx(StatusLines, {
1353
- preview: data,
1354
- locales: locales.data ?? []
1355
- })
1356
- ]
1357
- }) : /* @__PURE__ */ jsx("div", {
1358
- className: "flex flex-1 items-center justify-center",
1359
- children: /* @__PURE__ */ jsx(Spinner, { className: "text-muted-foreground" })
1360
- });
1361
- $[35] = data;
1362
- $[36] = locales;
1363
- $[37] = onOpenChange;
1364
- $[38] = preview;
1365
- $[39] = projectId;
1366
- $[40] = showInCanvas;
1367
- $[41] = t16;
1368
- } else t16 = $[41];
1369
- let t17;
1370
- let t18;
1371
- if ($[42] === Symbol.for("react.memo_cache_sentinel")) {
1372
- t17 = () => setConfirmingDelete(true);
1373
- t18 = /* @__PURE__ */ jsx(Trash2, {});
1374
- $[42] = t17;
1375
- $[43] = t18;
1376
- } else {
1377
- t17 = $[42];
1378
- t18 = $[43];
1379
- }
1380
- let t19;
1381
- if ($[44] !== busy) {
1382
- t19 = /* @__PURE__ */ jsxs(Button, {
1383
- variant: "ghost",
1384
- className: "text-destructive",
1385
- disabled: busy,
1386
- onClick: t17,
1387
- children: [t18, "Delete draft"]
1388
- });
1389
- $[44] = busy;
1390
- $[45] = t19;
1391
- } else t19 = $[45];
1392
- const t20 = !ready;
1393
- let t21;
1394
- if ($[46] !== data || $[47] !== projectId || $[48] !== publish) {
1395
- t21 = () => data && publish.mutate(publishInput(projectId, data));
1396
- $[46] = data;
1397
- $[47] = projectId;
1398
- $[48] = publish;
1399
- $[49] = t21;
1400
- } else t21 = $[49];
1401
- let t22;
1402
- if ($[50] !== publish.isPending) {
1403
- t22 = publish.isPending ? /* @__PURE__ */ jsx(Spinner, {}) : null;
1404
- $[50] = publish.isPending;
1405
- $[51] = t22;
1406
- } else t22 = $[51];
1407
- let t23;
1408
- if ($[52] !== t20 || $[53] !== t21 || $[54] !== t22) {
1409
- t23 = /* @__PURE__ */ jsxs(Button, {
1410
- className: "ml-auto",
1411
- disabled: t20,
1412
- onClick: t21,
1413
- children: [t22, "Publish"]
1414
- });
1415
- $[52] = t20;
1416
- $[53] = t21;
1417
- $[54] = t22;
1418
- $[55] = t23;
1419
- } else t23 = $[55];
1420
- let t24;
1421
- if ($[56] !== t19 || $[57] !== t23) {
1422
- t24 = /* @__PURE__ */ jsx("div", {
1423
- className: "flex flex-col gap-3 border-t p-4",
1424
- children: /* @__PURE__ */ jsxs("div", {
1425
- className: "flex items-center gap-2",
1426
- children: [t19, t23]
1427
- })
1428
- });
1429
- $[56] = t19;
1430
- $[57] = t23;
1431
- $[58] = t24;
1432
- } else t24 = $[58];
1433
- let t25;
1434
- if ($[59] !== t15 || $[60] !== t16 || $[61] !== t24) {
1435
- t25 = /* @__PURE__ */ jsxs(SheetContent, {
1436
- ref: popup,
1437
- initialFocus: popup,
1438
- side: "right",
1439
- className: "w-full gap-0 data-[side=right]:sm:max-w-lg",
1440
- children: [
1441
- t15,
1442
- t16,
1443
- t24
1444
- ]
1445
- });
1446
- $[59] = t15;
1447
- $[60] = t16;
1448
- $[61] = t24;
1449
- $[62] = t25;
1450
- } else t25 = $[62];
1451
- let t26;
1452
- if ($[63] !== onOpenChange || $[64] !== open || $[65] !== t25) {
1453
- t26 = /* @__PURE__ */ jsx(Sheet, {
1454
- open,
1455
- onOpenChange,
1456
- children: t25
1457
- });
1458
- $[63] = onOpenChange;
1459
- $[64] = open;
1460
- $[65] = t25;
1461
- $[66] = t26;
1462
- } else t26 = $[66];
1463
- let t27;
1464
- if ($[67] !== confirmingDelete || $[68] !== leave || $[69] !== projectId) {
1465
- t27 = /* @__PURE__ */ jsx(DeleteDraftDialog, {
1466
- projectId,
1467
- open: confirmingDelete,
1468
- onOpenChange: setConfirmingDelete,
1469
- onDeleted: leave
1470
- });
1471
- $[67] = confirmingDelete;
1472
- $[68] = leave;
1473
- $[69] = projectId;
1474
- $[70] = t27;
1475
- } else t27 = $[70];
1476
- let t28;
1477
- if ($[71] !== t26 || $[72] !== t27) {
1478
- t28 = /* @__PURE__ */ jsxs(Fragment, { children: [t26, t27] });
1479
- $[71] = t26;
1480
- $[72] = t27;
1481
- $[73] = t28;
1482
- } else t28 = $[73];
1483
- return t28;
1484
- }
1485
- /** Asks before deleting the draft the studio is in, then deletes it. */
1486
- function DeleteDraftDialog(t0) {
1487
- const $ = c(26);
1488
- const { projectId, open, onOpenChange, onDeleted } = t0;
1489
- let t1;
1490
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
1491
- t1 = draftMutations.delete();
1492
- $[0] = t1;
1493
- } else t1 = $[0];
1494
- let t2;
1495
- if ($[1] !== onDeleted || $[2] !== onOpenChange) {
1496
- t2 = {
1497
- ...t1,
1498
- onSuccess: (t3) => {
1499
- const { ended } = t3;
1500
- onOpenChange(false);
1501
- onDeleted(ended);
1502
- },
1503
- onError: _temp13
1504
- };
1505
- $[1] = onDeleted;
1506
- $[2] = onOpenChange;
1507
- $[3] = t2;
1508
- } else t2 = $[3];
1509
- const deleteDraft = useMutation(t2);
1510
- let t3;
1511
- if ($[4] !== deleteDraft.isPending || $[5] !== onOpenChange) {
1512
- t3 = (next) => {
1513
- if (!deleteDraft.isPending) onOpenChange(next);
1514
- };
1515
- $[4] = deleteDraft.isPending;
1516
- $[5] = onOpenChange;
1517
- $[6] = t3;
1518
- } else t3 = $[6];
1519
- let t4;
1520
- if ($[7] === Symbol.for("react.memo_cache_sentinel")) {
1521
- t4 = /* @__PURE__ */ jsxs(AlertDialogHeader, { children: [/* @__PURE__ */ jsx(AlertDialogTitle, { children: "Delete this draft?" }), /* @__PURE__ */ jsx(AlertDialogDescription, { children: "Every change in this draft is deleted for everyone. Live stays as it is. This can't be undone." })] });
1522
- $[7] = t4;
1523
- } else t4 = $[7];
1524
- let t5;
1525
- if ($[8] !== deleteDraft.isPending) {
1526
- t5 = /* @__PURE__ */ jsx(AlertDialogCancel, {
1527
- variant: "outline",
1528
- size: "default",
1529
- disabled: deleteDraft.isPending,
1530
- children: "Cancel"
1531
- });
1532
- $[8] = deleteDraft.isPending;
1533
- $[9] = t5;
1534
- } else t5 = $[9];
1535
- let t6;
1536
- if ($[10] !== deleteDraft || $[11] !== projectId) {
1537
- t6 = () => deleteDraft.mutate({ projectId });
1538
- $[10] = deleteDraft;
1539
- $[11] = projectId;
1540
- $[12] = t6;
1541
- } else t6 = $[12];
1542
- let t7;
1543
- if ($[13] !== deleteDraft.isPending) {
1544
- t7 = deleteDraft.isPending ? /* @__PURE__ */ jsx(Spinner, {}) : null;
1545
- $[13] = deleteDraft.isPending;
1546
- $[14] = t7;
1547
- } else t7 = $[14];
1548
- let t8;
1549
- if ($[15] !== deleteDraft.isPending || $[16] !== t6 || $[17] !== t7) {
1550
- t8 = /* @__PURE__ */ jsxs(AlertDialogAction, {
1551
- variant: "destructive",
1552
- disabled: deleteDraft.isPending,
1553
- onClick: t6,
1554
- children: [t7, "Delete draft"]
1555
- });
1556
- $[15] = deleteDraft.isPending;
1557
- $[16] = t6;
1558
- $[17] = t7;
1559
- $[18] = t8;
1560
- } else t8 = $[18];
1561
- let t9;
1562
- if ($[19] !== t5 || $[20] !== t8) {
1563
- t9 = /* @__PURE__ */ jsxs(AlertDialogContent, { children: [t4, /* @__PURE__ */ jsxs(AlertDialogFooter, { children: [t5, t8] })] });
1564
- $[19] = t5;
1565
- $[20] = t8;
1566
- $[21] = t9;
1567
- } else t9 = $[21];
1568
- let t10;
1569
- if ($[22] !== open || $[23] !== t3 || $[24] !== t9) {
1570
- t10 = /* @__PURE__ */ jsx(AlertDialog, {
1571
- open,
1572
- onOpenChange: t3,
1573
- children: t9
1574
- });
1575
- $[22] = open;
1576
- $[23] = t3;
1577
- $[24] = t9;
1578
- $[25] = t10;
1579
- } else t10 = $[25];
1580
- return t10;
1581
- }
1582
- function _temp13(error) {
1583
- return toast.error(error.message || "Could not delete the draft");
1584
- }
1585
-
1586
- //#endregion
1587
- export { DeleteDraftDialog, ReviewDraftSheet };