camox 0.72.0 → 0.75.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 (38) hide show
  1. package/dist/core/lib/artifactRuntime.js +4 -2
  2. package/dist/features/preview/components/PageInfo.js +121 -98
  3. package/dist/features/preview/components/SelectionEditor.js +1 -1
  4. package/dist/features/renderer/RendererFrames.js +47 -41
  5. package/dist/features/routes/pageRuntime.js +15 -4
  6. package/dist/features/runtime/ClaimCard.js +192 -0
  7. package/dist/features/runtime/pageApp.js +4 -3
  8. package/dist/features/runtime/runtime.js +26 -5
  9. package/dist/features/runtime/worker.js +2 -2
  10. package/dist/features/runtime/workerRequest.d.ts +6 -0
  11. package/dist/features/runtime/workerRequest.js +13 -1
  12. package/dist/features/runtime/workerRuntime.d.ts +2 -2
  13. package/dist/features/runtime/workerRuntime.js +2 -2
  14. package/dist/features/studio/components/AgentSidebar.js +7 -7
  15. package/dist/features/studio/components/ChatWidget.js +142 -106
  16. package/dist/features/studio/components/ContentFindings.js +127 -230
  17. package/dist/features/studio/components/DeleteDraftDialog.js +112 -0
  18. package/dist/features/studio/components/DraftBar.js +98 -53
  19. package/dist/features/studio/components/DraftsControl.js +203 -190
  20. package/dist/features/studio/components/ReviewDraftDialog.js +670 -0
  21. package/dist/features/studio/components/{Patrol.js → Specialists.js} +291 -330
  22. package/dist/features/studio/components/Squareling.js +5 -5
  23. package/dist/features/studio/components/ThreadComposer.js +106 -127
  24. package/dist/features/studio/components/ThreadMessages.js +246 -71
  25. package/dist/features/studio/findingSentence.js +14 -12
  26. package/dist/features/studio/fixMessage.js +23 -0
  27. package/dist/features/studio/reportSentence.js +1 -1
  28. package/dist/features/studio/{patrollerBio.js → specialistBio.js} +8 -5
  29. package/dist/features/studio/studioStore.js +29 -15
  30. package/dist/features/studio/workingSentence.js +1 -1
  31. package/dist/lib/api-client.js +5 -1
  32. package/dist/lib/queries.js +5 -5
  33. package/dist/lib/studio-reads.d.ts +1 -1
  34. package/dist/lib/studio-reads.js +5 -5
  35. package/dist/package.js +1 -1
  36. package/dist/studio.css +1 -1
  37. package/package.json +4 -4
  38. package/dist/features/studio/components/ReviewDraftSheet.js +0 -1587
