@nivaro/react 0.3.40 → 0.3.42

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 (99) hide show
  1. package/dist/components/LayoutForm.js +100 -98
  2. package/dist/full.css +1 -1
  3. package/dist/hooks/useSessionRecorder.js +1 -1
  4. package/dist/index.d.ts +645 -16
  5. package/dist/index.js +814 -775
  6. package/dist/shared/components/ActivityEntry.js +154 -0
  7. package/dist/shared/components/AudienceConfirmPanel.js +98 -0
  8. package/dist/shared/components/BackgroundRunOffer.js +43 -31
  9. package/dist/shared/components/BroadcastView.js +225 -204
  10. package/dist/shared/components/CollectionBrowserView.js +3924 -3584
  11. package/dist/shared/components/ConfigHistory.js +153 -0
  12. package/dist/shared/components/ConfigReadBack.js +65 -0
  13. package/dist/shared/components/DataTable.js +379 -346
  14. package/dist/shared/components/ForceReloadBanner.js +47 -40
  15. package/dist/shared/components/IdleReloadWatcher.js +69 -0
  16. package/dist/shared/components/ItemEditForm.js +4041 -3853
  17. package/dist/shared/components/MyWorkView.js +278 -213
  18. package/dist/shared/components/NotificationBell.js +130 -121
  19. package/dist/shared/components/PickerExcludedRows.js +3 -3
  20. package/dist/shared/components/ProfileView.js +776 -1003
  21. package/dist/shared/components/RecentRecordsRail.js +34 -16
  22. package/dist/shared/components/RecordReadView.js +500 -477
  23. package/dist/shared/components/Skeletons.js +199 -0
  24. package/dist/shared/components/SlowNotice.js +63 -0
  25. package/dist/shared/components/Term.js +23 -0
  26. package/dist/shared/components/WidgetSlot.js +350 -353
  27. package/dist/shared/components/access/PermissionSummary.js +106 -0
  28. package/dist/shared/components/bulk/BulkActionButtons.js +76 -73
  29. package/dist/shared/components/chat/ChatPanel.js +902 -886
  30. package/dist/shared/components/chat/MemberPaging.js +70 -0
  31. package/dist/shared/components/chat/RoomParts.js +147 -117
  32. package/dist/shared/components/chat/ScreenClip.js +73 -69
  33. package/dist/shared/components/chat/chat-core.js +449 -396
  34. package/dist/shared/components/chat/huddle/huddle-store.js +48 -43
  35. package/dist/shared/components/help-videos/api.js +2 -5
  36. package/dist/shared/components/help-videos/viewer/HelpVideoMatchChip.js +79 -0
  37. package/dist/shared/components/help-videos/viewer/matchChip.js +50 -0
  38. package/dist/shared/components/imports/CollectionImportPanel.js +139 -133
  39. package/dist/shared/components/imports/RunDetailSheet.js +222 -227
  40. package/dist/shared/components/integrations/console/ErrorExplanation.js +121 -0
  41. package/dist/shared/components/integrations/console/PartnerDetail.js +175 -174
  42. package/dist/shared/components/integrations/console/SubmissionRow.js +36 -34
  43. package/dist/shared/components/integrations/console/drill/SubmissionDrill.js +50 -48
  44. package/dist/shared/components/item-edit/FieldComments.js +212 -0
  45. package/dist/shared/components/item-edit/FieldRow.js +340 -336
  46. package/dist/shared/components/item-edit/RecordGrantTools.js +28 -28
  47. package/dist/shared/components/item-edit/RecordHeaderActions.js +23 -22
  48. package/dist/shared/components/item-edit/RelationCombobox.js +231 -222
  49. package/dist/shared/components/item-edit/RuleHiddenNotes.js +55 -0
  50. package/dist/shared/components/item-edit/field-comments-context.js +6 -0
  51. package/dist/shared/components/item-edit/field-sources.js +33 -0
  52. package/dist/shared/components/item-edit/rule-hidden.js +30 -0
  53. package/dist/shared/components/layout-editor/HistoryPanel.js +113 -96
  54. package/dist/shared/components/layout-editor/editors/cascade-filters.js +170 -145
  55. package/dist/shared/components/layout-editor/inspector/Breadcrumb.js +22 -18
  56. package/dist/shared/components/layout-editor/inspector/GroupInspector.js +177 -159
  57. package/dist/shared/components/layout-editor/inspector/PickerTab.js +35 -34
  58. package/dist/shared/components/layout-editor/inspector/RulesTab.js +124 -111
  59. package/dist/shared/components/layout-editor/inspector/kit.js +292 -277
  60. package/dist/shared/components/layout-editor/parity-keys.json.js +1 -1
  61. package/dist/shared/components/layout-editor/settings/settings-registry.js +1 -1
  62. package/dist/shared/components/list/CopyListLinkButton.js +41 -0
  63. package/dist/shared/components/list/InlineEdit.js +363 -0
  64. package/dist/shared/components/notifications/NotificationCenterView.js +213 -181
  65. package/dist/shared/components/notifications/NotificationDetailBits.js +205 -82
  66. package/dist/shared/components/notifications/NotificationRulesEditor.js +515 -0
  67. package/dist/shared/components/notifications/TestMyRules.js +137 -0
  68. package/dist/shared/components/notifications/changes-lines.js +24 -0
  69. package/dist/shared/components/notifications/why-lines.js +64 -0
  70. package/dist/shared/components/panels/CommentPanel.js +316 -281
  71. package/dist/shared/components/panels/LegalHoldBanner.js +38 -0
  72. package/dist/shared/components/panels/PipelinePanel.js +201 -196
  73. package/dist/shared/components/panels/RevisionsPanel.js +496 -479
  74. package/dist/shared/components/pipeline/PipelineEditorView.js +1587 -1560
  75. package/dist/shared/components/pipeline/PipelineStateOwners.js +116 -103
  76. package/dist/shared/components/profile/PersonDidPanel.js +188 -0
  77. package/dist/shared/components/profile/PersonProfile.js +57 -52
  78. package/dist/shared/components/queue/QueueWorklist.js +1526 -1365
  79. package/dist/shared/hooks/useSlowReason.js +39 -0
  80. package/dist/shared/lib/activity-sentence.js +670 -0
  81. package/dist/shared/lib/config-sentences.js +418 -0
  82. package/dist/shared/lib/core-glossary.js +229 -0
  83. package/dist/shared/lib/error-hints.js +159 -0
  84. package/dist/shared/lib/error-message.js +105 -0
  85. package/dist/shared/lib/error-toast.js +22 -0
  86. package/dist/shared/lib/field-comments.js +25 -0
  87. package/dist/shared/lib/filter-sentence.js +261 -0
  88. package/dist/shared/lib/glossary.js +55 -48
  89. package/dist/shared/lib/idle-reload.js +138 -0
  90. package/dist/shared/lib/layout-resolve.js +42 -29
  91. package/dist/shared/lib/list-inline-edit.js +190 -0
  92. package/dist/shared/lib/list-link.js +147 -0
  93. package/dist/shared/lib/prefetch.js +259 -106
  94. package/dist/shared/lib/record-ref.js +72 -0
  95. package/dist/shared/lib/reload-holds.js +25 -0
  96. package/dist/shared/lib/safe-error.js +52 -24
  97. package/dist/shared/lib/skeleton-shapes.js +72 -0
  98. package/dist/shared/lib/slow-reason.js +63 -0
  99. package/package.json +1 -1
