camox 0.76.1 → 0.78.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 (33) hide show
  1. package/dist/core/lib/artifactTheme.js +43 -6
  2. package/dist/features/canvas/CamoxCanvas.js +187 -197
  3. package/dist/features/canvas/canvasCameraController.js +1 -1
  4. package/dist/features/canvas/canvasItems.js +40 -9
  5. package/dist/features/canvas/sidebar/ContentSidebarFrame.js +15 -11
  6. package/dist/features/canvas/useCanvasLayout.js +34 -0
  7. package/dist/features/memory/CamoxMemory.js +747 -0
  8. package/dist/features/preview/EditablePageExperience.js +2 -0
  9. package/dist/features/runtime/publicCache.d.ts +2 -0
  10. package/dist/features/runtime/publicCache.js +27 -4
  11. package/dist/features/runtime/runtime.d.ts +1 -1
  12. package/dist/features/runtime/runtime.js +34 -15
  13. package/dist/features/studio/FollowAgentProvider.js +1 -1
  14. package/dist/features/studio/components/AgentSidebar.js +22 -16
  15. package/dist/features/studio/components/DraftBar.js +167 -103
  16. package/dist/features/studio/components/{ReviewDraftDialog.js → DraftReview.js} +191 -218
  17. package/dist/features/studio/components/DraftsControl.js +174 -202
  18. package/dist/features/studio/components/DraftsSheet.js +102 -94
  19. package/dist/features/studio/components/LocalePicker.js +518 -134
  20. package/dist/features/studio/components/Navbar.js +121 -84
  21. package/dist/features/studio/components/PublishedTab.js +21 -20
  22. package/dist/features/studio/routes.js +3 -1
  23. package/dist/features/studio/studioStore.js +12 -9
  24. package/dist/features/studio/usePublishDraft.js +116 -0
  25. package/dist/features/studio/viewSwitch.js +10 -7
  26. package/dist/lib/locale-path.js +2 -2
  27. package/dist/lib/queries.js +12 -2
  28. package/dist/lib/studio-reads.js +6 -0
  29. package/dist/package.js +1 -1
  30. package/dist/studio.css +1 -1
  31. package/package.json +5 -5
  32. package/skills/camox/references/artifacts.md +7 -0
  33. package/LICENSE.md +0 -21
@@ -4,24 +4,27 @@ import { draftMutations } from "../../../lib/queries.js";
4
4
  import { studioStore } from "../studioStore.js";
5
5
  import { localeName } from "../localeOptions.js";
6
6
  import { fixMessage, whereSentence } from "../fixMessage.js";
7
- import { useLeaveDraft } from "../viewSwitch.js";
8
7
  import { draftLabel, plural } from "../draftLabel.js";
8
+ import { PUBLISH_STOPPED } from "../usePublishDraft.js";
9
9
  import { useShowInCanvas } from "../showInCanvas.js";
10
10
  import { c } from "react/compiler-runtime";
11
- import { useState } from "react";
12
- import { PUBLISH_BLOCKED_ERROR } from "@camox/api-contract/drafts";
13
11
  import { jsx, jsxs } from "react/jsx-runtime";
14
12
  import { useMutation } from "@tanstack/react-query";
15
13
  import { Button } from "@camox/ui/button";
16
14
  import { OctagonX } from "lucide-react";
17
- import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@camox/ui/dialog";
18
15
  import { toast } from "@camox/ui/toaster";
19
16
  import { Skeleton } from "@camox/ui/skeleton";
20
17
  import { Spinner } from "@camox/ui/spinner";
18
+ import { Popover, PopoverContent, PopoverHeader, PopoverTitle, PopoverTrigger } from "@camox/ui/popover";
21
19
 