@@ -0,0 +1,670 @@
1
+ import { reads, useReadQuery } from "../../../lib/studio-reads.js";
2
+ import { draftMutations } from "../../../lib/queries.js";
3
+ import { studioStore } from "../studioStore.js";
4
+ import { localeName } from "../localeOptions.js";
5
+ import { fixMessage, whereSentence } from "../fixMessage.js";
6
+ import { draftLabel, plural } from "../draftLabel.js";
7
+ import { useLeaveDraft } from "../viewSwitch.js";
8
+ import { useShowInCanvas } from "../showInCanvas.js";
9
+ import { c } from "react/compiler-runtime";
10
+ import { useState } from "react";
11
+ import { PUBLISH_BLOCKED_ERROR } from "@camox/api-contract/drafts";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
13
+ import { useMutation } from "@tanstack/react-query";
14
+ import { Button } from "@camox/ui/button";
15
+ import { OctagonX } from "lucide-react";
16
+ import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@camox/ui/dialog";
17
+ import { toast } from "@camox/ui/toaster";
18
+ import { Skeleton } from "@camox/ui/skeleton";
19
+ import { Spinner } from "@camox/ui/spinner";
20
+
21
+ //#region src/features/studio/components/ReviewDraftDialog.tsx
22
+ /** Where a subject sits: its page or layout, or the files, which belong to neither. */
23
+ function ownerName(owner, entity) {
24
+ if (!owner) return entity === "file" ? "Files" : "Elsewhere";
25
+ if (owner.kind === "layout") return `Layout ${owner.name}`;
26
+ if (owner.kind === "syncedBlock") return `Synced block ${owner.title}`;
27
+ if (owner.kind === "collection") return owner.title;
28
+ return owner.nickname || owner.path;
29
+ }
30
+ /**
31
+ * Where to find a blocker. One with nowhere to find it, like the draft's code, names only
32
+ * itself.
33
+ */
34
+ function problemPlace(problem) {
35
+ if (!problem.owner && problem.entity !== "file") return null;
36
+ return ownerName(problem.owner, problem.entity);
37
+ }
38
+ /** Where in the Canvas a blocker is, or null when it sits on no page, like a definition. */
39
+ function blockerTarget(problem) {
40
+ if (problem.owner?.kind !== "page") return null;
41
+ return {
42
+ pageId: problem.owner.id,
43
+ locale: problem.locale,
44
+ blockId: problem.blockId,
45
+ itemId: problem.entity === "repeatableItem" ? problem.id : null,
46
+ field: problem.blockId && problem.field ? {
47
+ name: problem.field,
48
+ kind: problem.fieldKind
49
+ } : null
50
+ };
51
+ }
52
+ const isImage = (problem) => problem.fieldKind === "Image" || problem.fieldKind === "ImageList";
53
+ /** What a blocker's action does, named by the fix where it's obvious. */
54
+ function blockerActionLabel(problem) {
55
+ switch (problem.code) {
56
+ case "emptyRequiredFile": return isImage(problem) ? "Choose an image" : "Choose a file";
57
+ case "missingFile":
58
+ case "unacceptedFileType": return isImage(problem) ? "Choose another image" : "Choose another file";
59
+ case "emptyRequiredReference": return "Choose a record";
60
+ case "danglingReference": return "Choose another record";
61
+ case "duplicatePath": return "Fix the path";
62
+ default: return "Show in Canvas";
63
+ }
64
+ }
65
+ /** Where a blocker is, in a sentence: "Hero on Home, in German, field “image”". */
66
+ function blockerWhere(problem) {
67
+ const place = problemPlace(problem);
68
+ return whereSentence({
69
+ ...problem,
70
+ label: place ? `${problem.label} on ${place}` : problem.label
71
+ });
72
+ }
73
+ /**
74
+ * What Fix with agent sends to the draft's thread about blockers sharing a message: what's wrong
75
+ * and each place it is, for Camox's agent to fix in the draft.
76
+ */
77
+ function fixBlockersMessage(problems) {
78
+ const [first] = problems;
79
+ const places = first.entity === "code" ? [] : problems.map(blockerWhere);
80
+ return fixMessage({
81
+ from: "Publishing blocker",
82
+ what: first.message,
83
+ places
84
+ });
85
+ }
86
+ /** From how many blockers sharing a message they fold into one, naming each place. */
87
+ const SHARED_MESSAGE_MIN = 3;
88
+ const blockerKey = (problem) => `${problem.code}:${problem.id}:${problem.locale}:${problem.field}`;
89
+ /**
90
+ * One item per blocker, saying what's wrong and where, with Fix with agent, and for one on a page
91
+ * an action showing it in the Canvas. Blockers sharing a message fold into one item naming each:
92
+ * a value its definition no longer accepts can sit on dozens of pages.
93
+ */
94
+ function Blockers(t0) {
95
+ const $ = c(3);
96
+ const { blockers, onShow } = t0;
97
+ if (blockers.length === 0) return null;
98
+ let t1;
99
+ if ($[0] !== blockers || $[1] !== onShow) {
100
+ const byMessage = /* @__PURE__ */ new Map();
101
+ for (const problem of blockers) byMessage.set(problem.message, [...byMessage.get(problem.message) ?? [], problem]);
102
+ const groups = [...byMessage.values()].flatMap(_temp2);
103
+ t1 = /* @__PURE__ */ jsx("ul", {
104
+ className: "flex flex-col gap-2",
105
+ children: groups.map((group) => {
106
+ const [first] = group;
107
+ const target = group.length === 1 ? blockerTarget(first) : null;
108
+ return /* @__PURE__ */ jsxs("li", {
109
+ className: "border-destructive/30 bg-destructive/5 flex items-start gap-2 rounded-lg border p-3",
110
+ "data-blocker": true,
111
+ children: [/* @__PURE__ */ jsx(OctagonX, { className: "text-destructive mt-0.5 size-4 shrink-0" }), /* @__PURE__ */ jsxs("div", {
112
+ className: "flex min-w-0 flex-1 flex-col gap-1",
113
+ children: [
114
+ /* @__PURE__ */ jsx("p", {
115
+ className: "text-sm font-medium",
116
+ "data-blocker-message": true,
117
+ children: first.message
118
+ }),
119
+ /* @__PURE__ */ jsx(BlockerPlaces, { problems: group }),
120
+ /* @__PURE__ */ jsxs("div", {
121
+ className: "flex flex-wrap gap-2 pt-1",
122
+ children: [target && /* @__PURE__ */ jsx(Button, {
123
+ variant: "outline",
124
+ size: "sm",
125
+ onClick: () => onShow(target),
126
+ children: blockerActionLabel(first)
127
+ }), /* @__PURE__ */ jsx(Button, {
128
+ variant: "outline",
129
+ size: "sm",
130
+ onClick: () => studioStore.trigger.sendToAgent({ text: fixBlockersMessage(group) }),
131
+ children: "Fix with agent"
132
+ })]
133
+ })
134
+ ]
135
+ })]
136
+ }, blockerKey(first));
137
+ })
138
+ });
139
+ $[0] = blockers;
140
+ $[1] = onShow;
141
+ $[2] = t1;
142
+ } else t1 = $[2];
143
+ return t1;
144
+ }
145
+ function _temp2(shared) {
146
+ return shared.length < SHARED_MESSAGE_MIN ? shared.map(_temp) : [shared];
147
+ }
148
+ function _temp(problem_0) {
149
+ return [problem_0];
150
+ }
151
+ /** Where a blocker is, or each place of blockers folded into one. */
152
+ function BlockerPlaces(t0) {
153
+ const $ = c(9);
154
+ const { problems } = t0;
155
+ const label = _temp3;
156
+ if (problems.length === 1) {
157
+ let t1;
158
+ if ($[0] !== problems[0]) {
159
+ t1 = label(problems[0]);
160
+ $[0] = problems[0];
161
+ $[1] = t1;
162
+ } else t1 = $[1];
163
+ let t2;
164
+ if ($[2] !== t1) {
165
+ t2 = /* @__PURE__ */ jsx("p", {
166
+ className: "text-muted-foreground text-sm",
167
+ children: t1
168
+ });
169
+ $[2] = t1;
170
+ $[3] = t2;
171
+ } else t2 = $[3];
172
+ return t2;
173
+ }
174
+ let t1;
175
+ if ($[4] !== problems) {
176
+ let t2;
177
+ if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
178
+ t2 = (problem_0) => /* @__PURE__ */ jsx("li", {
179
+ className: "bg-background rounded-md border px-1.5 py-0.5 text-xs",
180
+ children: label(problem_0)
181
+ }, blockerKey(problem_0));
182
+ $[6] = t2;
183
+ } else t2 = $[6];
184
+ t1 = problems.map(t2);
185
+ $[4] = problems;
186
+ $[5] = t1;
187
+ } else t1 = $[5];
188
+ let t2;
189
+ if ($[7] !== t1) {
190
+ t2 = /* @__PURE__ */ jsx("ul", {
191
+ className: "text-muted-foreground flex flex-wrap gap-1 pt-0.5",
192
+ children: t1
193
+ });
194
+ $[7] = t1;
195
+ $[8] = t2;
196
+ } else t2 = $[8];
197
+ return t2;
198
+ }
199
+ function _temp3(problem) {
200
+ const place = problemPlace(problem);
201
+ return place ? `${problem.label} · ${place}` : problem.label;
202
+ }
203
+ const PUBLISH_FAILED = "The publish couldn't finish on Camox's side, and Live is as it was. Try again.";
204
+ /**
205
+ * Whether a publish request failed on Camox's side rather than being refused: a server error,
206
+ * or no answer at all. Either way the publish applied nothing.
207
+ */
208
+ const failedOnCamoxSide = (error) => {
209
+ const status = error.status;
210
+ return typeof status !== "number" || status >= 500;
211
+ };
212
+ /**
213
+ * Why the last publish with code stopped, when it isn't a blocker, which the review shows
214
+ * instead.
215
+ */
216
+ const PUBLISH_STOPPED = {
217
+ revisionChanged: "The draft's code changed while publishing, so the publish stopped and Live is as it was. Publish again.",
218
+ liveCodeMoved: "Live's code changed while publishing, and the draft took too long to take it in, so the publish stopped and Live is as it was. Try again.",
219
+ conflictsChanged: PUBLISH_FAILED,
220
+ failed: PUBLISH_FAILED
221
+ };
222
+ /**
223
+ * The review's plain lines under the blockers: each language the publish holds off Live until
224
+ * it's translated, and why the last publish stopped.
225
+ */
226
+ function reviewLines(preview) {
227
+ const { code } = preview;
228
+ const held = preview.heldLocales.map((tag) => `${localeName(tag)} goes live once it's translated`);
229
+ const stopped = code?.publishAborted && !code.publishing ? code.publishAborted : null;
230
+ return [...held, ...stopped && PUBLISH_STOPPED[stopped] ? [PUBLISH_STOPPED[stopped]] : []];
231
+ }
232
+ /** What Publish sends: the revision a draft with code shows, which publishing ships. */
233
+ const publishInput = (projectId, shown) => ({
234
+ projectId,
235
+ ...shown.code?.revision && { revision: shown.code.revision }
236
+ });
237
+ /**
238
+ * The draft's overview: the bullets AI wrote about its changes, in full, saying it's updating
239
+ * while they describe an older version of the draft. While
240
+ * it's first written, skeleton lines; once it failed, a Retry and a plain count of the changes,
241
+ * so the draft can still be reviewed. Nothing for a draft that gets no overview, as a catch-up
242
+ * draft.
243
+ */
244
+ function DraftOverview(t0) {
245
+ const $ = c(35);
246
+ const { projectId, preview } = t0;
247
+ const { overview, changes } = preview;
248
+ let t1;
249
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
250
+ t1 = {
251
+ ...draftMutations.retryOverview(),
252
+ onError: _temp4
253
+ };
254
+ $[0] = t1;
255
+ } else t1 = $[0];
256
+ const retry = useMutation(t1);
257
+ if (changes.length === 0) {
258
+ const t2 = preview.code ? "This draft changes the website's code." : "This draft has no changes.";
259
+ let t3;
260
+ if ($[1] !== t2) {
261
+ t3 = /* @__PURE__ */ jsx("p", {
262
+ className: "text-muted-foreground text-sm",
263
+ children: t2
264
+ });
265
+ $[1] = t2;
266
+ $[2] = t3;
267
+ } else t3 = $[2];
268
+ return t3;
269
+ }
270
+ if (overview.status === "ready") {
271
+ let t2;
272
+ if ($[3] !== overview.bullets) {
273
+ t2 = overview.bullets.map(_temp5);
274
+ $[3] = overview.bullets;
275
+ $[4] = t2;
276
+ } else t2 = $[4];
277
+ let t3;
278
+ if ($[5] !== t2) {
279
+ t3 = /* @__PURE__ */ jsx("ul", {
280
+ className: "text-foreground/85 flex list-disc flex-col gap-1.5 pl-5 leading-relaxed",
281
+ children: t2
282
+ });
283
+ $[5] = t2;
284
+ $[6] = t3;
285
+ } else t3 = $[6];
286
+ let t4;
287
+ if ($[7] !== overview.stale) {
288
+ t4 = overview.stale && /* @__PURE__ */ jsxs("p", {
289
+ className: "text-muted-foreground flex items-center gap-1.5 text-xs",
290
+ children: [/* @__PURE__ */ jsx(Spinner, {
291
+ "aria-hidden": true,
292
+ className: "size-3"
293
+ }), "Updating…"]
294
+ });
295
+ $[7] = overview.stale;
296
+ $[8] = t4;
297
+ } else t4 = $[8];
298
+ let t5;
299
+ if ($[9] !== t3 || $[10] !== t4) {
300
+ t5 = /* @__PURE__ */ jsxs("div", {
301
+ "data-overview": true,
302
+ className: "flex flex-col gap-2",
303
+ children: [t3, t4]
304
+ });
305
+ $[9] = t3;
306
+ $[10] = t4;
307
+ $[11] = t5;
308
+ } else t5 = $[11];
309
+ return t5;
310
+ }
311
+ if (overview.status === "failed") {
312
+ let t2;
313
+ if ($[12] !== changes) {
314
+ t2 = new Set(changes.map(_temp6));
315
+ $[12] = changes;
316
+ $[13] = t2;
317
+ } else t2 = $[13];
318
+ const places = t2.size;
319
+ let t3;
320
+ if ($[14] === Symbol.for("react.memo_cache_sentinel")) {
321
+ t3 = /* @__PURE__ */ jsx("p", {
322
+ className: "text-sm font-medium",
323
+ children: "Couldn't summarize this draft"
324
+ });
325
+ $[14] = t3;
326
+ } else t3 = $[14];
327
+ let t4;
328
+ if ($[15] !== projectId || $[16] !== retry) {
329
+ t4 = () => retry.mutate({ projectId });
330
+ $[15] = projectId;
331
+ $[16] = retry;
332
+ $[17] = t4;
333
+ } else t4 = $[17];
334
+ let t5;
335
+ if ($[18] !== retry.isPending) {
336
+ t5 = retry.isPending ? /* @__PURE__ */ jsx(Spinner, {}) : null;
337
+ $[18] = retry.isPending;
338
+ $[19] = t5;
339
+ } else t5 = $[19];
340
+ let t6;
341
+ if ($[20] !== retry.isPending || $[21] !== t4 || $[22] !== t5) {
342
+ t6 = /* @__PURE__ */ jsxs("div", {
343
+ className: "flex items-center gap-3",
344
+ children: [t3, /* @__PURE__ */ jsxs(Button, {
345
+ variant: "outline",
346
+ size: "sm",
347
+ className: "ml-auto",
348
+ disabled: retry.isPending,
349
+ onClick: t4,
350
+ children: [t5, "Retry"]
351
+ })]
352
+ });
353
+ $[20] = retry.isPending;
354
+ $[21] = t4;
355
+ $[22] = t5;
356
+ $[23] = t6;
357
+ } else t6 = $[23];
358
+ let t7;
359
+ if ($[24] !== changes.length) {
360
+ t7 = plural(changes.length, "change");
361
+ $[24] = changes.length;
362
+ $[25] = t7;
363
+ } else t7 = $[25];
364
+ let t8;
365
+ if ($[26] !== places) {
366
+ t8 = plural(places, "place");
367
+ $[26] = places;
368
+ $[27] = t8;
369
+ } else t8 = $[27];
370
+ let t9;
371
+ if ($[28] !== t7 || $[29] !== t8) {
372
+ t9 = /* @__PURE__ */ jsxs("p", {
373
+ className: "text-muted-foreground text-sm",
374
+ children: [
375
+ t7,
376
+ " in ",
377
+ t8
378
+ ]
379
+ });
380
+ $[28] = t7;
381
+ $[29] = t8;
382
+ $[30] = t9;
383
+ } else t9 = $[30];
384
+ let t10;
385
+ if ($[31] !== t6 || $[32] !== t9) {
386
+ t10 = /* @__PURE__ */ jsxs("div", {
387
+ "data-overview": true,
388
+ className: "flex flex-col gap-2",
389
+ children: [t6, t9]
390
+ });
391
+ $[31] = t6;
392
+ $[32] = t9;
393
+ $[33] = t10;
394
+ } else t10 = $[33];
395
+ return t10;
396
+ }
397
+ if (overview.status === "none") return null;
398
+ let t2;
399
+ if ($[34] === Symbol.for("react.memo_cache_sentinel")) {
400
+ t2 = /* @__PURE__ */ jsxs("div", {
401
+ "data-overview": true,
402
+ className: "flex flex-col gap-2",
403
+ children: [
404
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-11/12" }),
405
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-4/5" }),
406
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-2/3" }),
407
+ /* @__PURE__ */ jsx("p", {
408
+ className: "text-muted-foreground text-sm",
409
+ children: "Summarizing this draft…"
410
+ })
411
+ ]
412
+ });
413
+ $[34] = t2;
414
+ } else t2 = $[34];
415
+ return t2;
416
+ }
417
+ function _temp6(change) {
418
+ return change.entity === "locale" ? "Languages" : ownerName(change.owner, change.entity);
419
+ }
420
+ function _temp5(bullet, index) {
421
+ return /* @__PURE__ */ jsx("li", { children: bullet }, index);
422
+ }
423
+ function _temp4(error) {
424
+ return toast.error(error.message || "Could not summarize the draft");
425
+ }
426
+ /**
427
+ * Reviews a draft before publishing it whole (ADR 0009, ADR 0043). Publish is held only by
428
+ * blockers or an empty draft, never by work Camox still runs. Once the draft ends, the studio
429
+ * switches to Live.
430
+ */
431
+ function ReviewDraftDialog(t0) {
432
+ const $ = c(60);
433
+ const { projectId, draftId, open, onOpenChange } = t0;
434
+ let t1;
435
+ if ($[0] !== draftId || $[1] !== projectId) {
436
+ t1 = reads.publishPreview({
437
+ projectId,
438
+ draftId
439
+ });
440
+ $[0] = draftId;
441
+ $[1] = projectId;
442
+ $[2] = t1;
443
+ } else t1 = $[2];
444
+ let t2;
445
+ if ($[3] !== open) {
446
+ t2 = { enabled: open };
447
+ $[3] = open;
448
+ $[4] = t2;
449
+ } else t2 = $[4];
450
+ const preview = useReadQuery(t1, t2);
451
+ let t3;
452
+ if ($[5] !== draftId || $[6] !== projectId) {
453
+ t3 = reads.draft({
454
+ projectId,
455
+ draftId
456
+ });
457
+ $[5] = draftId;
458
+ $[6] = projectId;
459
+ $[7] = t3;
460
+ } else t3 = $[7];
461
+ let t4;
462
+ if ($[8] !== open) {
463
+ t4 = { enabled: open };
464
+ $[8] = open;
465
+ $[9] = t4;
466
+ } else t4 = $[9];
467
+ const draft = useReadQuery(t3, t4);
468
+ const leaveDraft = useLeaveDraft();
469
+ const showInCanvas = useShowInCanvas();
470
+ const [failed, setFailed] = useState(false);
471
+ let t5;
472
+ let t6;
473
+ if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
474
+ t5 = draftMutations.publish();
475
+ t6 = () => setFailed(false);
476
+ $[10] = t5;
477
+ $[11] = t6;
478
+ } else {
479
+ t5 = $[10];
480
+ t6 = $[11];
481
+ }
482
+ let t7;
483
+ if ($[12] !== leaveDraft || $[13] !== onOpenChange || $[14] !== preview) {
484
+ t7 = (result) => {
485
+ if ("publishing" in result && result.publishing) {
486
+ preview.refetch();
487
+ return;
488
+ }
489
+ if (!result.empty) {
490
+ onOpenChange(false);
491
+ return leaveDraft(result.ended);
492
+ }
493
+ toast.info("This draft has no changes, so there is nothing to publish.");
494
+ preview.refetch();
495
+ };
496
+ $[12] = leaveDraft;
497
+ $[13] = onOpenChange;
498
+ $[14] = preview;
499
+ $[15] = t7;
500
+ } else t7 = $[15];
501
+ let t8;
502
+ if ($[16] !== preview) {
503
+ t8 = (error) => {
504
+ if (failedOnCamoxSide(error)) setFailed(true);
505
+ else if (error.code !== PUBLISH_BLOCKED_ERROR) toast.error(error.message);
506
+ preview.refetch();
507
+ };
508
+ $[16] = preview;
509
+ $[17] = t8;
510
+ } else t8 = $[17];
511
+ let t9;
512
+ if ($[18] !== t7 || $[19] !== t8) {
513
+ t9 = {
514
+ ...t5,
515
+ onMutate: t6,
516
+ onSuccess: t7,
517
+ onError: t8
518
+ };
519
+ $[18] = t7;
520
+ $[19] = t8;
521
+ $[20] = t9;
522
+ } else t9 = $[20];
523
+ const publish = useMutation(t9);
524
+ const data = preview.data;
525
+ const empty = !!data && data.changes.length === 0 && !data.code;
526
+ const publishing = publish.isPending || !!data?.code?.publishing;
527
+ let T0;
528
+ let T1;
529
+ let t10;
530
+ let t11;
531
+ let t12;
532
+ let t13;
533
+ let t14;
534
+ if ($[21] !== data || $[22] !== draft.data || $[23] !== failed || $[24] !== onOpenChange || $[25] !== open || $[26] !== projectId || $[27] !== showInCanvas) {
535
+ const lines = data ? reviewLines(data) : [];
536
+ if (failed && !lines.includes(PUBLISH_FAILED)) lines.push(PUBLISH_FAILED);
537
+ T1 = Dialog;
538
+ t13 = open;
539
+ t14 = onOpenChange;
540
+ T0 = DialogContent;
541
+ t10 = "flex max-h-[85vh] flex-col gap-4 sm:max-w-lg";
542
+ let t15;
543
+ if ($[35] !== draft.data) {
544
+ t15 = draft.data ? draftLabel(draft.data) : "Draft";
545
+ $[35] = draft.data;
546
+ $[36] = t15;
547
+ } else t15 = $[36];
548
+ if ($[37] !== t15) {
549
+ t11 = /* @__PURE__ */ jsx(DialogHeader, {
550
+ className: "pr-8",
551
+ children: /* @__PURE__ */ jsx(DialogTitle, {
552
+ className: "truncate text-base",
553
+ children: t15
554
+ })
555
+ });
556
+ $[37] = t15;
557
+ $[38] = t11;
558
+ } else t11 = $[38];
559
+ t12 = data ? /* @__PURE__ */ jsxs("div", {
560
+ className: "-mx-6 flex min-h-0 flex-col gap-4 overflow-y-auto px-6",
561
+ children: [
562
+ /* @__PURE__ */ jsx(DraftOverview, {
563
+ projectId,
564
+ preview: data
565
+ }),
566
+ /* @__PURE__ */ jsx(Blockers, {
567
+ blockers: data.blockers,
568
+ onShow: (target) => {
569
+ onOpenChange(false);
570
+ showInCanvas(target);
571
+ }
572
+ }),
573
+ lines.map(_temp7)
574
+ ]
575
+ }) : /* @__PURE__ */ jsx("div", {
576
+ className: "flex items-center justify-center py-6",
577
+ children: /* @__PURE__ */ jsx(Spinner, { className: "text-muted-foreground" })
578
+ });
579
+ $[21] = data;
580
+ $[22] = draft.data;
581
+ $[23] = failed;
582
+ $[24] = onOpenChange;
583
+ $[25] = open;
584
+ $[26] = projectId;
585
+ $[27] = showInCanvas;
586
+ $[28] = T0;
587
+ $[29] = T1;
588
+ $[30] = t10;
589
+ $[31] = t11;
590
+ $[32] = t12;
591
+ $[33] = t13;
592
+ $[34] = t14;
593
+ } else {
594
+ T0 = $[28];
595
+ T1 = $[29];
596
+ t10 = $[30];
597
+ t11 = $[31];
598
+ t12 = $[32];
599
+ t13 = $[33];
600
+ t14 = $[34];
601
+ }
602
+ const t15 = !data || data.blockers.length > 0 || empty || publishing;
603
+ let t16;
604
+ if ($[39] !== data || $[40] !== projectId || $[41] !== publish) {
605
+ t16 = () => data && publish.mutate(publishInput(projectId, data));
606
+ $[39] = data;
607
+ $[40] = projectId;
608
+ $[41] = publish;
609
+ $[42] = t16;
610
+ } else t16 = $[42];
611
+ let t17;
612
+ if ($[43] !== publishing) {
613
+ t17 = publishing ? /* @__PURE__ */ jsx(Spinner, {}) : null;
614
+ $[43] = publishing;
615
+ $[44] = t17;
616
+ } else t17 = $[44];
617
+ let t18;
618
+ if ($[45] !== t15 || $[46] !== t16 || $[47] !== t17) {
619
+ t18 = /* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsxs(Button, {
620
+ disabled: t15,
621
+ onClick: t16,
622
+ children: [t17, "Publish"]
623
+ }) });
624
+ $[45] = t15;
625
+ $[46] = t16;
626
+ $[47] = t17;
627
+ $[48] = t18;
628
+ } else t18 = $[48];
629
+ let t19;
630
+ if ($[49] !== T0 || $[50] !== t10 || $[51] !== t11 || $[52] !== t12 || $[53] !== t18) {
631
+ t19 = /* @__PURE__ */ jsxs(T0, {
632
+ className: t10,
633
+ children: [
634
+ t11,
635
+ t12,
636
+ t18
637
+ ]
638
+ });
639
+ $[49] = T0;
640
+ $[50] = t10;
641
+ $[51] = t11;
642
+ $[52] = t12;
643
+ $[53] = t18;
644
+ $[54] = t19;
645
+ } else t19 = $[54];
646
+ let t20;
647
+ if ($[55] !== T1 || $[56] !== t13 || $[57] !== t14 || $[58] !== t19) {
648
+ t20 = /* @__PURE__ */ jsx(T1, {
649
+ open: t13,
650
+ onOpenChange: t14,
651
+ children: t19
652
+ });
653
+ $[55] = T1;
654
+ $[56] = t13;
655
+ $[57] = t14;
656
+ $[58] = t19;
657
+ $[59] = t20;
658
+ } else t20 = $[59];
659
+ return t20;
660
+ }
661
+ function _temp7(line) {
662
+ return /* @__PURE__ */ jsx("p", {
663
+ className: "text-sm text-amber-700 dark:text-amber-400",
664
+ "data-review-line": true,
665
+ children: line
666
+ }, line);
667
+ }
668
+
669
+ //#endregion
670
+ export { ReviewDraftDialog, fixBlockersMessage };