@@ -1,22 +1,23 @@
1
1
  import { jsxs as a, jsx as t } from "react/jsx-runtime";
2
- import { ChevronDown as x, Loader2 as h, RefreshCw as f } from "lucide-react";
3
- import { useState as k } from "react";
4
- import { formatRelative as _, cn as y, titleCase as N } from "../../../lib/utils.js";
5
- import { Button as g } from "../../ui/button.js";
6
- import { AttemptHistory as w } from "./drill/attempts.js";
7
- import { pretty as d, CodeBlock as o } from "./drill/json.js";
8
- import { StatusPill as v } from "./drill/status.js";
9
- function u(e, r) {
10
- return `${N(e).replace(/s$/, "")} · ${r}`;
2
+ import { ChevronDown as h, Loader2 as f, RefreshCw as k } from "lucide-react";
3
+ import { useState as _ } from "react";
4
+ import { formatRelative as y, cn as N, titleCase as w } from "../../../lib/utils.js";
5
+ import { Button as v } from "../../ui/button.js";
6
+ import { AttemptHistory as g } from "./drill/attempts.js";
7
+ import { pretty as i, CodeBlock as s } from "./drill/json.js";
8
+ import { StatusPill as L } from "./drill/status.js";
9
+ import { ErrorExplanation as d } from "./ErrorExplanation.js";
10
+ function C(e, n) {
11
+ return `${w(e).replace(/s$/, "")} · ${n}`;
11
12
  }
12
- function j({
13
+ function q({
13
14
  sub: e,
14
- onRetry: r,
15
- retrying: n,
16
- onShowPath: s,
17
- initialOpen: i = !1
15
+ onRetry: n,
16
+ retrying: l,
17
+ onShowPath: o,
18
+ initialOpen: p = !1
18
19
  }) {
19
- const [l, p] = k(i), m = d(e.payload), c = d(e.response);
20
+ const [r, m] = _(p), c = i(e.payload), x = i(e.response);
20
21
  return /* @__PURE__ */ a(
21
22
  "div",
22
23
  {
@@ -28,10 +29,10 @@ function j({
28
29
  "button",
29
30
  {
30
31
  type: "button",
31
- onClick: () => p(!l),
32
+ onClick: () => m(!r),
32
33
  className: "flex min-w-0 flex-1 items-center gap-3 px-3 py-2 text-left",
33
34
  children: [
34
- /* @__PURE__ */ t(v, { status: e.status }),
35
+ /* @__PURE__ */ t(L, { status: e.status }),
35
36
  e.external_api_name && /* @__PURE__ */ t("span", { className: "shrink-0 text-[11.5px] font-semibold text-slate-700 dark:text-slate-200", children: e.external_api_name }),
36
37
  /* @__PURE__ */ t("span", { className: "min-w-0 flex-1 truncate font-mono text-[11.5px] text-slate-500 dark:text-slate-400", children: e.endpoint_path ?? "—" }),
37
38
  e.record_label && /* @__PURE__ */ t(
@@ -39,7 +40,7 @@ function j({
39
40
  {
40
41
  className: "shrink-0 rounded bg-slate-100 px-1.5 py-0.5 text-[10.5px] font-medium text-slate-600 dark:bg-muted dark:text-slate-300",
41
42
  "data-tip": `${e.collection}/${e.item}`,
42
- children: u(e.collection, e.record_label)
43
+ children: C(e.collection, e.record_label)
43
44
  }
44
45
  ),
45
46
  e.external_ref && /* @__PURE__ */ t("span", { className: "shrink-0 rounded bg-slate-100 px-1.5 py-0.5 font-mono text-[10.5px] text-slate-600 dark:bg-muted dark:text-slate-300", children: e.external_ref }),
@@ -48,7 +49,7 @@ function j({
48
49
  {
49
50
  className: "shrink-0 text-[11px] text-slate-400",
50
51
  title: new Date(e.updated_at).toLocaleString(),
51
- children: _(e.updated_at)
52
+ children: y(e.updated_at)
52
53
  }
53
54
  ),
54
55
  e.attempts > 1 && /* @__PURE__ */ a("span", { className: "shrink-0 text-[10.5px] text-slate-400", children: [
@@ -56,22 +57,22 @@ function j({
56
57
  e.attempts
57
58
  ] }),
58
59
  /* @__PURE__ */ t(
59
- x,
60
+ h,
60
61
  {
61
- className: y(
62
+ className: N(
62
63
  "h-3.5 w-3.5 shrink-0 text-slate-400 transition-transform",
63
- l && "rotate-180"
64
+ r && "rotate-180"
64
65
  )
65
66
  }
66
67
  )
67
68
  ]
68
69
  }
69
70
  ),
70
- s && /* @__PURE__ */ t(
71
+ o && /* @__PURE__ */ t(
71
72
  "button",
72
73
  {
73
74
  type: "button",
74
- onClick: () => s(e.id),
75
+ onClick: () => o(e.id),
75
76
  className: "mr-2 shrink-0 rounded px-1.5 py-0.5 text-[11px] font-medium text-nvr-navy underline-offset-2 hover:underline dark:text-nvr-cyan",
76
77
  "data-submission-show-path": e.id,
77
78
  "data-tip": "Everything that led to this push and what came back",
@@ -79,7 +80,8 @@ function j({
79
80
  }
80
81
  )
81
82
  ] }),
82
- l && /* @__PURE__ */ a("div", { className: "space-y-2 border-t border-slate-100 px-3 py-2.5 dark:border-border", children: [
83
+ !r && e.explanation && /* @__PURE__ */ t("div", { className: "-mt-1 px-3 pb-2", children: /* @__PURE__ */ t(d, { explanation: e.explanation, compact: !0 }) }),
84
+ r && /* @__PURE__ */ a("div", { className: "space-y-2 border-t border-slate-100 px-3 py-2.5 dark:border-border", children: [
83
85
  /* @__PURE__ */ a("div", { className: "grid grid-cols-2 gap-x-4 gap-y-1 text-[11.5px] text-slate-500 dark:text-slate-400", children: [
84
86
  /* @__PURE__ */ a("span", { children: [
85
87
  "Sent: ",
@@ -99,18 +101,18 @@ function j({
99
101
  e.external_api_name ?? (e.external_api != null ? `#${e.external_api}` : "—")
100
102
  ] })
101
103
  ] }),
102
- e.last_error && /* @__PURE__ */ t("p", { className: "rounded bg-red-50 px-2 py-1.5 text-[11.5px] text-red-700 dark:bg-red-500/10 dark:text-red-400", children: e.last_error }),
104
+ e.last_error && /* @__PURE__ */ t(d, { explanation: e.explanation, raw: e.last_error }),
103
105
  /* @__PURE__ */ t(
104
- o,
106
+ s,
105
107
  {
106
108
  label: e.attempts > 1 ? "Latest request" : "Request payload",
107
- value: m
109
+ value: c
108
110
  }
109
111
  ),
110
- /* @__PURE__ */ t(o, { label: e.attempts > 1 ? "Latest response" : "Response", value: c }),
111
- e.attempts > 1 && /* @__PURE__ */ t(w, { submissionId: e.id }),
112
- e.status === "failed" && /* @__PURE__ */ a(g, { size: "sm", variant: "outline", disabled: n, onClick: () => r(e.id), children: [
113
- n ? /* @__PURE__ */ t(h, { className: "h-3 w-3 animate-spin" }) : /* @__PURE__ */ t(f, { className: "h-3 w-3" }),
112
+ /* @__PURE__ */ t(s, { label: e.attempts > 1 ? "Latest response" : "Response", value: x }),
113
+ e.attempts > 1 && /* @__PURE__ */ t(g, { submissionId: e.id }),
114
+ e.status === "failed" && /* @__PURE__ */ a(v, { size: "sm", variant: "outline", disabled: l, onClick: () => n(e.id), children: [
115
+ l ? /* @__PURE__ */ t(f, { className: "h-3 w-3 animate-spin" }) : /* @__PURE__ */ t(k, { className: "h-3 w-3" }),
114
116
  /* @__PURE__ */ t("span", { className: "ml-1.5", children: "Retry" })
115
117
  ] })
116
118
  ] })
@@ -119,6 +121,6 @@ function j({
119
121
  );
120
122
  }
121
123
  export {
122
- v as StatusPill,
123
- j as SubmissionRow
124
+ L as StatusPill,
125
+ q as SubmissionRow
124
126
  };
@@ -4,22 +4,23 @@ import { useMemo as W } from "react";
4
4
  import { useNavigation as L } from "../../../../context.js";
5
5
  import { cn as m, titleCase as A } from "../../../../lib/utils.js";
6
6
  import { useSubmissionDetail as F, useRetrySubmission as M } from "../api.js";
7
+ import { ErrorExplanation as j } from "../ErrorExplanation.js";
7
8
  import { TONE_TEXT as d, TONE_SOFT as w, agoText as C, exactTime as y } from "../tone.js";
8
- import { AttemptHistory as j } from "./attempts.js";
9
- import { CodeBlock as q, pretty as S } from "./json.js";
10
- import { RequesterChip as T } from "./requester.js";
11
- import { StatusPill as B } from "./status.js";
12
- function z() {
9
+ import { AttemptHistory as B } from "./attempts.js";
10
+ import { CodeBlock as q, pretty as E } from "./json.js";
11
+ import { RequesterChip as S } from "./requester.js";
12
+ import { StatusPill as z } from "./status.js";
13
+ function H() {
13
14
  const t = L();
14
15
  return (i) => i ? t.consoleUrl ? t.consoleUrl(i) : i : null;
15
16
  }
16
- function E(t, i) {
17
+ function T(t, i) {
17
18
  /^https?:/.test(i) ? window.open(i, "_blank", "noopener") : t.navigate(i);
18
19
  }
19
- function x({ name: t, title: i, children: l }) {
20
+ function h({ name: t, title: i, children: o }) {
20
21
  return /* @__PURE__ */ n("section", { "data-ic-drill-section": t, className: "min-w-0", children: [
21
22
  /* @__PURE__ */ e("h4", { className: "mb-1.5 text-[12px] font-semibold text-foreground", children: i }),
22
- l
23
+ o
23
24
  ] });
24
25
  }
25
26
  function b({ label: t, children: i }) {
@@ -31,11 +32,11 @@ function b({ label: t, children: i }) {
31
32
  function N() {
32
33
  return /* @__PURE__ */ e("span", { "aria-hidden": !0, className: "text-muted-foreground", children: "·" });
33
34
  }
34
- function H(t, i) {
35
- var l, c, o, u;
36
- return (l = t.user) != null && l.id || (c = i.user) != null && c.id ? ((o = t.user) == null ? void 0 : o.id) === ((u = i.user) == null ? void 0 : u.id) : t.kind === i.kind && t.label === i.label;
35
+ function I(t, i) {
36
+ var o, c, l, u;
37
+ return (o = t.user) != null && o.id || (c = i.user) != null && c.id ? ((l = t.user) == null ? void 0 : l.id) === ((u = i.user) == null ? void 0 : u.id) : t.kind === i.kind && t.label === i.label;
37
38
  }
38
- const I = {
39
+ const X = {
39
40
  transient: "Temporary failure",
40
41
  rate_limited: "Rate limited",
41
42
  auth: "Credentials refused",
@@ -51,7 +52,7 @@ const I = {
51
52
  skipped: "neutral",
52
53
  superseded: "neutral"
53
54
  };
54
- function X() {
55
+ function G() {
55
56
  return /* @__PURE__ */ n("div", { className: "space-y-2.5", "aria-busy": !0, children: [
56
57
  [72, 96, 60, 84].map((t) => /* @__PURE__ */ e(
57
58
  "div",
@@ -64,11 +65,11 @@ function X() {
64
65
  /* @__PURE__ */ e("div", { className: "h-16 animate-pulse rounded-md bg-[hsl(var(--nvr-skeleton))]" })
65
66
  ] });
66
67
  }
67
- function ie({ id: t, onOpenRecord: i, onRetry: l, retryBusy: c }) {
68
- var g, f, h;
69
- const { data: o, isLoading: u, isError: v, error: r } = F(t), p = M();
70
- if (u) return /* @__PURE__ */ e(X, {});
71
- if (v || !o) {
68
+ function oe({ id: t, onOpenRecord: i, onRetry: o, retryBusy: c }) {
69
+ var g, f, x;
70
+ const { data: l, isLoading: u, isError: v, error: r } = F(t), p = M();
71
+ if (u) return /* @__PURE__ */ e(G, {});
72
+ if (v || !l) {
72
73
  const s = ((g = r == null ? void 0 : r.response) == null ? void 0 : g.error) ?? (r instanceof Error ? r.message : null);
73
74
  return /* @__PURE__ */ n("p", { className: m("rounded-md px-3 py-2 text-[12px]", w.negative, d.negative), children: [
74
75
  "Couldn't load this push",
@@ -77,28 +78,28 @@ function ie({ id: t, onOpenRecord: i, onRetry: l, retryBusy: c }) {
77
78
  ] });
78
79
  }
79
80
  return /* @__PURE__ */ e(
80
- G,
81
+ J,
81
82
  {
82
- d: o,
83
+ d: l,
83
84
  onOpenRecord: i,
84
- onRetry: l ?? (() => p.mutate(t)),
85
- retryBusy: l ? !!c : p.isPending,
86
- retryError: l ? null : p.isError ? ((h = (f = p.error) == null ? void 0 : f.response) == null ? void 0 : h.error) ?? "The retry failed" : null
85
+ onRetry: o ?? (() => p.mutate(t)),
86
+ retryBusy: o ? !!c : p.isPending,
87
+ retryError: o ? null : p.isError ? ((x = (f = p.error) == null ? void 0 : f.response) == null ? void 0 : x.error) ?? "The retry failed" : null
87
88
  }
88
89
  );
89
90
  }
90
- function G({
91
+ function J({
91
92
  d: t,
92
93
  onOpenRecord: i,
93
- onRetry: l,
94
+ onRetry: o,
94
95
  retryBusy: c,
95
- retryError: o
96
+ retryError: l
96
97
  }) {
97
- const u = L(), v = z(), r = t.submission, p = W(
98
+ const u = L(), v = H(), r = t.submission, p = W(
98
99
  () => new Map(t.attempt_requesters.map((a) => [a.attempt, a.requester])),
99
100
  [t.attempt_requesters]
100
- ), g = A(r.collection).replace(/s$/, ""), f = v(t.trigger.link), h = t.partner.id != null ? v(`/external-apis/${t.partner.id}`) : null, s = t.obligation, k = t.attempt_requesters.filter(
101
- (a) => a.attempt > 1 && a.requester.kind !== "unknown" && !H(a.requester, t.triggered_by)
101
+ ), g = A(r.collection).replace(/s$/, ""), f = v(t.trigger.link), x = t.partner.id != null ? v(`/external-apis/${t.partner.id}`) : null, s = t.obligation, k = t.attempt_requesters.filter(
102
+ (a) => a.attempt > 1 && a.requester.kind !== "unknown" && !I(a.requester, t.triggered_by)
102
103
  );
103
104
  return /* @__PURE__ */ n("div", { className: "space-y-4", "data-ic-drill": `submission:${r.id}`, children: [
104
105
  /* @__PURE__ */ n(
@@ -135,7 +136,7 @@ function G({
135
136
  r.record_label
136
137
  ] }),
137
138
  /* @__PURE__ */ e(N, {}),
138
- /* @__PURE__ */ e(B, { status: r.status }),
139
+ /* @__PURE__ */ e(z, { status: r.status }),
139
140
  r.error_class && /* @__PURE__ */ e(
140
141
  "span",
141
142
  {
@@ -145,7 +146,7 @@ function G({
145
146
  d.warning
146
147
  ),
147
148
  "data-tip": `Error class: ${r.error_class}`,
148
- children: I[r.error_class] ?? r.error_class
149
+ children: X[r.error_class] ?? r.error_class
149
150
  }
150
151
  ),
151
152
  /* @__PURE__ */ e(N, {}),
@@ -169,8 +170,9 @@ function G({
169
170
  ]
170
171
  }
171
172
  ),
172
- (r.last_error || (s == null ? void 0 : s.reason)) && /* @__PURE__ */ n(x, { name: "error", title: "What went wrong", children: [
173
- r.last_error && /* @__PURE__ */ e(
173
+ (r.last_error || (s == null ? void 0 : s.reason)) && /* @__PURE__ */ n(h, { name: "error", title: "What went wrong", children: [
174
+ r.last_error && r.explanation && /* @__PURE__ */ e(j, { explanation: r.explanation, raw: r.last_error }),
175
+ r.last_error && !r.explanation && /* @__PURE__ */ e(
174
176
  "p",
175
177
  {
176
178
  className: m(
@@ -187,26 +189,26 @@ function G({
187
189
  s.reason
188
190
  ] })
189
191
  ] }),
190
- /* @__PURE__ */ e(x, { name: "attempts", title: "Attempts", children: /* @__PURE__ */ e(j, { submissionId: r.id, requesters: p, title: null }) }),
192
+ /* @__PURE__ */ e(h, { name: "attempts", title: "Attempts", children: /* @__PURE__ */ e(B, { submissionId: r.id, requesters: p, title: null }) }),
191
193
  /* @__PURE__ */ e(
192
- x,
194
+ h,
193
195
  {
194
196
  name: "bodies",
195
197
  title: r.attempts > 1 ? "Latest request and response" : "Request and response",
196
198
  children: /* @__PURE__ */ n("div", { className: "grid gap-3 lg:grid-cols-2", children: [
197
- /* @__PURE__ */ e(q, { label: "Request", value: S(r.payload), fold: !0 }),
198
- /* @__PURE__ */ e(q, { label: "Response", value: S(r.response), fold: !0 })
199
+ /* @__PURE__ */ e(q, { label: "Request", value: E(r.payload), fold: !0 }),
200
+ /* @__PURE__ */ e(q, { label: "Response", value: E(r.response), fold: !0 })
199
201
  ] })
200
202
  }
201
203
  ),
202
204
  /* @__PURE__ */ n("div", { className: "grid gap-4 xl:grid-cols-2", children: [
203
- /* @__PURE__ */ e(x, { name: "why", title: "Why it was sent — and who", children: /* @__PURE__ */ n("dl", { className: "grid grid-cols-[max-content_minmax(0,1fr)] items-baseline gap-x-4 gap-y-1.5", children: [
204
- /* @__PURE__ */ e(b, { label: "Triggered by", children: /* @__PURE__ */ e("span", { className: "inline-flex max-w-full", "data-ic-drill-triggered-by": !0, children: /* @__PURE__ */ e(T, { r: t.triggered_by }) }) }),
205
+ /* @__PURE__ */ e(h, { name: "why", title: "Why it was sent — and who", children: /* @__PURE__ */ n("dl", { className: "grid grid-cols-[max-content_minmax(0,1fr)] items-baseline gap-x-4 gap-y-1.5", children: [
206
+ /* @__PURE__ */ e(b, { label: "Triggered by", children: /* @__PURE__ */ e("span", { className: "inline-flex max-w-full", "data-ic-drill-triggered-by": !0, children: /* @__PURE__ */ e(S, { r: t.triggered_by }) }) }),
205
207
  /* @__PURE__ */ e(b, { label: "What sent it", children: f ? /* @__PURE__ */ n(
206
208
  "button",
207
209
  {
208
210
  type: "button",
209
- onClick: () => E(u, f),
211
+ onClick: () => T(u, f),
210
212
  className: "inline-flex items-center gap-1 text-left font-medium underline decoration-border underline-offset-2 hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
211
213
  children: [
212
214
  t.trigger.label,
@@ -225,7 +227,7 @@ function G({
225
227
  "#",
226
228
  a.attempt
227
229
  ] }),
228
- /* @__PURE__ */ e(T, { r: a.requester, size: "sm" })
230
+ /* @__PURE__ */ e(S, { r: a.requester, size: "sm" })
229
231
  ] }, a.attempt)) }) }),
230
232
  /* @__PURE__ */ e(b, { label: "Obligation", children: s ? /* @__PURE__ */ n("span", { className: "inline-flex flex-wrap items-center gap-x-1.5 gap-y-0.5", children: [
231
233
  /* @__PURE__ */ e("span", { className: "font-mono text-[11.5px]", children: s.kind }),
@@ -251,7 +253,7 @@ function G({
251
253
  ] }) : /* @__PURE__ */ e("span", { className: "text-muted-foreground", children: "None recorded for this push" }) }),
252
254
  t.partner.owner && /* @__PURE__ */ e(b, { label: "Partner owner", children: t.partner.owner.name })
253
255
  ] }) }),
254
- /* @__PURE__ */ n(x, { name: "calls", title: "Call log", children: [
256
+ /* @__PURE__ */ n(h, { name: "calls", title: "Call log", children: [
255
257
  t.call_logs.length === 0 ? /* @__PURE__ */ e("p", { className: "text-[12px] text-muted-foreground", children: "No partner calls matched this push — the writer that sent it does not log its calls." }) : /* @__PURE__ */ e("ul", { className: "divide-y divide-border rounded-md border border-border", children: t.call_logs.map((a) => {
256
258
  const O = a.error != null || (a.status ?? 0) >= 400;
257
259
  return /* @__PURE__ */ n(
@@ -293,12 +295,12 @@ function G({
293
295
  a.id
294
296
  );
295
297
  }) }),
296
- h && /* @__PURE__ */ n(
298
+ x && /* @__PURE__ */ n(
297
299
  "button",
298
300
  {
299
301
  type: "button",
300
302
  "data-ic-drill-call-logs": !0,
301
- onClick: () => E(u, h),
303
+ onClick: () => T(u, x),
302
304
  className: "mt-1.5 inline-flex items-center gap-1 text-[12px] font-medium text-foreground underline decoration-border underline-offset-2 hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
303
305
  children: [
304
306
  "Open in Call Logs",
@@ -320,7 +322,7 @@ function G({
320
322
  type: "button",
321
323
  "data-ic-drill-retry": !0,
322
324
  disabled: !t.retry.eligible || c,
323
- onClick: l,
325
+ onClick: o,
324
326
  className: "inline-flex h-7 items-center gap-1.5 rounded-md border border-border bg-card px-2.5 text-[12px] font-medium text-foreground transition-colors hover:bg-muted disabled:cursor-not-allowed disabled:opacity-60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
325
327
  children: [
326
328
  c ? /* @__PURE__ */ e(U, { className: "h-3 w-3 animate-spin", "aria-hidden": !0 }) : /* @__PURE__ */ e($, { className: "h-3 w-3", "aria-hidden": !0 }),
@@ -339,13 +341,13 @@ function G({
339
341
  ),
340
342
  !t.retry.eligible && t.retry.reason && /* @__PURE__ */ e("span", { className: "text-[12px] text-muted-foreground", "data-ic-drill-retry-reason": !0, children: t.retry.reason }),
341
343
  t.retry.eligible && t.retry.warning && /* @__PURE__ */ e("span", { className: m("text-[12px]", d.warning), children: t.retry.warning }),
342
- o && /* @__PURE__ */ e("span", { className: m("text-[12px]", d.negative), children: o })
344
+ l && /* @__PURE__ */ e("span", { className: m("text-[12px]", d.negative), children: l })
343
345
  ]
344
346
  }
345
347
  )
346
348
  ] });
347
349
  }
348
350
  export {
349
- ie as SubmissionDrill,
350
- H as sameRequester
351
+ oe as SubmissionDrill,
352
+ I as sameRequester
351
353
  };
@@ -0,0 +1,212 @@
1
+ import { jsx as n, jsxs as s } from "react/jsx-runtime";
2
+ import { useQuery as O, useQueryClient as j, useMutation as q } from "@tanstack/react-query";
3
+ import { MessageSquare as D, Link2 as Q, RotateCcw as _, Check as E } from "lucide-react";
4
+ import { useState as v, useMemo as y } from "react";
5
+ import { toast as x } from "sonner";
6
+ import { useNivaroClient as T } from "../../context.js";
7
+ import { get as I, post as R } from "../../lib/commands.js";
8
+ import { openFieldCommentCounts as A, fieldThread as B, fieldDeepLinkQuery as H } from "../../lib/field-comments.js";
9
+ import { cn as L, formatRelative as U } from "../../lib/utils.js";
10
+ import { AutolinkedText as W } from "../AutolinkedText.js";
11
+ import { MentionTextarea as z } from "../panels/CommentPanel.js";
12
+ import { Popover as G, PopoverTrigger as J, PopoverContent as V } from "../ui/popover.js";
13
+ import { useFieldComments as X } from "./field-comments-context.js";
14
+ const S = (t, o) => ["comments", t, o];
15
+ function K(t, o, r) {
16
+ const a = T();
17
+ return O({
18
+ queryKey: S(t, o),
19
+ queryFn: () => a.request(I("/comments", { collection: t, item: o })).then((d) => d.data),
20
+ enabled: r
21
+ });
22
+ }
23
+ function he(t) {
24
+ const o = t.itemId == null ? "" : String(t.itemId), r = t.enabled && o !== "" && o !== "new", { data: a } = K(t.collection, o, r), [d, c] = v(null), l = y(() => A(a ?? []), [a]), { labelOf: i, jump: p, collection: u } = t;
25
+ return y(
26
+ () => r ? { collection: u, item: o, counts: l, openField: d, setOpenField: c, labelOf: i, jump: p } : null,
27
+ [r, u, o, l, d, i, p]
28
+ );
29
+ }
30
+ function Y(t) {
31
+ return t ? [t.first_name, t.last_name].filter(Boolean).join(" ") || t.email : "Someone";
32
+ }
33
+ function xe({ field: t, label: o }) {
34
+ const r = X();
35
+ return r ? /* @__PURE__ */ n(Z, { ctx: r, field: t, label: o }) : null;
36
+ }
37
+ function Z({
38
+ ctx: t,
39
+ field: o,
40
+ label: r
41
+ }) {
42
+ const a = t.counts[o] ?? 0, d = t.openField === o;
43
+ return /* @__PURE__ */ s(G, { open: d, onOpenChange: (c) => t.setOpenField(c ? o : null), children: [
44
+ /* @__PURE__ */ n(J, { asChild: !0, children: /* @__PURE__ */ s(
45
+ "button",
46
+ {
47
+ type: "button",
48
+ "data-field-comment": o,
49
+ "data-field-comment-count": a || void 0,
50
+ "aria-label": a ? `${a} open ${a === 1 ? "comment" : "comments"} on ${r}` : `Comment on ${r}`,
51
+ "data-tip": a ? void 0 : `Comment on ${r}`,
52
+ className: L(
53
+ "inline-flex items-center gap-0.5 rounded px-0.5 py-0.5 text-[10px] font-semibold transition-[opacity,color]",
54
+ a || d ? "text-[#0e7490] opacity-100 dark:text-nvr-cyan" : "text-slate-400 opacity-0 hover:text-[#0e7490] focus-visible:opacity-100 group-hover/fieldrow:opacity-100 group-focus-within/fieldrow:opacity-100 dark:text-slate-400 dark:hover:text-nvr-cyan"
55
+ ),
56
+ children: [
57
+ /* @__PURE__ */ n(D, { "aria-hidden": !0, className: "h-3 w-3" }),
58
+ a > 0 && /* @__PURE__ */ n("span", { className: "tabular-nums", children: a })
59
+ ]
60
+ }
61
+ ) }),
62
+ /* @__PURE__ */ n(
63
+ V,
64
+ {
65
+ align: "start",
66
+ className: "w-[340px] p-0",
67
+ onInteractOutside: (c) => {
68
+ var i;
69
+ const l = c.target;
70
+ (i = l == null ? void 0 : l.closest) != null && i.call(l, "[data-mention-menu]") && c.preventDefault();
71
+ },
72
+ children: d && /* @__PURE__ */ n(ee, { ctx: t, field: o, label: r })
73
+ }
74
+ )
75
+ ] });
76
+ }
77
+ function ee({
78
+ ctx: t,
79
+ field: o,
80
+ label: r
81
+ }) {
82
+ const a = T(), d = j(), { data: c, isLoading: l } = K(t.collection, t.item, !0), i = y(() => B(c ?? [], o), [c, o]), [p, u] = v(!1), [f, g] = v(""), b = () => d.invalidateQueries({ queryKey: S(t.collection, t.item) }), k = (e, m) => {
83
+ var $, F, P;
84
+ return ((F = ($ = e == null ? void 0 : e.response) == null ? void 0 : $.data) == null ? void 0 : F.error) ?? ((P = e == null ? void 0 : e.data) == null ? void 0 : P.error) ?? m;
85
+ }, h = q({
86
+ mutationFn: (e) => a.request(
87
+ R("/comments", {
88
+ collection: t.collection,
89
+ item: t.item,
90
+ text: e,
91
+ field: o,
92
+ field_label: r
93
+ })
94
+ ),
95
+ onSuccess: () => {
96
+ g(""), b();
97
+ },
98
+ onError: (e) => x.error(k(e, "Could not post the comment"))
99
+ }), w = q({
100
+ mutationFn: ({ id: e, resolved: m }) => a.request(R(`/comments/${e}/resolve`, { resolved: m })),
101
+ onSuccess: () => void b(),
102
+ onError: (e) => x.error(k(e, "Could not update the comment"))
103
+ }), C = () => {
104
+ const e = f.trim();
105
+ e && !h.isPending && h.mutate(e);
106
+ }, M = () => {
107
+ const e = new URL(window.location.href);
108
+ e.searchParams.delete("field");
109
+ const m = e.search ? "&" : "?";
110
+ navigator.clipboard.writeText(`${e.origin}${e.pathname}${e.search}${m}${H(o)}`).then(
111
+ () => x.success("Link to this field copied"),
112
+ () => x.error("Could not copy")
113
+ );
114
+ }, N = (e, m) => /* @__PURE__ */ s("li", { "data-field-comment-row": e.id, className: "px-3 py-2", children: [
115
+ /* @__PURE__ */ s("div", { className: "flex items-baseline gap-1.5", children: [
116
+ /* @__PURE__ */ n("span", { className: "truncate text-[12px] font-medium text-slate-800 dark:text-foreground", children: Y(e.user) }),
117
+ /* @__PURE__ */ n("span", { className: "shrink-0 text-[11px] text-slate-400 dark:text-muted-foreground", children: U(e.created_at) }),
118
+ /* @__PURE__ */ s(
119
+ "button",
120
+ {
121
+ type: "button",
122
+ disabled: w.isPending,
123
+ onClick: () => w.mutate({ id: e.id, resolved: !m }),
124
+ "data-field-comment-resolve": e.id,
125
+ className: "ml-auto inline-flex shrink-0 items-center gap-1 rounded px-1 py-px text-[11px] text-slate-500 transition-colors hover:bg-muted hover:text-slate-800 disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground",
126
+ children: [
127
+ m ? /* @__PURE__ */ n(_, { "aria-hidden": !0, className: "h-3 w-3" }) : /* @__PURE__ */ n(E, { "aria-hidden": !0, className: "h-3 w-3" }),
128
+ m ? "Reopen" : "Resolve"
129
+ ]
130
+ }
131
+ )
132
+ ] }),
133
+ /* @__PURE__ */ n(
134
+ "p",
135
+ {
136
+ className: L(
137
+ "m-0 mt-0.5 whitespace-pre-wrap text-[12.5px] leading-snug [overflow-wrap:anywhere]",
138
+ m ? "text-slate-400 dark:text-muted-foreground" : "text-slate-600 dark:text-slate-300"
139
+ ),
140
+ children: /* @__PURE__ */ n(W, { text: e.text })
141
+ }
142
+ )
143
+ ] }, e.id);
144
+ return /* @__PURE__ */ s("div", { "data-field-comments": o, children: [
145
+ /* @__PURE__ */ s("div", { className: "flex items-center gap-2 border-b border-slate-200 px-3 py-2 dark:border-border", children: [
146
+ /* @__PURE__ */ s("p", { className: "m-0 min-w-0 flex-1 truncate text-[12px] font-semibold text-slate-700 dark:text-foreground", children: [
147
+ "Comments on ",
148
+ r
149
+ ] }),
150
+ /* @__PURE__ */ n(
151
+ "button",
152
+ {
153
+ type: "button",
154
+ onClick: M,
155
+ "aria-label": `Copy a link to ${r}`,
156
+ "data-tip": "Copy a link that opens the record on this field",
157
+ className: "rounded p-1 text-slate-400 transition-colors hover:bg-muted hover:text-slate-700 dark:hover:text-foreground",
158
+ children: /* @__PURE__ */ n(Q, { "aria-hidden": !0, className: "h-3.5 w-3.5" })
159
+ }
160
+ )
161
+ ] }),
162
+ /* @__PURE__ */ s("div", { className: "max-h-[260px] overflow-y-auto overscroll-contain", children: [
163
+ l ? /* @__PURE__ */ n("p", { className: "m-0 px-3 py-3 text-[12px] text-slate-400 dark:text-muted-foreground", children: "Loading…" }) : i.open.length === 0 && i.resolved.length === 0 ? /* @__PURE__ */ n("p", { className: "m-0 px-3 py-3 text-[12px] text-slate-500 dark:text-muted-foreground", children: "No comments on this field yet. They also show in the record’s Comments." }) : /* @__PURE__ */ s("ul", { className: "m-0 list-none divide-y divide-slate-100 p-0 dark:divide-border", children: [
164
+ i.open.map((e) => N(e, !1)),
165
+ p && i.resolved.map((e) => N(e, !0))
166
+ ] }),
167
+ i.resolved.length > 0 && /* @__PURE__ */ n(
168
+ "button",
169
+ {
170
+ type: "button",
171
+ onClick: () => u((e) => !e),
172
+ "aria-expanded": p,
173
+ className: "block w-full px-3 py-1.5 text-left text-[11px] text-slate-500 transition-colors hover:bg-muted dark:text-muted-foreground",
174
+ children: p ? "Hide resolved" : `${i.resolved.length} resolved`
175
+ }
176
+ )
177
+ ] }),
178
+ /* @__PURE__ */ s("div", { className: "space-y-1.5 border-t border-slate-200 p-2 dark:border-border", children: [
179
+ /* @__PURE__ */ n(
180
+ z,
181
+ {
182
+ value: f,
183
+ onChange: g,
184
+ rows: 2,
185
+ "aria-label": `Comment on ${r}`,
186
+ placeholder: "Write a comment… type @ to mention someone",
187
+ className: "min-h-[56px] text-[12.5px]",
188
+ onKeyDownCapture: (e) => {
189
+ e.key === "Enter" && (e.metaKey || e.ctrlKey) && (e.preventDefault(), C());
190
+ }
191
+ }
192
+ ),
193
+ /* @__PURE__ */ s("div", { className: "flex items-center justify-between gap-2", children: [
194
+ /* @__PURE__ */ n("span", { className: "text-[11px] text-slate-400 dark:text-muted-foreground", children: "Only people who can open this record are notified." }),
195
+ /* @__PURE__ */ n(
196
+ "button",
197
+ {
198
+ type: "button",
199
+ onClick: C,
200
+ disabled: !f.trim() || h.isPending,
201
+ className: "inline-flex h-7 shrink-0 items-center rounded-md bg-nvr-cyan px-2.5 text-[12px] font-medium text-white transition-colors hover:bg-nvr-cyan-dark disabled:opacity-50",
202
+ children: h.isPending ? "Posting…" : "Comment"
203
+ }
204
+ )
205
+ ] })
206
+ ] })
207
+ ] });
208
+ }
209
+ export {
210
+ xe as FieldCommentButton,
211
+ he as useFieldCommentsApi
212
+ };