22
- //#region src/features/studio/components/ReviewDraftDialog.tsx
23
- /** Where a subject sits: its page or layout, or the files, which belong to neither. */
20
+ //#region src/features/studio/components/DraftReview.tsx
21
+ /**
22
+ * Where a subject sits: its page or layout, or the files, the languages or memory, which belong
23
+ * to none.
24
+ */
24
25
  function ownerName(owner, entity) {
26
+ if (entity === "locale") return "Languages";
27
+ if (entity === "memory") return "Memory";
25
28
  if (!owner) return entity === "file" ? "Files" : "Elsewhere";
26
29
  if (owner.kind === "layout") return `Layout ${owner.name}`;
27
30
  if (owner.kind === "syncedBlock") return `Synced block ${owner.title}`;
@@ -201,25 +204,6 @@ function _temp3(problem) {
201
204
  const place = problemPlace(problem);
202
205
  return place ? `${problem.label} · ${place}` : problem.label;
203
206
  }
204
- const PUBLISH_FAILED = "The publish couldn't finish on Camox's side, and Live is as it was. Try again.";
205
- /**
206
- * Whether a publish request failed on Camox's side rather than being refused: a server error,
207
- * or no answer at all. Either way the publish applied nothing.
208
- */
209
- const failedOnCamoxSide = (error) => {
210
- const status = error.status;
211
- return typeof status !== "number" || status >= 500;
212
- };
213
- /**
214
- * Why the last publish with code stopped, when it isn't a blocker, which the review shows
215
- * instead.
216
- */
217
- const PUBLISH_STOPPED = {
218
- revisionChanged: "The draft's code changed while publishing, so the publish stopped and Live is as it was. Publish again.",
219
- 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.",
220
- conflictsChanged: PUBLISH_FAILED,
221
- failed: PUBLISH_FAILED
222
- };
223
207
  /**
224
208
  * The review's plain lines under the blockers: each language the publish holds off Live until
225
209
  * it's translated, and why the last publish stopped.
@@ -230,11 +214,67 @@ function reviewLines(preview) {
230
214
  const stopped = code?.publishAborted && !code.publishing ? code.publishAborted : null;
231
215
  return [...held, ...stopped && PUBLISH_STOPPED[stopped] ? [PUBLISH_STOPPED[stopped]] : []];
232
216
  }
233
- /** What Publish sends: the revision a draft with code shows, which publishing ships. */
234
- const publishInput = (projectId, shown) => ({
235
- projectId,
236
- ...shown.code?.revision && { revision: shown.code.revision }
237
- });
217
+ const MEMORY_CHANGE_LABELS = {
218
+ added: "Added",
219
+ changed: "Changed",
220
+ deleted: "Deleted"
221
+ };
222
+ /**
223
+ * The memories the draft adds, changes and deletes, each with its text, and Live's before a
224
+ * change: what Camox's agent will remember once it's published. Nothing when it changes none.
225
+ */
226
+ function MemoryChanges(t0) {
227
+ const $ = c(5);
228
+ const { changes } = t0;
229
+ if (changes.length === 0) return null;
230
+ let t1;
231
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
232
+ t1 = /* @__PURE__ */ jsx("h3", {
233
+ className: "text-sm font-medium",
234
+ children: "Memory"
235
+ });
236
+ $[0] = t1;
237
+ } else t1 = $[0];
238
+ let t2;
239
+ if ($[1] !== changes) {
240
+ t2 = changes.map(_temp4);
241
+ $[1] = changes;
242
+ $[2] = t2;
243
+ } else t2 = $[2];
244
+ let t3;
245
+ if ($[3] !== t2) {
246
+ t3 = /* @__PURE__ */ jsxs("section", {
247
+ "data-memory-changes": true,
248
+ className: "flex flex-col gap-2",
249
+ children: [t1, /* @__PURE__ */ jsx("ul", {
250
+ className: "flex flex-col gap-2",
251
+ children: t2
252
+ })]
253
+ });
254
+ $[3] = t2;
255
+ $[4] = t3;
256
+ } else t3 = $[4];
257
+ return t3;
258
+ }
259
+ function _temp4(memory) {
260
+ return /* @__PURE__ */ jsxs("li", {
261
+ className: "flex flex-col gap-0.5 rounded-lg border p-3 text-sm",
262
+ children: [
263
+ /* @__PURE__ */ jsx("span", {
264
+ className: "text-muted-foreground text-xs",
265
+ children: MEMORY_CHANGE_LABELS[memory.change]
266
+ }),
267
+ /* @__PURE__ */ jsx("p", {
268
+ className: cn(memory.change === "deleted" && "text-muted-foreground line-through"),
269
+ children: memory.text
270
+ }),
271
+ memory.before !== void 0 && /* @__PURE__ */ jsxs("p", {
272
+ className: "text-muted-foreground text-xs",
273
+ children: ["Was: ", memory.before]
274
+ })
275
+ ]
276
+ }, memory.id);
277
+ }
238
278
  /**
239
279
  * The draft's overview: the bullets AI wrote about its changes, in full, saying it's updating
240
280
  * while they describe an older version of the draft. While
@@ -250,7 +290,7 @@ function DraftOverview(t0) {
250
290
  if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
251
291
  t1 = {
252
292
  ...draftMutations.retryOverview(),
253
- onError: _temp4
293
+ onError: _temp5
254
294
  };
255
295
  $[0] = t1;
256
296
  } else t1 = $[0];
@@ -271,7 +311,7 @@ function DraftOverview(t0) {
271
311
  if (overview.status === "ready") {
272
312
  let t2;
273
313
  if ($[3] !== overview.bullets) {
274
- t2 = overview.bullets.map(_temp5);
314
+ t2 = overview.bullets.map(_temp6);
275
315
  $[3] = overview.bullets;
276
316
  $[4] = t2;
277
317
  } else t2 = $[4];
@@ -312,7 +352,7 @@ function DraftOverview(t0) {
312
352
  if (overview.status === "failed") {
313
353
  let t2;
314
354
  if ($[12] !== changes) {
315
- t2 = new Set(changes.map(_temp6));
355
+ t2 = new Set(changes.map(_temp7));
316
356
  $[12] = changes;
317
357
  $[13] = t2;
318
358
  } else t2 = $[13];
@@ -415,28 +455,28 @@ function DraftOverview(t0) {
415
455
  } else t2 = $[34];
416
456
  return t2;
417
457
  }
418
- function _temp6(change) {
419
- return change.entity === "locale" ? "Languages" : ownerName(change.owner, change.entity);
458
+ function _temp7(change) {
459
+ return ownerName(change.owner, change.entity);
420
460
  }
421
- function _temp5(bullet, index) {
461
+ function _temp6(bullet, index) {
422
462
  return /* @__PURE__ */ jsx("li", { children: bullet }, index);
