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.
- package/dist/features/preview/components/PageInfo.js +121 -98
- package/dist/features/preview/components/SelectionEditor.js +1 -1
- package/dist/features/routes/pageRuntime.js +15 -4
- package/dist/features/runtime/ClaimCard.js +192 -0
- package/dist/features/runtime/pageApp.js +4 -3
- package/dist/features/runtime/runtime.js +26 -5
- package/dist/features/runtime/worker.js +2 -2
- package/dist/features/runtime/workerRequest.d.ts +6 -0
- package/dist/features/runtime/workerRequest.js +13 -1
- package/dist/features/runtime/workerRuntime.d.ts +2 -2
- package/dist/features/runtime/workerRuntime.js +2 -2
- package/dist/features/studio/components/AgentSidebar.js +7 -7
- package/dist/features/studio/components/ChatWidget.js +142 -106
- package/dist/features/studio/components/ContentFindings.js +127 -230
- package/dist/features/studio/components/DeleteDraftDialog.js +112 -0
- package/dist/features/studio/components/DraftBar.js +98 -53
- package/dist/features/studio/components/DraftsControl.js +203 -190
- package/dist/features/studio/components/ReviewDraftDialog.js +670 -0
- package/dist/features/studio/components/{Patrol.js → Specialists.js} +291 -330
- package/dist/features/studio/components/Squareling.js +5 -5
- package/dist/features/studio/components/ThreadComposer.js +106 -127
- package/dist/features/studio/components/ThreadMessages.js +94 -69
- package/dist/features/studio/findingSentence.js +14 -12
- package/dist/features/studio/fixMessage.js +23 -0
- package/dist/features/studio/reportSentence.js +1 -1
- package/dist/features/studio/{patrollerBio.js → specialistBio.js} +8 -5
- package/dist/features/studio/studioStore.js +29 -15
- package/dist/features/studio/workingSentence.js +1 -1
- package/dist/lib/api-client.js +5 -1
- package/dist/lib/queries.js +5 -5
- package/dist/lib/studio-reads.d.ts +1 -1
- package/dist/lib/studio-reads.js +5 -5
- package/dist/package.js +1 -1
- package/dist/studio.css +1 -1
- package/package.json +4 -4
- 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 };
|