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.
- package/dist/core/lib/artifactRuntime.js +4 -2
- package/dist/features/preview/components/PageInfo.js +121 -98
- package/dist/features/preview/components/SelectionEditor.js +1 -1
- package/dist/features/renderer/RendererFrames.js +47 -41
- 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 +246 -71
- 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
|
@@ -4,6 +4,9 @@ import { ThreadMarkdown } from "./ThreadMarkdown.js";
|
|
|
4
4
|
import { c } from "react/compiler-runtime";
|
|
5
5
|
import * as React from "react";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { Button } from "@camox/ui/button";
|
|
8
|
+
import { X } from "lucide-react";
|
|
9
|
+
import { Dialog, DialogContent, DialogTitle } from "@camox/ui/dialog";
|
|
7
10
|
import { Avatar, AvatarFallback, AvatarImage } from "@camox/ui/avatar";
|
|
8
11
|
import { Bubble, BubbleContent } from "@camox/ui/bubble";
|
|
9
12
|
import { Message, MessageAvatar, MessageContent, MessageHeader } from "@camox/ui/message";
|
|
@@ -298,7 +301,7 @@ const PUSH_OUTCOMES = {
|
|
|
298
301
|
notPreviewed: "Built, but the preview can’t show it."
|
|
299
302
|
};
|
|
300
303
|
function ThreadMessageRow(t0) {
|
|
301
|
-
const $ = c(
|
|
304
|
+
const $ = c(56);
|
|
302
305
|
const { message, onOpenDraft } = t0;
|
|
303
306
|
if (message.from === "draft") {
|
|
304
307
|
let t1;
|
|
@@ -407,95 +410,136 @@ function ThreadMessageRow(t0) {
|
|
|
407
410
|
}
|
|
408
411
|
if (message.from === "connectedAgent") {
|
|
409
412
|
const { member, client } = message;
|
|
413
|
+
const sender = `${member.name}’s ${client.verified ? client.name : "agent"}`;
|
|
414
|
+
if (message.answer) {
|
|
415
|
+
const t1 = `${sender} added context`;
|
|
416
|
+
const t2 = client.verified ? void 0 : client.name;
|
|
417
|
+
let t3;
|
|
418
|
+
if ($[26] !== message.attachments) {
|
|
419
|
+
t3 = message.attachments && /* @__PURE__ */ jsx(AttachmentThumbnails, { attachments: message.attachments });
|
|
420
|
+
$[26] = message.attachments;
|
|
421
|
+
$[27] = t3;
|
|
422
|
+
} else t3 = $[27];
|
|
423
|
+
let t4;
|
|
424
|
+
if ($[28] !== message.text || $[29] !== t1 || $[30] !== t2 || $[31] !== t3) {
|
|
425
|
+
t4 = /* @__PURE__ */ jsx(Message, { children: /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx(CollapsedNote, {
|
|
426
|
+
label: t1,
|
|
427
|
+
hideLabel: "Hide the context",
|
|
428
|
+
title: t2,
|
|
429
|
+
text: message.text,
|
|
430
|
+
children: t3
|
|
431
|
+
}) }) });
|
|
432
|
+
$[28] = message.text;
|
|
433
|
+
$[29] = t1;
|
|
434
|
+
$[30] = t2;
|
|
435
|
+
$[31] = t3;
|
|
436
|
+
$[32] = t4;
|
|
437
|
+
} else t4 = $[32];
|
|
438
|
+
return t4;
|
|
439
|
+
}
|
|
410
440
|
const t1 = client.verified ? void 0 : client.name;
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
t3 = /* @__PURE__ */ jsx(MessageHeader, {
|
|
441
|
+
let t2;
|
|
442
|
+
if ($[33] !== sender || $[34] !== t1) {
|
|
443
|
+
t2 = /* @__PURE__ */ jsx(MessageHeader, {
|
|
415
444
|
className: "text-muted-foreground text-xs",
|
|
416
445
|
title: t1,
|
|
417
|
-
children:
|
|
446
|
+
children: sender
|
|
418
447
|
});
|
|
419
|
-
$[
|
|
420
|
-
$[
|
|
421
|
-
$[
|
|
422
|
-
} else
|
|
423
|
-
let
|
|
424
|
-
if ($[
|
|
425
|
-
|
|
448
|
+
$[33] = sender;
|
|
449
|
+
$[34] = t1;
|
|
450
|
+
$[35] = t2;
|
|
451
|
+
} else t2 = $[35];
|
|
452
|
+
let t3;
|
|
453
|
+
if ($[36] !== message.text) {
|
|
454
|
+
t3 = /* @__PURE__ */ jsx(Bubble, {
|
|
426
455
|
variant: "muted",
|
|
427
456
|
className: "max-w-full",
|
|
428
457
|
children: /* @__PURE__ */ jsx(BubbleContent, { children: /* @__PURE__ */ jsx(CroppedText, { text: message.text }) })
|
|
429
458
|
});
|
|
430
|
-
$[
|
|
431
|
-
$[
|
|
432
|
-
} else
|
|
459
|
+
$[36] = message.text;
|
|
460
|
+
$[37] = t3;
|
|
461
|
+
} else t3 = $[37];
|
|
462
|
+
let t4;
|
|
463
|
+
if ($[38] !== message.attachments) {
|
|
464
|
+
t4 = message.attachments && /* @__PURE__ */ jsx(AttachmentThumbnails, { attachments: message.attachments });
|
|
465
|
+
$[38] = message.attachments;
|
|
466
|
+
$[39] = t4;
|
|
467
|
+
} else t4 = $[39];
|
|
433
468
|
let t5;
|
|
434
|
-
if ($[
|
|
435
|
-
t5 = /* @__PURE__ */ jsx(Message, { children: /* @__PURE__ */ jsxs(MessageContent, { children: [
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
469
|
+
if ($[40] !== t2 || $[41] !== t3 || $[42] !== t4) {
|
|
470
|
+
t5 = /* @__PURE__ */ jsx(Message, { children: /* @__PURE__ */ jsxs(MessageContent, { children: [
|
|
471
|
+
t2,
|
|
472
|
+
t3,
|
|
473
|
+
t4
|
|
474
|
+
] }) });
|
|
475
|
+
$[40] = t2;
|
|
476
|
+
$[41] = t3;
|
|
477
|
+
$[42] = t4;
|
|
478
|
+
$[43] = t5;
|
|
479
|
+
} else t5 = $[43];
|
|
440
480
|
return t5;
|
|
441
481
|
}
|
|
442
482
|
if (message.from === "brief") {
|
|
443
483
|
let t1;
|
|
444
|
-
if ($[
|
|
445
|
-
t1 = /* @__PURE__ */ jsx(Message, { children: /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx(
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
484
|
+
if ($[44] !== message.text) {
|
|
485
|
+
t1 = /* @__PURE__ */ jsx(Message, { children: /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx(CollapsedNote, {
|
|
486
|
+
label: "Camox briefed the agent",
|
|
487
|
+
hideLabel: "Hide the brief",
|
|
488
|
+
text: message.text
|
|
489
|
+
}) }) });
|
|
490
|
+
$[44] = message.text;
|
|
491
|
+
$[45] = t1;
|
|
492
|
+
} else t1 = $[45];
|
|
449
493
|
return t1;
|
|
450
494
|
}
|
|
451
495
|
if (message.from === "camox") {
|
|
452
496
|
let t1;
|
|
453
|
-
if ($[
|
|
497
|
+
if ($[46] === Symbol.for("react.memo_cache_sentinel")) {
|
|
454
498
|
t1 = /* @__PURE__ */ jsx(MessageHeader, {
|
|
455
499
|
className: "text-muted-foreground text-xs",
|
|
456
500
|
children: "Camox"
|
|
457
501
|
});
|
|
458
|
-
$[
|
|
459
|
-
} else t1 = $[
|
|
502
|
+
$[46] = t1;
|
|
503
|
+
} else t1 = $[46];
|
|
460
504
|
let t2;
|
|
461
|
-
if ($[
|
|
505
|
+
if ($[47] !== message.text) {
|
|
462
506
|
t2 = /* @__PURE__ */ jsx(Message, { children: /* @__PURE__ */ jsxs(MessageContent, { children: [t1, /* @__PURE__ */ jsx(Bubble, {
|
|
463
507
|
variant: "muted",
|
|
464
508
|
className: "max-w-full",
|
|
465
509
|
children: /* @__PURE__ */ jsx(BubbleContent, { children: /* @__PURE__ */ jsx(CroppedText, { text: message.text }) })
|
|
466
510
|
})] }) });
|
|
467
|
-
$[
|
|
468
|
-
$[
|
|
469
|
-
} else t2 = $[
|
|
511
|
+
$[47] = message.text;
|
|
512
|
+
$[48] = t2;
|
|
513
|
+
} else t2 = $[48];
|
|
470
514
|
return t2;
|
|
471
515
|
}
|
|
472
516
|
let t1;
|
|
473
|
-
if ($[
|
|
517
|
+
if ($[49] !== message.sender) {
|
|
474
518
|
t1 = /* @__PURE__ */ jsx(MessageAvatar, { children: /* @__PURE__ */ jsx(SenderAvatar, { sender: message.sender }) });
|
|
475
|
-
$[
|
|
476
|
-
$[
|
|
477
|
-
} else t1 = $[
|
|
519
|
+
$[49] = message.sender;
|
|
520
|
+
$[50] = t1;
|
|
521
|
+
} else t1 = $[50];
|
|
478
522
|
let t2;
|
|
479
|
-
if ($[
|
|
523
|
+
if ($[51] !== message.text) {
|
|
480
524
|
t2 = /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx(Bubble, {
|
|
481
525
|
align: "end",
|
|
482
526
|
variant: "muted",
|
|
483
527
|
className: "max-w-full",
|
|
484
528
|
children: /* @__PURE__ */ jsx(BubbleContent, { children: /* @__PURE__ */ jsx(CroppedText, { text: message.text }) })
|
|
485
529
|
}) });
|
|
486
|
-
$[
|
|
487
|
-
$[
|
|
488
|
-
} else t2 = $[
|
|
530
|
+
$[51] = message.text;
|
|
531
|
+
$[52] = t2;
|
|
532
|
+
} else t2 = $[52];
|
|
489
533
|
let t3;
|
|
490
|
-
if ($[
|
|
534
|
+
if ($[53] !== t1 || $[54] !== t2) {
|
|
491
535
|
t3 = /* @__PURE__ */ jsxs(Message, {
|
|
492
536
|
align: "end",
|
|
493
537
|
children: [t1, t2]
|
|
494
538
|
});
|
|
495
|
-
$[
|
|
496
|
-
$[
|
|
497
|
-
$[
|
|
498
|
-
} else t3 = $[
|
|
539
|
+
$[53] = t1;
|
|
540
|
+
$[54] = t2;
|
|
541
|
+
$[55] = t3;
|
|
542
|
+
} else t3 = $[55];
|
|
499
543
|
return t3;
|
|
500
544
|
}
|
|
501
545
|
function _temp(subject, index) {
|
|
@@ -586,34 +630,159 @@ function CroppedText(t0) {
|
|
|
586
630
|
return t9;
|
|
587
631
|
}
|
|
588
632
|
/**
|
|
589
|
-
* The
|
|
590
|
-
*
|
|
633
|
+
* The Attachments a Connected Agent's message carries, the images Camox's agent saw with it
|
|
634
|
+
* (ADR 0044): a thumbnail of each, which opens it at full size.
|
|
591
635
|
*/
|
|
592
|
-
function
|
|
593
|
-
const $ = c(
|
|
594
|
-
const {
|
|
636
|
+
function AttachmentThumbnails(t0) {
|
|
637
|
+
const $ = c(20);
|
|
638
|
+
const { attachments } = t0;
|
|
639
|
+
const [opened, setOpened] = React.useState();
|
|
640
|
+
let t1;
|
|
641
|
+
if ($[0] !== attachments) {
|
|
642
|
+
let t2;
|
|
643
|
+
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
|
644
|
+
t2 = (attachment) => /* @__PURE__ */ jsx("button", {
|
|
645
|
+
type: "button",
|
|
646
|
+
title: attachment.filename,
|
|
647
|
+
onClick: () => setOpened(attachment),
|
|
648
|
+
className: "checkered focus-visible:ring-ring size-16 overflow-hidden rounded-md border focus-visible:ring-2 focus-visible:outline-none",
|
|
649
|
+
children: /* @__PURE__ */ jsx("img", {
|
|
650
|
+
src: attachment.url,
|
|
651
|
+
alt: attachment.filename,
|
|
652
|
+
className: "size-full object-cover",
|
|
653
|
+
draggable: false
|
|
654
|
+
})
|
|
655
|
+
}, attachment.id);
|
|
656
|
+
$[2] = t2;
|
|
657
|
+
} else t2 = $[2];
|
|
658
|
+
t1 = attachments.map(t2);
|
|
659
|
+
$[0] = attachments;
|
|
660
|
+
$[1] = t1;
|
|
661
|
+
} else t1 = $[1];
|
|
662
|
+
let t2;
|
|
663
|
+
if ($[3] !== t1) {
|
|
664
|
+
t2 = /* @__PURE__ */ jsx("div", {
|
|
665
|
+
"data-thread-attachments": true,
|
|
666
|
+
className: "flex flex-wrap gap-1.5",
|
|
667
|
+
children: t1
|
|
668
|
+
});
|
|
669
|
+
$[3] = t1;
|
|
670
|
+
$[4] = t2;
|
|
671
|
+
} else t2 = $[4];
|
|
672
|
+
const t3 = !!opened;
|
|
673
|
+
let t4;
|
|
674
|
+
if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
|
|
675
|
+
t4 = (open) => !open && setOpened(void 0);
|
|
676
|
+
$[5] = t4;
|
|
677
|
+
} else t4 = $[5];
|
|
678
|
+
const t5 = opened?.filename;
|
|
679
|
+
let t6;
|
|
680
|
+
if ($[6] !== t5) {
|
|
681
|
+
t6 = /* @__PURE__ */ jsx(DialogTitle, {
|
|
682
|
+
className: "sr-only",
|
|
683
|
+
children: t5
|
|
684
|
+
});
|
|
685
|
+
$[6] = t5;
|
|
686
|
+
$[7] = t6;
|
|
687
|
+
} else t6 = $[7];
|
|
688
|
+
let t7;
|
|
689
|
+
if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
|
|
690
|
+
t7 = /* @__PURE__ */ jsxs(Button, {
|
|
691
|
+
type: "button",
|
|
692
|
+
variant: "ghost",
|
|
693
|
+
size: "icon",
|
|
694
|
+
className: "absolute top-2 right-2 z-10",
|
|
695
|
+
onClick: () => setOpened(void 0),
|
|
696
|
+
children: [/* @__PURE__ */ jsx(X, {}), /* @__PURE__ */ jsx("span", {
|
|
697
|
+
className: "sr-only",
|
|
698
|
+
children: "Close"
|
|
699
|
+
})]
|
|
700
|
+
});
|
|
701
|
+
$[8] = t7;
|
|
702
|
+
} else t7 = $[8];
|
|
703
|
+
let t8;
|
|
704
|
+
if ($[9] !== opened) {
|
|
705
|
+
t8 = opened && /* @__PURE__ */ jsx("div", {
|
|
706
|
+
className: "checkered absolute inset-0 flex items-center justify-center overflow-hidden p-6",
|
|
707
|
+
children: /* @__PURE__ */ jsx("img", {
|
|
708
|
+
src: opened.url,
|
|
709
|
+
alt: opened.filename,
|
|
710
|
+
className: "max-h-full max-w-full object-contain shadow-lg",
|
|
711
|
+
draggable: false
|
|
712
|
+
})
|
|
713
|
+
});
|
|
714
|
+
$[9] = opened;
|
|
715
|
+
$[10] = t8;
|
|
716
|
+
} else t8 = $[10];
|
|
717
|
+
let t9;
|
|
718
|
+
if ($[11] !== t6 || $[12] !== t8) {
|
|
719
|
+
t9 = /* @__PURE__ */ jsxs(DialogContent, {
|
|
720
|
+
className: "h-[90vh] max-h-[90vh] w-[90vw] max-w-[90vw] gap-0 overflow-hidden p-0 sm:max-w-[90vw]",
|
|
721
|
+
showCloseButton: false,
|
|
722
|
+
forceOverlay: true,
|
|
723
|
+
children: [
|
|
724
|
+
t6,
|
|
725
|
+
t7,
|
|
726
|
+
t8
|
|
727
|
+
]
|
|
728
|
+
});
|
|
729
|
+
$[11] = t6;
|
|
730
|
+
$[12] = t8;
|
|
731
|
+
$[13] = t9;
|
|
732
|
+
} else t9 = $[13];
|
|
733
|
+
let t10;
|
|
734
|
+
if ($[14] !== t3 || $[15] !== t9) {
|
|
735
|
+
t10 = /* @__PURE__ */ jsx(Dialog, {
|
|
736
|
+
open: t3,
|
|
737
|
+
onOpenChange: t4,
|
|
738
|
+
children: t9
|
|
739
|
+
});
|
|
740
|
+
$[14] = t3;
|
|
741
|
+
$[15] = t9;
|
|
742
|
+
$[16] = t10;
|
|
743
|
+
} else t10 = $[16];
|
|
744
|
+
let t11;
|
|
745
|
+
if ($[17] !== t10 || $[18] !== t2) {
|
|
746
|
+
t11 = /* @__PURE__ */ jsxs(Fragment, { children: [t2, t10] });
|
|
747
|
+
$[17] = t10;
|
|
748
|
+
$[18] = t2;
|
|
749
|
+
$[19] = t11;
|
|
750
|
+
} else t11 = $[19];
|
|
751
|
+
return t11;
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Context the agent was given beside the editors' requests, such as the Brief the agent on Live
|
|
755
|
+
* handed the request off with, or a Connected Agent's answers to its questions: a quiet line,
|
|
756
|
+
* `label`, so the requests read on as they were sent, which shows `text`, then `children`, once
|
|
757
|
+
* clicked.
|
|
758
|
+
*/
|
|
759
|
+
function CollapsedNote(t0) {
|
|
760
|
+
const $ = c(12);
|
|
761
|
+
const { label, hideLabel, title, text, children } = t0;
|
|
595
762
|
const [open, setOpen] = React.useState(false);
|
|
596
763
|
let t1;
|
|
597
764
|
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
598
765
|
t1 = () => setOpen(_temp2);
|
|
599
766
|
$[0] = t1;
|
|
600
767
|
} else t1 = $[0];
|
|
601
|
-
const t2 = open ?
|
|
768
|
+
const t2 = open ? hideLabel : label;
|
|
602
769
|
let t3;
|
|
603
|
-
if ($[1] !== open || $[2] !== t2) {
|
|
770
|
+
if ($[1] !== open || $[2] !== t2 || $[3] !== title) {
|
|
604
771
|
t3 = /* @__PURE__ */ jsx("button", {
|
|
605
772
|
type: "button",
|
|
606
773
|
"aria-expanded": open,
|
|
774
|
+
title,
|
|
607
775
|
onClick: t1,
|
|
608
776
|
className: "focus-visible:ring-ring self-start rounded-sm hover:underline focus-visible:ring-2 focus-visible:outline-none",
|
|
609
777
|
children: t2
|
|
610
778
|
});
|
|
611
779
|
$[1] = open;
|
|
612
780
|
$[2] = t2;
|
|
613
|
-
$[3] =
|
|
614
|
-
|
|
781
|
+
$[3] = title;
|
|
782
|
+
$[4] = t3;
|
|
783
|
+
} else t3 = $[4];
|
|
615
784
|
let t4;
|
|
616
|
-
if ($[
|
|
785
|
+
if ($[5] !== open || $[6] !== text) {
|
|
617
786
|
t4 = open && /* @__PURE__ */ jsx(Bubble, {
|
|
618
787
|
variant: "muted",
|
|
619
788
|
className: "max-w-full",
|
|
@@ -622,22 +791,28 @@ function BriefNote(t0) {
|
|
|
622
791
|
children: text
|
|
623
792
|
}) })
|
|
624
793
|
});
|
|
625
|
-
$[
|
|
626
|
-
$[
|
|
627
|
-
$[
|
|
628
|
-
} else t4 = $[
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
794
|
+
$[5] = open;
|
|
795
|
+
$[6] = text;
|
|
796
|
+
$[7] = t4;
|
|
797
|
+
} else t4 = $[7];
|
|
798
|
+
const t5 = open && children;
|
|
799
|
+
let t6;
|
|
800
|
+
if ($[8] !== t3 || $[9] !== t4 || $[10] !== t5) {
|
|
801
|
+
t6 = /* @__PURE__ */ jsxs("div", {
|
|
802
|
+
"data-thread-collapsed": true,
|
|
633
803
|
className: "text-muted-foreground flex flex-col gap-2 text-xs",
|
|
634
|
-
children: [
|
|
804
|
+
children: [
|
|
805
|
+
t3,
|
|
806
|
+
t4,
|
|
807
|
+
t5
|
|
808
|
+
]
|
|
635
809
|
});
|
|
636
|
-
$[
|
|
637
|
-
$[
|
|
638
|
-
$[
|
|
639
|
-
|
|
640
|
-
|
|
810
|
+
$[8] = t3;
|
|
811
|
+
$[9] = t4;
|
|
812
|
+
$[10] = t5;
|
|
813
|
+
$[11] = t6;
|
|
814
|
+
} else t6 = $[11];
|
|
815
|
+
return t6;
|
|
641
816
|
}
|
|
642
817
|
function _temp2(current) {
|
|
643
818
|
return !current;
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { findingSentence, findingSentenceInPlace } from "@camox/api-contract/
|
|
1
|
+
import { fixMessage, whereSentence } from "./fixMessage.js";
|
|
2
|
+
import { findingSentence, findingSentenceInPlace } from "@camox/api-contract/specialists";
|
|
3
3
|
|
|
4
4
|
//#region src/features/studio/findingSentence.ts
|
|
5
|
-
/**
|
|
6
|
-
const quoted = (text) => `“${text}”`;
|
|
7
|
-
/** What a dismissal dismissed, briefly: "Links to About". */
|
|
5
|
+
/** What a dismissal dismissed, briefly: "Links to About", or "No meta title". */
|
|
8
6
|
function dismissedSentence(about) {
|
|
9
7
|
switch (about.kind) {
|
|
10
8
|
case "missingPage": return `Links to ${about.page ?? "a missing page"}`;
|
|
11
9
|
case "brokenLink": return `Links to ${about.url}`;
|
|
10
|
+
case "missingMetaTitle": return "No meta title";
|
|
12
11
|
}
|
|
13
12
|
}
|
|
14
13
|
/** What dismissing a finding says, as its button says it: a broken link's is "This link is fine". */
|
|
@@ -22,14 +21,17 @@ function fixLabel(fix) {
|
|
|
22
21
|
}
|
|
23
22
|
}
|
|
24
23
|
/**
|
|
25
|
-
* What
|
|
26
|
-
* suggests, for the agent to find among the
|
|
24
|
+
* What Fix with agent sends to the chat of what the studio views: who found what, where, and the
|
|
25
|
+
* fix it suggests, for the agent to find among the findings it sees and fix.
|
|
27
26
|
*/
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
function fixWithAgentMessage(finding, role) {
|
|
28
|
+
return fixMessage({
|
|
29
|
+
from: `${role} finding`,
|
|
30
|
+
what: findingSentence(finding),
|
|
31
|
+
places: [whereSentence(finding)],
|
|
32
|
+
fix: finding.fix ? fixLabel(finding.fix) : void 0
|
|
33
|
+
});
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
//#endregion
|
|
35
|
-
export {
|
|
37
|
+
export { dismissLabel, dismissedSentence, findingSentence, findingSentenceInPlace, fixLabel, fixWithAgentMessage };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { localeName } from "./localeOptions.js";
|
|
2
|
+
|
|
3
|
+
//#region src/features/studio/fixMessage.ts
|
|
4
|
+
/** Quoted as editors read it. */
|
|
5
|
+
const quoted = (text) => `“${text}”`;
|
|
6
|
+
/** Where something is in content, in a sentence: "Hero on Home, in German, field “image”". */
|
|
7
|
+
function whereSentence({ label, locale, field }) {
|
|
8
|
+
return [
|
|
9
|
+
label,
|
|
10
|
+
locale && `in ${localeName(locale)}`,
|
|
11
|
+
field && `field ${quoted(field)}`
|
|
12
|
+
].filter(Boolean).join(", ");
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The message: "Link checker finding: … (in French, field “body”). Suggested fix: Remove the
|
|
16
|
+
* link." Each of `places` is a `whereSentence`.
|
|
17
|
+
*/
|
|
18
|
+
function fixMessage({ from, what, places = [], fix }) {
|
|
19
|
+
return `${from}: ${what}${places.length > 0 ? ` (${places.join("; ")})` : ""}.${fix ? ` Suggested fix: ${fix}.` : ""}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
export { fixMessage, quoted, whereSentence };
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
//#region src/features/studio/
|
|
2
|
-
/** What each
|
|
1
|
+
//#region src/features/studio/specialistBio.ts
|
|
2
|
+
/** What each specialist does, wherever it works. */
|
|
3
3
|
const ABOUT = {
|
|
4
4
|
seoManager: "Writes what search engines read: each page's SEO, and each file's alt text and filename.",
|
|
5
5
|
translator: "Translates your website from its default language into every other one, so that each stays complete.",
|
|
6
6
|
linkChecker: "Looks for links that lead nowhere, to your own pages or elsewhere, and suggests a fix when it can."
|
|
7
7
|
};
|
|
8
|
-
/** What a
|
|
8
|
+
/** What a specialist does, as its profile card introduces it. */
|
|
9
9
|
function aboutSentence(id) {
|
|
10
10
|
return ABOUT[id];
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* When a
|
|
13
|
+
* When a specialist works where the editor is, by its duty there, in a draft or on Live, as its
|
|
14
14
|
* card's tag says it, and whether it runs there at all. In a project with a single locale, the
|
|
15
15
|
* Translator waits for a second one.
|
|
16
16
|
*/
|
|
@@ -23,12 +23,15 @@ function whenTag(id, duty, inDraft, singleLocale) {
|
|
|
23
23
|
label: "Runs once you add a language",
|
|
24
24
|
runs: false
|
|
25
25
|
};
|
|
26
|
-
if (duty === "atPublish") return runs("Runs when you publish");
|
|
27
26
|
if (duty === "asYouGo") {
|
|
28
27
|
if (inDraft) return runs("Runs as you edit");
|
|
29
28
|
if (id === "linkChecker") return runs("Runs every 6 hours");
|
|
30
29
|
return runs("Runs while a release is translated");
|
|
31
30
|
}
|
|
31
|
+
if (inDraft) return {
|
|
32
|
+
label: "Runs on Live only",
|
|
33
|
+
runs: false
|
|
34
|
+
};
|
|
32
35
|
return {
|
|
33
36
|
label: "Doesn't run on Live",
|
|
34
37
|
runs: false
|
|
@@ -5,12 +5,13 @@ const studioStore = createStore({
|
|
|
5
5
|
context: {
|
|
6
6
|
isCommandPaletteOpen: false,
|
|
7
7
|
commandPalettePages: [],
|
|
8
|
-
|
|
8
|
+
isReviewDraftDialogOpen: false,
|
|
9
9
|
isDeleteDraftDialogOpen: false,
|
|
10
10
|
localeDialog: null,
|
|
11
11
|
websiteLocation: null,
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
agentMessages: [],
|
|
13
|
+
agentMessagesSent: 0,
|
|
14
|
+
agentWorkingIn: null
|
|
14
15
|
},
|
|
15
16
|
on: {
|
|
16
17
|
openCommandPalette: (context) => {
|
|
@@ -45,16 +46,16 @@ const studioStore = createStore({
|
|
|
45
46
|
commandPalettePages: context.commandPalettePages.slice(0, -1)
|
|
46
47
|
};
|
|
47
48
|
},
|
|
48
|
-
|
|
49
|
+
openReviewDraftDialog: (context) => {
|
|
49
50
|
return {
|
|
50
51
|
...context,
|
|
51
|
-
|
|
52
|
+
isReviewDraftDialogOpen: true
|
|
52
53
|
};
|
|
53
54
|
},
|
|
54
|
-
|
|
55
|
+
closeReviewDraftDialog: (context) => {
|
|
55
56
|
return {
|
|
56
57
|
...context,
|
|
57
|
-
|
|
58
|
+
isReviewDraftDialogOpen: false
|
|
58
59
|
};
|
|
59
60
|
},
|
|
60
61
|
openDeleteDraftDialog: (context) => {
|
|
@@ -81,21 +82,34 @@ const studioStore = createStore({
|
|
|
81
82
|
localeDialog: null
|
|
82
83
|
};
|
|
83
84
|
},
|
|
84
|
-
|
|
85
|
+
sendToAgent: (context, event) => {
|
|
86
|
+
const id = context.agentMessagesSent + 1;
|
|
85
87
|
return {
|
|
86
88
|
...context,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
isReviewDraftDialogOpen: false,
|
|
90
|
+
agentMessages: [...context.agentMessages, {
|
|
89
91
|
text: event.text,
|
|
90
|
-
id
|
|
91
|
-
},
|
|
92
|
-
|
|
92
|
+
id
|
|
93
|
+
}],
|
|
94
|
+
agentMessagesSent: id
|
|
93
95
|
};
|
|
94
96
|
},
|
|
95
|
-
|
|
97
|
+
takeAgentMessage: (context, event) => {
|
|
98
|
+
if (!context.agentMessages.some((message) => message.id === event.id)) return context;
|
|
96
99
|
return {
|
|
97
100
|
...context,
|
|
98
|
-
|
|
101
|
+
agentMessages: context.agentMessages.filter((message) => message.id !== event.id)
|
|
102
|
+
};
|
|
103
|
+
},
|
|
104
|
+
agentWorking: (context, event) => {
|
|
105
|
+
if (event.working) return {
|
|
106
|
+
...context,
|
|
107
|
+
agentWorkingIn: event.draftId
|
|
108
|
+
};
|
|
109
|
+
if (context.agentWorkingIn !== event.draftId) return context;
|
|
110
|
+
return {
|
|
111
|
+
...context,
|
|
112
|
+
agentWorkingIn: null
|
|
99
113
|
};
|
|
100
114
|
},
|
|
101
115
|
rememberWebsiteLocation: (context, event) => {
|
|
@@ -35,7 +35,7 @@ function inLocales(locales, preposition) {
|
|
|
35
35
|
return listed(parts);
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
38
|
-
* What a
|
|
38
|
+
* What a specialist is working on: "Translating hero into Spanish" for one subject, "Translating
|
|
39
39
|
* 38 items into German and 12 into Spanish" for a burst, counted in each locale.
|
|
40
40
|
*/
|
|
41
41
|
function workingSentence(id, working) {
|
package/dist/lib/api-client.js
CHANGED
|
@@ -61,6 +61,10 @@ function createStudioClient(apiUrl, draftHeaders) {
|
|
|
61
61
|
});
|
|
62
62
|
return createORPCClient(link);
|
|
63
63
|
}
|
|
64
|
+
function getApiClient() {
|
|
65
|
+
if (!_client) throw new Error("API client not initialized — call initApiClient first");
|
|
66
|
+
return _client;
|
|
67
|
+
}
|
|
64
68
|
function getOrpc() {
|
|
65
69
|
if (!_orpc) throw new Error("API client not initialized — call initApiClient first");
|
|
66
70
|
return _orpc;
|
|
@@ -79,4 +83,4 @@ function getContentWriteHeaders() {
|
|
|
79
83
|
}
|
|
80
84
|
|
|
81
85
|
//#endregion
|
|
82
|
-
export { getApiUrl, getContentWriteHeaders, getDraftReadClient, getOrpc, initApiClient };
|
|
86
|
+
export { getApiClient, getApiUrl, getContentWriteHeaders, getDraftReadClient, getOrpc, initApiClient };
|
package/dist/lib/queries.js
CHANGED
|
@@ -51,12 +51,12 @@ const draftMutations = {
|
|
|
51
51
|
revertToLive: () => getOrpc().drafts.revertToLive.mutationOptions()
|
|
52
52
|
};
|
|
53
53
|
/**
|
|
54
|
-
* What members do with a
|
|
54
|
+
* What members do with a specialist's finding (ADR 0034): apply its fix in the draft viewed, or
|
|
55
55
|
* dismiss it for the whole project.
|
|
56
56
|
*/
|
|
57
|
-
const
|
|
58
|
-
applyFix: () => getOrpc().
|
|
59
|
-
dismissFinding: () => getOrpc().
|
|
57
|
+
const specialistMutations = {
|
|
58
|
+
applyFix: () => getOrpc().specialists.applyFix.mutationOptions(),
|
|
59
|
+
dismissFinding: () => getOrpc().specialists.dismissFinding.mutationOptions()
|
|
60
60
|
};
|
|
61
61
|
/** Adding and removing locales: content writes, so on Live they start a draft (ADR 0015). */
|
|
62
62
|
const localeMutations = {
|
|
@@ -138,4 +138,4 @@ const fileMutations = {
|
|
|
138
138
|
};
|
|
139
139
|
|
|
140
140
|
//#endregion
|
|
141
|
-
export { blockMutations, collectionMutations, draftMutations, fileMutations, localeMutations, pageMutations,
|
|
141
|
+
export { blockMutations, collectionMutations, draftMutations, fileMutations, localeMutations, pageMutations, projectMutations, repeatableItemMutations, specialistMutations };
|
|
@@ -6,7 +6,7 @@ import { ApiClient } from "./api-client.js";
|
|
|
6
6
|
import "./queries.js";
|
|
7
7
|
import "react";
|
|
8
8
|
import "@camox/api-contract/query-keys";
|
|
9
|
-
import "@camox/api-contract/
|
|
9
|
+
import "@camox/api-contract/specialists";
|
|
10
10
|
import { QueryClient } from "@tanstack/react-query";
|
|
11
11
|
//#region src/lib/studio-reads.d.ts
|
|
12
12
|
type LayoutRead = Awaited<ReturnType<ApiClient["layouts"]["get"]>>;
|