423
463
  }
424
- function _temp4(error) {
464
+ function _temp5(error) {
425
465
  return toast.error(error.message || "Could not summarize the draft");
426
466
  }
427
467
  /**
428
- * The review's body is tall enough for a typical overview from the start, so the dialog doesn't
429
- * grow once it's written. A longer one scrolls within the dialog's own limit.
468
+ * The review's body is tall enough for a typical overview from the start, so the popover doesn't
469
+ * grow once it's written. A longer one scrolls within the space above the bar.
430
470
  */
431
- const REVIEW_BODY_HEIGHT = "min-h-52";
471
+ const REVIEW_BODY_HEIGHT = "min-h-40";
432
472
  /**
433
- * Reviews a draft before publishing it whole (ADR 0009, ADR 0043). Publish is held only by
434
- * blockers or an empty draft, never by work Camox still runs. Once the draft ends, the studio
435
- * switches to Live.
473
+ * Reviews a draft's pending changes (ADR 0009, ADR 0043) in a popover above `trigger`, the Draft
474
+ * Bar's count of them. The bar's Publish opens it too, when blockers or a stopped publish left the
475
+ * draft as it was. It publishes nothing itself.
436
476
  */
437
- function ReviewDraftDialog(t0) {
438
- const $ = c(66);
439
- const { projectId, draftId, open, onOpenChange } = t0;
477
+ function DraftReview(t0) {
478
+ const $ = c(51);
479
+ const { projectId, draftId, open, onOpenChange, trigger, anchor } = t0;
440
480
  let t1;
441
481
  if ($[0] !== draftId || $[1] !== projectId) {
442
482
  t1 = reads.publishPreview({
@@ -471,62 +511,8 @@ function ReviewDraftDialog(t0) {
471
511
  $[9] = t4;
472
512
  } else t4 = $[9];
473
513
  const draft = useReadQuery(t3, t4);
474
- const leaveDraft = useLeaveDraft();
475
514
  const showInCanvas = useShowInCanvas();
476
- const [failed, setFailed] = useState(false);
477
- let t5;
478
- let t6;
479
- if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
480
- t5 = draftMutations.publish();
481
- t6 = () => setFailed(false);
482
- $[10] = t5;
483
- $[11] = t6;
484
- } else {
485
- t5 = $[10];
486
- t6 = $[11];
487
- }
488
- let t7;
489
- if ($[12] !== leaveDraft || $[13] !== onOpenChange || $[14] !== preview) {
490
- t7 = (result) => {
491
- if ("publishing" in result && result.publishing) return preview.refetch();
492
- if (!result.empty) {
493
- onOpenChange(false);
494
- return leaveDraft(result.ended);
495
- }
496
- toast.info("This draft has no changes, so there is nothing to publish.");
497
- preview.refetch();
498
- };
499
- $[12] = leaveDraft;
500
- $[13] = onOpenChange;
501
- $[14] = preview;
502
- $[15] = t7;
503
- } else t7 = $[15];
504
- let t8;
505
- if ($[16] !== preview) {
506
- t8 = (error) => {
507
- if (failedOnCamoxSide(error)) setFailed(true);
508
- else if (error.code !== PUBLISH_BLOCKED_ERROR) toast.error(error.message);
509
- preview.refetch();
510
- };
511
- $[16] = preview;
512
- $[17] = t8;
513
- } else t8 = $[17];
514
- let t9;
515
- if ($[18] !== t7 || $[19] !== t8) {
516
- t9 = {
517
- ...t5,
518
- onMutate: t6,
519
- onSuccess: t7,
520
- onError: t8
521
- };
522
- $[18] = t7;
523
- $[19] = t8;
524
- $[20] = t9;
525
- } else t9 = $[20];
526
- const publish = useMutation(t9);
527
515
  const data = preview.data;
528
- const empty = !!data && data.changes.length === 0 && !data.code;
529
- const publishing = publish.isPending || !!data?.code?.publishing;
530
516
  let T0;
531
517
  let T1;
532
518
  let t10;
@@ -534,40 +520,43 @@ function ReviewDraftDialog(t0) {
534
520
  let t12;
535
521
  let t13;
536
522
  let t14;
537
- let t15;
538
- if ($[21] !== data || $[22] !== draft.data || $[23] !== failed || $[24] !== onOpenChange || $[25] !== open || $[26] !== projectId || $[27] !== publishing || $[28] !== showInCanvas) {
523
+ let t5;
524
+ let t6;
525
+ let t7;
526
+ let t8;
527
+ let t9;
528
+ if ($[10] !== anchor || $[11] !== data || $[12] !== draft.data || $[13] !== onOpenChange || $[14] !== open || $[15] !== projectId || $[16] !== showInCanvas || $[17] !== trigger) {
539
529
  const lines = data ? reviewLines(data) : [];
540
- if (failed && !lines.includes(PUBLISH_FAILED)) lines.push(PUBLISH_FAILED);
541
- T1 = Dialog;
542
- t14 = open;
543
- if ($[37] !== onOpenChange || $[38] !== publishing) {
544
- t15 = (next) => (next || !publishing) && onOpenChange(next);
545
- $[37] = onOpenChange;
546
- $[38] = publishing;
547
- $[39] = t15;
548
- } else t15 = $[39];
549
- T0 = DialogContent;
550
- t10 = "flex max-h-[85vh] flex-col gap-4 sm:max-w-xl";
551
- t11 = !publishing;
552
- let t16;
553
- if ($[40] !== draft.data) {
554
- t16 = draft.data ? draftLabel(draft.data) : "Draft";
555
- $[40] = draft.data;
556
- $[41] = t16;
557
- } else t16 = $[41];
558
- if ($[42] !== t16) {
559
- t12 = /* @__PURE__ */ jsx(DialogHeader, {
560
- className: "pr-8",
561
- children: /* @__PURE__ */ jsx(DialogTitle, {
562
- className: "truncate text-base",
563
- children: t16
564
- })
565
- });
566
- $[42] = t16;
567
- $[43] = t12;
568
- } else t12 = $[43];
569
- t13 = data ? /* @__PURE__ */ jsxs("div", {
570
- className: cn("-mx-6 flex flex-col gap-4 overflow-y-auto px-6", REVIEW_BODY_HEIGHT),
530
+ T1 = Popover;
531
+ t12 = open;
532
+ t13 = onOpenChange;
533
+ if ($[30] !== trigger) {
534
+ t14 = /* @__PURE__ */ jsx(PopoverTrigger, { render: trigger });
535
+ $[30] = trigger;
536
+ $[31] = t14;
537
+ } else t14 = $[31];
538
+ T0 = PopoverContent;
539
+ t5 = "top";
540
+ t6 = "start";
541
+ t7 = 8;
542
+ t8 = anchor;
543
+ t9 = "max-h-[min(36rem,var(--available-height))] w-[min(28rem,calc(100vw-2rem))] gap-3 overflow-y-auto";
544
+ let t15;
545
+ if ($[32] !== draft.data) {
546
+ t15 = draft.data ? draftLabel(draft.data) : "Draft";
547
+ $[32] = draft.data;
548
+ $[33] = t15;
549
+ } else t15 = $[33];
550
+ if ($[34] !== t15) {
551
+ t10 = /* @__PURE__ */ jsx(PopoverHeader, { children: /* @__PURE__ */ jsx(PopoverTitle, {
552
+ className: "truncate",
553
+ children: t15
554
+ }) });
555
+ $[34] = t15;
556
+ $[35] = t10;
557
+ } else t10 = $[35];
558
+ t11 = data ? /* @__PURE__ */ jsxs("div", {
559
+ className: cn("flex flex-col gap-4", REVIEW_BODY_HEIGHT),
571
560
  children: [
572
561
  /* @__PURE__ */ jsx(DraftOverview, {
573
562
  projectId,
@@ -580,100 +569,84 @@ function ReviewDraftDialog(t0) {
580
569
  showInCanvas(target);
581
570
  }
582
571
  }),
583
- lines.map(_temp7)
572
+ lines.map(_temp8),
573
+ /* @__PURE__ */ jsx(MemoryChanges, { changes: data.memoryChanges })
584
574
  ]
585
575
  }) : /* @__PURE__ */ jsx("div", {
586
576
  className: cn("flex items-center justify-center", REVIEW_BODY_HEIGHT),
587
577
  children: /* @__PURE__ */ jsx(Spinner, { className: "text-muted-foreground" })
588
578
  });
589
- $[21] = data;
590
- $[22] = draft.data;
591
- $[23] = failed;
592
- $[24] = onOpenChange;
593
- $[25] = open;
594
- $[26] = projectId;
595
- $[27] = publishing;
596
- $[28] = showInCanvas;
597
- $[29] = T0;
598
- $[30] = T1;
599
- $[31] = t10;
600
- $[32] = t11;
601
- $[33] = t12;
602
- $[34] = t13;
603
- $[35] = t14;
604
- $[36] = t15;
579
+ $[10] = anchor;
580
+ $[11] = data;
581
+ $[12] = draft.data;
582
+ $[13] = onOpenChange;
583
+ $[14] = open;
584
+ $[15] = projectId;
585
+ $[16] = showInCanvas;
586
+ $[17] = trigger;
587
+ $[18] = T0;
588
+ $[19] = T1;
589
+ $[20] = t10;
590
+ $[21] = t11;
591
+ $[22] = t12;
592
+ $[23] = t13;
593
+ $[24] = t14;
594
+ $[25] = t5;
595
+ $[26] = t6;
596
+ $[27] = t7;
597
+ $[28] = t8;
598
+ $[29] = t9;
605
599
  } else {
606
- T0 = $[29];
607
- T1 = $[30];
608
- t10 = $[31];
609
- t11 = $[32];
610
- t12 = $[33];
611
- t13 = $[34];
612
- t14 = $[35];
613
- t15 = $[36];
600
+ T0 = $[18];
601
+ T1 = $[19];
602
+ t10 = $[20];
603
+ t11 = $[21];
604
+ t12 = $[22];
605
+ t13 = $[23];
606
+ t14 = $[24];
607
+ t5 = $[25];
608
+ t6 = $[26];
609
+ t7 = $[27];
610
+ t8 = $[28];
611
+ t9 = $[29];
614
612
  }
615
- const t16 = !data || data.blockers.length > 0 || empty || publishing;
616
- let t17;
617
- if ($[44] !== data || $[45] !== projectId || $[46] !== publish) {
618
- t17 = () => data && publish.mutate(publishInput(projectId, data));
619
- $[44] = data;
620
- $[45] = projectId;
621
- $[46] = publish;
622
- $[47] = t17;
623
- } else t17 = $[47];
624
- let t18;
625
- if ($[48] !== publishing) {
626
- t18 = publishing ? /* @__PURE__ */ jsx(Spinner, {}) : null;
627
- $[48] = publishing;
628
- $[49] = t18;
629
- } else t18 = $[49];
630
- let t19;
631
- if ($[50] !== t16 || $[51] !== t17 || $[52] !== t18) {
632
- t19 = /* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsxs(Button, {
633
- disabled: t16,
634
- onClick: t17,
635
- children: [t18, "Publish"]
636
- }) });
637
- $[50] = t16;
638
- $[51] = t17;
639
- $[52] = t18;
640
- $[53] = t19;
641
- } else t19 = $[53];
642
- let t20;
643
- if ($[54] !== T0 || $[55] !== t10 || $[56] !== t11 || $[57] !== t12 || $[58] !== t13 || $[59] !== t19) {
644
- t20 = /* @__PURE__ */ jsxs(T0, {
645
- className: t10,
646
- showCloseButton: t11,
647
- children: [
648
- t12,
649
- t13,
650
- t19
651
- ]
613
+ let t15;
614
+ if ($[36] !== T0 || $[37] !== t10 || $[38] !== t11 || $[39] !== t5 || $[40] !== t6 || $[41] !== t7 || $[42] !== t8 || $[43] !== t9) {
615
+ t15 = /* @__PURE__ */ jsxs(T0, {
616
+ side: t5,
617
+ align: t6,
618
+ sideOffset: t7,
619
+ anchor: t8,
620
+ className: t9,
621
+ children: [t10, t11]
652
622
  });
653
- $[54] = T0;
654
- $[55] = t10;
655
- $[56] = t11;
656
- $[57] = t12;
657
- $[58] = t13;
658
- $[59] = t19;
659
- $[60] = t20;
660
- } else t20 = $[60];
661
- let t21;
662
- if ($[61] !== T1 || $[62] !== t14 || $[63] !== t15 || $[64] !== t20) {
663
- t21 = /* @__PURE__ */ jsx(T1, {
664
- open: t14,
665
- onOpenChange: t15,
666
- children: t20
623
+ $[36] = T0;
624
+ $[37] = t10;
625
+ $[38] = t11;
626
+ $[39] = t5;
627
+ $[40] = t6;
628
+ $[41] = t7;
629
+ $[42] = t8;
630
+ $[43] = t9;
631
+ $[44] = t15;
632
+ } else t15 = $[44];
633
+ let t16;
634
+ if ($[45] !== T1 || $[46] !== t12 || $[47] !== t13 || $[48] !== t14 || $[49] !== t15) {
635
+ t16 = /* @__PURE__ */ jsxs(T1, {
636
+ open: t12,
637
+ onOpenChange: t13,
638
+ children: [t14, t15]
667
639
  });
668
- $[61] = T1;
669
- $[62] = t14;
670
- $[63] = t15;
671
- $[64] = t20;
672
- $[65] = t21;
673
- } else t21 = $[65];
674
- return t21;
640
+ $[45] = T1;
641
+ $[46] = t12;
642
+ $[47] = t13;
643
+ $[48] = t14;
644
+ $[49] = t15;
645
+ $[50] = t16;
646
+ } else t16 = $[50];
647
+ return t16;
675
648
  }
676
- function _temp7(line) {
649
+ function _temp8(line) {
677
650
  return /* @__PURE__ */ jsx("p", {
678
651
  className: "text-sm text-amber-700 dark:text-amber-400",
679
652
  "data-review-line": true,
@@ -682,4 +655,4 @@ function _temp7(line) {
682
655
  }
683
656
 
684
657
  //#endregion
685
- export { ReviewDraftDialog, fixBlockersMessage };
658
+ export { DraftReview, fixBlockersMessage };