@nivaro/react 0.3.36 → 0.3.37
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/components/slots/CommentsSlot.js +44 -36
- package/dist/full.css +1 -1
- package/dist/hooks/useSessionRecorder.js +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/shared/components/AgentBadge.js +26 -0
- package/dist/shared/components/AgentQuestionsCard.js +198 -0
- package/dist/shared/components/ItemEditForm.js +3329 -3263
- package/dist/shared/components/McpConnectionScope.js +480 -0
- package/dist/shared/components/MyWorkView.js +223 -208
- package/dist/shared/components/RecordReadView.js +620 -575
- package/dist/shared/components/chat/ChatPanel.js +683 -671
- package/dist/shared/components/imports/DownloadSampleButton.js +69 -0
- package/dist/shared/components/imports/ImportConsole.js +106 -104
- package/dist/shared/components/imports/RunDetailSheet.js +11 -10
- package/dist/shared/components/item-edit/FieldAffordances.js +32 -32
- package/dist/shared/components/item-edit/FormTour.js +279 -0
- package/dist/shared/components/item-edit/GroupSection.js +377 -360
- package/dist/shared/components/item-edit/PersonalDefaultControl.js +28 -28
- package/dist/shared/components/item-edit/entry/EntryStrip.js +30 -26
- package/dist/shared/components/item-edit/form-density.js +36 -0
- package/dist/shared/components/item-edit/useFormUsageBeacon.js +59 -46
- package/dist/shared/components/item-edit/usePersonalDefaults.js +312 -296
- package/dist/shared/components/layout-editor/AddPanel.js +349 -192
- package/dist/shared/components/layout-editor/DesignNode.js +126 -112
- package/dist/shared/components/layout-editor/EditorTopBar.js +123 -103
- package/dist/shared/components/layout-editor/LayoutEditor.js +829 -751
- package/dist/shared/components/layout-editor/PlaceTools.js +334 -0
- package/dist/shared/components/layout-editor/SlashInsert.js +252 -0
- package/dist/shared/components/layout-editor/StructureMenu.js +285 -242
- package/dist/shared/components/layout-editor/add-target.js +54 -43
- package/dist/shared/components/layout-editor/ai-forms/AiComposer.js +238 -155
- package/dist/shared/components/layout-editor/ai-forms/AiFormsButton.js +1 -1
- package/dist/shared/components/layout-editor/ai-forms/ai-forms-api.js +15 -12
- package/dist/shared/components/layout-editor/dnd/LayoutDndProvider.js +347 -189
- package/dist/shared/components/layout-editor/dnd/TrashZone.js +60 -32
- package/dist/shared/components/layout-editor/dnd/UndoChip.js +76 -0
- package/dist/shared/components/layout-editor/dnd/merge-drop.js +33 -0
- package/dist/shared/components/layout-editor/dnd/multi-drop.js +87 -0
- package/dist/shared/components/layout-editor/dnd/node.js +115 -105
- package/dist/shared/components/layout-editor/dnd/sensors.js +23 -0
- package/dist/shared/components/layout-editor/dnd/trash-drop.js +34 -28
- package/dist/shared/components/layout-editor/dnd/trash-links.js +97 -0
- package/dist/shared/components/layout-editor/even-row.js +86 -0
- package/dist/shared/components/layout-editor/field-list.js +99 -0
- package/dist/shared/components/layout-editor/format-painter.js +102 -0
- package/dist/shared/components/layout-editor/grid-guides.js +15 -13
- package/dist/shared/components/layout-editor/inspector/BehaviourSettings.js +150 -132
- package/dist/shared/components/layout-editor/inspector/BulkInspector.js +57 -53
- package/dist/shared/components/layout-editor/inspector/EvenRowAction.js +31 -0
- package/dist/shared/components/layout-editor/inspector/GroupInspector.js +154 -141
- package/dist/shared/components/layout-editor/inspector/Inspector.js +209 -178
- package/dist/shared/components/layout-editor/inspector/LookTab.js +106 -98
- package/dist/shared/components/layout-editor/inspector/RulesTab.js +38 -37
- package/dist/shared/components/layout-editor/inspector/kit.js +280 -223
- package/dist/shared/components/layout-editor/keyboard-move.js +15 -15
- package/dist/shared/components/layout-editor/lint/LabelStyle.js +201 -0
- package/dist/shared/components/layout-editor/lint/LintPanel.js +132 -84
- package/dist/shared/components/layout-editor/lint/lint-api.js +65 -28
- package/dist/shared/components/layout-editor/nav/NavTools.js +14 -12
- package/dist/shared/components/layout-editor/nav/ZoomControls.js +145 -0
- package/dist/shared/components/layout-editor/nav/useEditorNav.js +34 -32
- package/dist/shared/components/layout-editor/nav/view-prefs.js +100 -15
- package/dist/shared/components/layout-editor/outputs/LayoutFile.js +89 -0
- package/dist/shared/components/layout-editor/outputs/OutputsButton.js +272 -195
- package/dist/shared/components/layout-editor/outputs/layout-file-plan.js +176 -0
- package/dist/shared/components/layout-editor/outputs/output-api.js +71 -37
- package/dist/shared/components/layout-editor/overview/describe-conditions.js +16 -11
- package/dist/shared/components/layout-editor/overview/purpose.js +5 -5
- package/dist/shared/components/layout-editor/parity-keys.json.js +1 -1
- package/dist/shared/components/layout-editor/pin.js +37 -19
- package/dist/shared/components/layout-editor/place-clip.js +257 -0
- package/dist/shared/components/layout-editor/preview/PreviewModes.js +27 -26
- package/dist/shared/components/layout-editor/preview/PreviewPanes.js +148 -117
- package/dist/shared/components/layout-editor/preview/SampleRecord.js +113 -0
- package/dist/shared/components/layout-editor/preview/preview-model.js +79 -60
- package/dist/shared/components/layout-editor/preview/sample-record.js +105 -0
- package/dist/shared/components/layout-editor/removed-log.js +151 -0
- package/dist/shared/components/layout-editor/reuse/LibraryRows.js +109 -78
- package/dist/shared/components/layout-editor/reuse/linked-sections.js +373 -0
- package/dist/shared/components/layout-editor/revert-element.js +140 -0
- package/dist/shared/components/layout-editor/section-structure.js +193 -170
- package/dist/shared/components/layout-editor/settings/EntrySection.js +63 -45
- package/dist/shared/components/layout-editor/settings/LayoutSection.js +63 -32
- package/dist/shared/components/layout-editor/settings/ResolveSettings.js +179 -137
- package/dist/shared/components/layout-editor/settings/WhoSection.js +18 -17
- package/dist/shared/components/layout-editor/settings/settings-registry.js +24 -0
- package/dist/shared/components/layout-editor/shortcuts.js +21 -16
- package/dist/shared/components/layout-editor/structure-ops.js +221 -195
- package/dist/shared/components/layout-editor/usage/UsagePanel.js +133 -85
- package/dist/shared/components/layout-editor/usage/refusal-lens.js +130 -0
- package/dist/shared/components/layout-editor/usage/usage-api.js +12 -11
- package/dist/shared/components/panels/CommentPanel.js +47 -45
- package/dist/shared/components/panels/RevisionsPanel.js +66 -64
- package/dist/shared/components/panels/TaskPanel.js +395 -332
- package/dist/shared/components/profile/AgentsPanel.js +196 -147
- package/dist/shared/components/profile/ConnectionRollback.js +329 -0
- package/dist/shared/components/profile/MyDefaultsCard.js +526 -520
- package/dist/shared/lib/entry-config.js +22 -22
- package/dist/shared/lib/form-usage-beacon.js +91 -55
- package/dist/shared/lib/layout-lint.js +530 -284
- package/dist/shared/lib/layout-resolve.js +58 -44
- package/package.json +1 -1
|
@@ -1,76 +1,77 @@
|
|
|
1
|
-
import { jsxs as s, jsx as t, Fragment as
|
|
2
|
-
import { ChevronsDownUp as
|
|
3
|
-
import { useState as
|
|
4
|
-
import { UNGROUPED_KEY as
|
|
5
|
-
import { titleCase as
|
|
6
|
-
import { Skeleton as
|
|
7
|
-
import { Toggle as
|
|
8
|
-
import { AbTestSection as
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
import { jsxs as s, jsx as t, Fragment as T } from "react/jsx-runtime";
|
|
2
|
+
import { ChevronsDownUp as J, Rows3 as Q } from "lucide-react";
|
|
3
|
+
import { useState as j, useMemo as b } from "react";
|
|
4
|
+
import { UNGROUPED_KEY as V } from "../../../lib/layout-ops.js";
|
|
5
|
+
import { titleCase as M } from "../../../lib/utils.js";
|
|
6
|
+
import { Skeleton as P } from "../../ui/skeleton.js";
|
|
7
|
+
import { Toggle as R } from "../settings/controls.js";
|
|
8
|
+
import { AbTestSection as X } from "./AbTestSection.js";
|
|
9
|
+
import { useRefusalLens as Z, useSaveRefusals as ee, refusalTone as te, refusalPct as ae, refusalTip as se, REFUSAL_MIN_ATTEMPTS as le } from "./refusal-lens.js";
|
|
10
|
+
import { suggestCollapse as re, rateText as ne } from "./suggest-collapse.js";
|
|
11
|
+
import { suggestSections as oe } from "./suggest-sections.js";
|
|
12
|
+
import { useLayoutUsageToday as de, useLayoutFriction as ie, useCoChanges as ce, formatDuration as me } from "./usage-api.js";
|
|
13
|
+
const c = "px-3 pb-1.5 pt-4 text-[12px] font-semibold text-slate-700 dark:text-foreground", o = "px-3 text-[12px] leading-snug text-slate-500 dark:text-muted-foreground";
|
|
14
|
+
function m({ label: r, value: p }) {
|
|
14
15
|
return /* @__PURE__ */ s("div", { className: "flex flex-col gap-0.5 bg-white px-2.5 py-2 dark:bg-card", children: [
|
|
15
|
-
/* @__PURE__ */ t("span", { className: "text-[11px] text-slate-500 dark:text-muted-foreground", children:
|
|
16
|
-
/* @__PURE__ */ t("span", { className: "text-[14px] font-semibold tabular-nums text-slate-900 dark:text-foreground", children:
|
|
16
|
+
/* @__PURE__ */ t("span", { className: "text-[11px] text-slate-500 dark:text-muted-foreground", children: r }),
|
|
17
|
+
/* @__PURE__ */ t("span", { className: "text-[14px] font-semibold tabular-nums text-slate-900 dark:text-foreground", children: p })
|
|
17
18
|
] });
|
|
18
19
|
}
|
|
19
|
-
function
|
|
20
|
-
return /* @__PURE__ */ t("div", { className: "mx-3 grid grid-cols-3 gap-px overflow-hidden rounded-lg border border-slate-200 bg-slate-200 dark:border-border dark:bg-border", children:
|
|
20
|
+
function U({ children: r }) {
|
|
21
|
+
return /* @__PURE__ */ t("div", { className: "mx-3 grid grid-cols-3 gap-px overflow-hidden rounded-lg border border-slate-200 bg-slate-200 dark:border-border dark:bg-border", children: r });
|
|
21
22
|
}
|
|
22
|
-
function
|
|
23
|
-
bundle:
|
|
24
|
-
collection:
|
|
25
|
-
fields:
|
|
26
|
-
apply:
|
|
27
|
-
showFill:
|
|
28
|
-
onShowFill:
|
|
29
|
-
onOpenLayout:
|
|
23
|
+
function Le({
|
|
24
|
+
bundle: r,
|
|
25
|
+
collection: p,
|
|
26
|
+
fields: k,
|
|
27
|
+
apply: y,
|
|
28
|
+
showFill: D,
|
|
29
|
+
onShowFill: E,
|
|
30
|
+
onOpenLayout: F
|
|
30
31
|
}) {
|
|
31
|
-
var
|
|
32
|
-
const
|
|
33
|
-
const e = new Map(
|
|
34
|
-
return (l) => e.get(l) ??
|
|
35
|
-
}, [
|
|
32
|
+
var C;
|
|
33
|
+
const h = Number(r.layout.id), { data: d, isLoading: O } = de(h), { data: a, isLoading: g } = ie(h), { data: u, isLoading: A } = ce(p), w = Z(h), { data: n, isLoading: q } = ee(h), [L, G] = j(() => /* @__PURE__ */ new Set()), [I, W] = j(!1), N = b(() => {
|
|
34
|
+
const e = new Map(k.map((l) => [l.field, l.label || M(l.field)]));
|
|
35
|
+
return (l) => e.get(l) ?? M(l);
|
|
36
|
+
}, [k]), x = (e) => {
|
|
36
37
|
var l;
|
|
37
|
-
return e == null || e ===
|
|
38
|
-
},
|
|
39
|
-
() =>
|
|
40
|
-
[
|
|
41
|
-
),
|
|
42
|
-
() =>
|
|
43
|
-
[
|
|
44
|
-
),
|
|
38
|
+
return e == null || e === V ? "Ungrouped" : ((l = r.groups.find((f) => f.key === e)) == null ? void 0 : l.label) ?? e;
|
|
39
|
+
}, K = (e) => e === "__form__" ? "Whole form" : e === "__general__" ? "General" : x(e), S = b(() => new Set(r.placements.map((e) => e.field)), [r.placements]), _ = b(
|
|
40
|
+
() => oe(r, (u == null ? void 0 : u.pairs) ?? []).filter((e) => !L.has(e.id)),
|
|
41
|
+
[r, u, L]
|
|
42
|
+
), i = b(
|
|
43
|
+
() => re(r, (a == null ? void 0 : a.sections) ?? []),
|
|
44
|
+
[r, a == null ? void 0 : a.sections]
|
|
45
|
+
), v = (a == null ? void 0 : a.steps) ?? [], Y = Math.max(1, ...v.map((e) => e.avg_ms)), $ = ((a == null ? void 0 : a.changed_after_save.fields) ?? []).slice(0, 8), z = d && !d.ready || a && !a.ready;
|
|
45
46
|
return /* @__PURE__ */ s("div", { "data-editor-usage": "", className: "flex flex-col pb-4", children: [
|
|
46
47
|
/* @__PURE__ */ s("div", { className: "flex items-center justify-between gap-2 px-3 pt-3", children: [
|
|
47
48
|
/* @__PURE__ */ t("span", { className: "text-[12.5px] text-slate-700 dark:text-foreground", children: "Show how full each field is" }),
|
|
48
|
-
/* @__PURE__ */ t(
|
|
49
|
+
/* @__PURE__ */ t(R, { label: "Show how full each field is", checked: D, onChange: E })
|
|
49
50
|
] }),
|
|
50
|
-
/* @__PURE__ */ t("p", { className: `${
|
|
51
|
-
|
|
52
|
-
/* @__PURE__ */ t("p", { className:
|
|
53
|
-
|
|
54
|
-
/* @__PURE__ */ t(
|
|
55
|
-
/* @__PURE__ */ t(
|
|
56
|
-
/* @__PURE__ */ t(
|
|
51
|
+
/* @__PURE__ */ t("p", { className: `${o} pt-1`, children: "Each field on the form shows the share of records that have a value." }),
|
|
52
|
+
z && /* @__PURE__ */ t("p", { role: "note", className: `${o} pt-3`, children: "Usage is not being recorded on this instance yet (its database needs the latest update)." }),
|
|
53
|
+
/* @__PURE__ */ t("p", { className: c, children: "Today" }),
|
|
54
|
+
O ? /* @__PURE__ */ t(P, { className: "mx-3 h-12 rounded-lg" }) : /* @__PURE__ */ s(U, { children: [
|
|
55
|
+
/* @__PURE__ */ t(m, { label: "Opens", value: ((d == null ? void 0 : d.opens) ?? 0).toLocaleString() }),
|
|
56
|
+
/* @__PURE__ */ t(m, { label: "People", value: ((d == null ? void 0 : d.people) ?? 0).toLocaleString() }),
|
|
57
|
+
/* @__PURE__ */ t(m, { label: "Records", value: ((d == null ? void 0 : d.records) ?? 0).toLocaleString() })
|
|
57
58
|
] }),
|
|
58
|
-
/* @__PURE__ */ s("p", { className:
|
|
59
|
+
/* @__PURE__ */ s("p", { className: c, children: [
|
|
59
60
|
"Last ",
|
|
60
61
|
(a == null ? void 0 : a.days) ?? 30,
|
|
61
62
|
" days"
|
|
62
63
|
] }),
|
|
63
|
-
|
|
64
|
-
/* @__PURE__ */ t(
|
|
65
|
-
/* @__PURE__ */ t(
|
|
66
|
-
/* @__PURE__ */ t(
|
|
64
|
+
g ? /* @__PURE__ */ t(P, { className: "mx-3 h-12 rounded-lg" }) : /* @__PURE__ */ s(U, { children: [
|
|
65
|
+
/* @__PURE__ */ t(m, { label: "Opens", value: ((a == null ? void 0 : a.opens) ?? 0).toLocaleString() }),
|
|
66
|
+
/* @__PURE__ */ t(m, { label: "Saves", value: ((a == null ? void 0 : a.saves) ?? 0).toLocaleString() }),
|
|
67
|
+
/* @__PURE__ */ t(m, { label: "Left unfinished", value: ((a == null ? void 0 : a.abandons) ?? 0).toLocaleString() })
|
|
67
68
|
] }),
|
|
68
|
-
/* @__PURE__ */ t("p", { className:
|
|
69
|
-
|
|
69
|
+
/* @__PURE__ */ t("p", { className: c, children: "Time per step" }),
|
|
70
|
+
v.length === 0 ? /* @__PURE__ */ t("p", { className: o, children: g ? "Loading…" : "No visits recorded yet." }) : /* @__PURE__ */ t("ul", { "data-usage-steps": "", className: "flex flex-col gap-2 px-3", children: v.map((e) => /* @__PURE__ */ s("li", { className: "flex flex-col gap-1", children: [
|
|
70
71
|
/* @__PURE__ */ s("div", { className: "flex items-baseline justify-between gap-2 text-[12px]", children: [
|
|
71
|
-
/* @__PURE__ */ t("span", { className: "truncate text-slate-800 dark:text-foreground", children:
|
|
72
|
+
/* @__PURE__ */ t("span", { className: "truncate text-slate-800 dark:text-foreground", children: K(e.key) }),
|
|
72
73
|
/* @__PURE__ */ s("span", { className: "shrink-0 tabular-nums text-slate-500 dark:text-muted-foreground", children: [
|
|
73
|
-
|
|
74
|
+
me(e.avg_ms),
|
|
74
75
|
e.abandons > 0 && /* @__PURE__ */ s("span", { className: "text-amber-700 dark:text-amber-300", children: [
|
|
75
76
|
" · ",
|
|
76
77
|
e.abandons,
|
|
@@ -82,20 +83,20 @@ function ge({
|
|
|
82
83
|
"div",
|
|
83
84
|
{
|
|
84
85
|
className: "h-full rounded-full bg-slate-400 dark:bg-slate-500",
|
|
85
|
-
style: { width: `${Math.max(2, Math.round(e.avg_ms /
|
|
86
|
+
style: { width: `${Math.max(2, Math.round(e.avg_ms / Y * 100))}%` }
|
|
86
87
|
}
|
|
87
88
|
) })
|
|
88
89
|
] }, e.key)) }),
|
|
89
|
-
/* @__PURE__ */ t("p", { className:
|
|
90
|
-
|
|
91
|
-
/* @__PURE__ */ t("ul", { "data-usage-changed": "", className: "flex flex-col px-3", children:
|
|
90
|
+
/* @__PURE__ */ t("p", { className: c, children: "Changed soon after saving" }),
|
|
91
|
+
$.length === 0 ? /* @__PURE__ */ t("p", { className: o, children: g ? "Loading…" : "No field was changed within a day of a record being created." }) : /* @__PURE__ */ s(T, { children: [
|
|
92
|
+
/* @__PURE__ */ t("ul", { "data-usage-changed": "", className: "flex flex-col px-3", children: $.map((e) => /* @__PURE__ */ s(
|
|
92
93
|
"li",
|
|
93
94
|
{
|
|
94
95
|
className: "flex items-baseline justify-between gap-2 border-b border-slate-100 py-1 text-[12px] last:border-0 dark:border-border",
|
|
95
96
|
children: [
|
|
96
97
|
/* @__PURE__ */ s("span", { className: "min-w-0 truncate text-slate-800 dark:text-foreground", children: [
|
|
97
|
-
|
|
98
|
-
!
|
|
98
|
+
N(e.field),
|
|
99
|
+
!S.has(e.field) && /* @__PURE__ */ s("span", { className: "text-slate-400 dark:text-muted-foreground", children: [
|
|
99
100
|
" ",
|
|
100
101
|
"· not on this form"
|
|
101
102
|
] })
|
|
@@ -108,29 +109,76 @@ function ge({
|
|
|
108
109
|
},
|
|
109
110
|
e.field
|
|
110
111
|
)) }),
|
|
111
|
-
/* @__PURE__ */ s("p", { className: `${
|
|
112
|
+
/* @__PURE__ */ s("p", { className: `${o} pt-1`, children: [
|
|
112
113
|
"Edits within 24 hours of a record being created, last 90 days",
|
|
113
114
|
(a == null ? void 0 : a.changed_after_save.scope) === "collection" ? ", across every form of this collection." : ", on records opened with this form."
|
|
114
115
|
] })
|
|
115
116
|
] }),
|
|
116
|
-
/* @__PURE__ */ t("p", { className:
|
|
117
|
-
|
|
117
|
+
/* @__PURE__ */ t("p", { className: c, children: "Where saves fail" }),
|
|
118
|
+
/* @__PURE__ */ s("div", { className: "flex items-center justify-between gap-2 px-3", children: [
|
|
119
|
+
/* @__PURE__ */ t("span", { className: "text-[12.5px] text-slate-700 dark:text-foreground", children: "Show where saves fail" }),
|
|
120
|
+
/* @__PURE__ */ t(R, { label: "Show where saves fail", checked: w.on, onChange: w.setOn })
|
|
121
|
+
] }),
|
|
122
|
+
q ? /* @__PURE__ */ t("p", { className: `${o} pt-1`, children: "Loading…" }) : !n || n.fields.length === 0 ? /* @__PURE__ */ t("p", { className: `${o} pt-1`, children: n != null && n.attempts ? `No save was refused in the last ${n.days} days.` : "No saves recorded yet." }) : /* @__PURE__ */ s(T, { children: [
|
|
123
|
+
/* @__PURE__ */ t("ul", { "data-usage-refusals": "", className: "flex flex-col px-3 pt-1", children: n.fields.slice(0, 8).map((e) => {
|
|
124
|
+
const l = te(e.rate);
|
|
125
|
+
return /* @__PURE__ */ s(
|
|
126
|
+
"li",
|
|
127
|
+
{
|
|
128
|
+
"data-usage-refusal": e.field,
|
|
129
|
+
"data-tip": se(e, n.attempts, n.days),
|
|
130
|
+
className: "flex items-baseline justify-between gap-2 border-b border-slate-100 py-1 text-[12px] last:border-0 dark:border-border",
|
|
131
|
+
children: [
|
|
132
|
+
/* @__PURE__ */ s("span", { className: "min-w-0 truncate text-slate-800 dark:text-foreground", children: [
|
|
133
|
+
N(e.field),
|
|
134
|
+
!S.has(e.field) && /* @__PURE__ */ s("span", { className: "text-slate-400 dark:text-muted-foreground", children: [
|
|
135
|
+
" ",
|
|
136
|
+
"· not on this form"
|
|
137
|
+
] })
|
|
138
|
+
] }),
|
|
139
|
+
/* @__PURE__ */ s(
|
|
140
|
+
"span",
|
|
141
|
+
{
|
|
142
|
+
className: l === "high" ? "shrink-0 tabular-nums text-red-700 dark:text-red-300" : l === "some" ? "shrink-0 tabular-nums text-amber-700 dark:text-amber-300" : "shrink-0 tabular-nums text-slate-500 dark:text-muted-foreground",
|
|
143
|
+
children: [
|
|
144
|
+
ae(e.rate),
|
|
145
|
+
" of saves"
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
]
|
|
150
|
+
},
|
|
151
|
+
e.field
|
|
152
|
+
);
|
|
153
|
+
}) }),
|
|
154
|
+
/* @__PURE__ */ s("p", { className: `${o} pt-1`, children: [
|
|
155
|
+
n.refused.toLocaleString(),
|
|
156
|
+
" of ",
|
|
157
|
+
n.attempts.toLocaleString(),
|
|
158
|
+
" saves were refused in the last ",
|
|
159
|
+
n.days,
|
|
160
|
+
" days — a required field left empty, or a value a rule turned down.",
|
|
161
|
+
n.attempts < le && " Too few saves yet to tint the form."
|
|
162
|
+
] })
|
|
163
|
+
] }),
|
|
164
|
+
/* @__PURE__ */ t("p", { className: c, children: "Rarely opened sections" }),
|
|
165
|
+
g ? /* @__PURE__ */ t("p", { className: o, children: "Loading…" }) : i.candidates.length === 0 || I ? /* @__PURE__ */ t("p", { className: o, children: (C = a == null ? void 0 : a.sections) != null && C.length ? "No suggestion. People open every section that starts open often enough." : "No section visits recorded yet." }) : /* @__PURE__ */ s(
|
|
118
166
|
"div",
|
|
119
167
|
{
|
|
120
168
|
"data-usage-collapse": "",
|
|
121
169
|
className: "mx-3 flex flex-col gap-2 rounded-lg border border-slate-200 bg-white p-2.5 dark:border-border dark:bg-card",
|
|
122
170
|
children: [
|
|
123
171
|
/* @__PURE__ */ s("p", { className: "m-0 text-[12px] leading-snug text-slate-700 dark:text-foreground", children: [
|
|
124
|
-
/* @__PURE__ */ t(
|
|
172
|
+
/* @__PURE__ */ t(J, { className: "mr-1 inline h-3.5 w-3.5 align-[-2px] text-slate-400" }),
|
|
125
173
|
"People rarely open",
|
|
126
174
|
" ",
|
|
127
|
-
|
|
175
|
+
i.candidates.length === 1 ? "this section" : "these sections",
|
|
128
176
|
". Starting",
|
|
129
177
|
" ",
|
|
130
|
-
|
|
178
|
+
i.candidates.length === 1 ? "it" : "them",
|
|
131
179
|
" collapsed keeps the form shorter."
|
|
132
180
|
] }),
|
|
133
|
-
/* @__PURE__ */ t("ul", { className: "m-0 flex list-none flex-col p-0", children:
|
|
181
|
+
/* @__PURE__ */ t("ul", { className: "m-0 flex list-none flex-col p-0", children: i.candidates.map((e) => /* @__PURE__ */ s(
|
|
134
182
|
"li",
|
|
135
183
|
{
|
|
136
184
|
"data-usage-collapse-section": e.key,
|
|
@@ -139,7 +187,7 @@ function ge({
|
|
|
139
187
|
/* @__PURE__ */ t("span", { className: "truncate text-slate-800 dark:text-foreground", children: e.label }),
|
|
140
188
|
/* @__PURE__ */ s("span", { className: "tabular-nums text-[11.5px] text-slate-500 dark:text-muted-foreground", children: [
|
|
141
189
|
"opened in ",
|
|
142
|
-
|
|
190
|
+
ne(e.rate),
|
|
143
191
|
" of ",
|
|
144
192
|
e.shown.toLocaleString(),
|
|
145
193
|
" visits"
|
|
@@ -153,18 +201,18 @@ function ge({
|
|
|
153
201
|
"button",
|
|
154
202
|
{
|
|
155
203
|
type: "button",
|
|
156
|
-
onClick: () =>
|
|
157
|
-
label:
|
|
204
|
+
onClick: () => y(i.ops, {
|
|
205
|
+
label: i.candidates.length === 1 ? `Collapse ${i.candidates[0].label}` : `Collapse ${i.candidates.length} rarely opened sections`
|
|
158
206
|
}),
|
|
159
207
|
className: "inline-flex h-7 items-center rounded-md bg-nvr-cyan px-2.5 text-[12px] font-medium text-white transition-opacity hover:opacity-90",
|
|
160
|
-
children:
|
|
208
|
+
children: i.candidates.length === 1 ? "Start it collapsed" : `Start all ${i.candidates.length} collapsed`
|
|
161
209
|
}
|
|
162
210
|
),
|
|
163
211
|
/* @__PURE__ */ t(
|
|
164
212
|
"button",
|
|
165
213
|
{
|
|
166
214
|
type: "button",
|
|
167
|
-
onClick: () =>
|
|
215
|
+
onClick: () => W(!0),
|
|
168
216
|
className: "inline-flex h-7 items-center rounded-md px-2 text-[12px] text-slate-500 transition-colors hover:bg-muted hover:text-slate-800 dark:text-muted-foreground dark:hover:text-foreground",
|
|
169
217
|
children: "Not now"
|
|
170
218
|
}
|
|
@@ -173,15 +221,15 @@ function ge({
|
|
|
173
221
|
]
|
|
174
222
|
}
|
|
175
223
|
),
|
|
176
|
-
/* @__PURE__ */ s("p", { className: `${
|
|
224
|
+
/* @__PURE__ */ s("p", { className: `${o} pt-1`, children: [
|
|
177
225
|
"A section counts as opened when someone expands it, clicks in it or types in it. Last",
|
|
178
226
|
" ",
|
|
179
227
|
(a == null ? void 0 : a.days) ?? 30,
|
|
180
228
|
" days."
|
|
181
229
|
] }),
|
|
182
|
-
/* @__PURE__ */ t("p", { className:
|
|
183
|
-
|
|
184
|
-
const l = e.fields.map(
|
|
230
|
+
/* @__PURE__ */ t("p", { className: c, children: "Suggested sections" }),
|
|
231
|
+
A ? /* @__PURE__ */ t("p", { className: o, children: "Loading…" }) : _.length === 0 ? /* @__PURE__ */ t("p", { className: o, children: "No suggestions. Fields people change together already sit together on this form." }) : /* @__PURE__ */ t("ul", { "data-usage-suggestions": "", className: "flex flex-col gap-2 px-3", children: _.map((e) => {
|
|
232
|
+
const l = e.fields.map(N), f = l.length > 1 ? `${l.slice(0, -1).join(", ")} and ${l[l.length - 1]}` : l[0], B = [...new Set(Object.values(e.from).map(x))];
|
|
185
233
|
return /* @__PURE__ */ s(
|
|
186
234
|
"li",
|
|
187
235
|
{
|
|
@@ -189,11 +237,11 @@ function ge({
|
|
|
189
237
|
className: "flex flex-col gap-2 rounded-lg border border-slate-200 bg-white p-2.5 dark:border-border dark:bg-card",
|
|
190
238
|
children: [
|
|
191
239
|
/* @__PURE__ */ s("p", { className: "m-0 text-[12px] leading-snug text-slate-700 dark:text-foreground", children: [
|
|
192
|
-
/* @__PURE__ */ t(
|
|
240
|
+
/* @__PURE__ */ t(Q, { className: "mr-1 inline h-3.5 w-3.5 align-[-2px] text-slate-400" }),
|
|
193
241
|
"People usually change ",
|
|
194
|
-
/* @__PURE__ */ t("b", { className: "font-semibold", children:
|
|
242
|
+
/* @__PURE__ */ t("b", { className: "font-semibold", children: f }),
|
|
195
243
|
" together, but they sit in ",
|
|
196
|
-
|
|
244
|
+
B.join(" and "),
|
|
197
245
|
"."
|
|
198
246
|
] }),
|
|
199
247
|
/* @__PURE__ */ s("div", { className: "flex items-center gap-1.5", children: [
|
|
@@ -201,11 +249,11 @@ function ge({
|
|
|
201
249
|
"button",
|
|
202
250
|
{
|
|
203
251
|
type: "button",
|
|
204
|
-
onClick: () =>
|
|
252
|
+
onClick: () => y(e.ops, { label: `Move ${f} into ${x(e.target)}` }),
|
|
205
253
|
className: "inline-flex h-7 items-center rounded-md bg-nvr-cyan px-2.5 text-[12px] font-medium text-white transition-opacity hover:opacity-90",
|
|
206
254
|
children: [
|
|
207
255
|
"Move into ",
|
|
208
|
-
|
|
256
|
+
x(e.target)
|
|
209
257
|
]
|
|
210
258
|
}
|
|
211
259
|
),
|
|
@@ -213,7 +261,7 @@ function ge({
|
|
|
213
261
|
"button",
|
|
214
262
|
{
|
|
215
263
|
type: "button",
|
|
216
|
-
onClick: () =>
|
|
264
|
+
onClick: () => G((H) => new Set(H).add(e.id)),
|
|
217
265
|
className: "inline-flex h-7 items-center rounded-md px-2 text-[12px] text-slate-500 transition-colors hover:bg-muted hover:text-slate-800 dark:text-muted-foreground dark:hover:text-foreground",
|
|
218
266
|
children: "Not now"
|
|
219
267
|
}
|
|
@@ -224,9 +272,9 @@ function ge({
|
|
|
224
272
|
e.id
|
|
225
273
|
);
|
|
226
274
|
}) }),
|
|
227
|
-
/* @__PURE__ */ t(
|
|
275
|
+
/* @__PURE__ */ t(X, { bundle: r, collection: p, onOpenLayout: F })
|
|
228
276
|
] });
|
|
229
277
|
}
|
|
230
278
|
export {
|
|
231
|
-
|
|
279
|
+
Le as UsagePanel
|
|
232
280
|
};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { jsx as g, jsxs as k } from "react/jsx-runtime";
|
|
2
|
+
import { useQuery as x } from "@tanstack/react-query";
|
|
3
|
+
import { useMemo as f, useCallback as S, useSyncExternalStore as w } from "react";
|
|
4
|
+
import { useNivaroClient as y } from "../../../context.js";
|
|
5
|
+
import { get as R } from "../../../lib/commands.js";
|
|
6
|
+
import { cn as T } from "../../../lib/utils.js";
|
|
7
|
+
import { usageKeys as $ } from "./usage-api.js";
|
|
8
|
+
function L(e, r = !0) {
|
|
9
|
+
const t = y();
|
|
10
|
+
return x({
|
|
11
|
+
queryKey: $.refusals(e ?? 0),
|
|
12
|
+
queryFn: () => t.request(R(`/layout-usage/${e}/refusals`)).then((n) => (n == null ? void 0 : n.data) ?? null),
|
|
13
|
+
enabled: r && e != null,
|
|
14
|
+
staleTime: 5 * 6e4,
|
|
15
|
+
retry: !1
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
const q = 0.05, E = 0.2, N = 5;
|
|
19
|
+
function p(e) {
|
|
20
|
+
return e >= E ? "high" : e >= q ? "some" : "none";
|
|
21
|
+
}
|
|
22
|
+
function m(e) {
|
|
23
|
+
const r = e * 100;
|
|
24
|
+
return r > 0 && r < 1 ? "<1%" : `${Math.round(r)}%`;
|
|
25
|
+
}
|
|
26
|
+
function v(e, r, t) {
|
|
27
|
+
const n = [
|
|
28
|
+
e.required > 0 ? `${e.required} left empty while required` : null,
|
|
29
|
+
e.invalid > 0 ? `${e.invalid} broke another rule` : null
|
|
30
|
+
].filter(Boolean);
|
|
31
|
+
return `Refused ${e.refusals.toLocaleString()} of ${r.toLocaleString()} saves in ${t} days: ${n.join(", ")}`;
|
|
32
|
+
}
|
|
33
|
+
const F = {
|
|
34
|
+
none: "",
|
|
35
|
+
some: "bg-amber-50/70 ring-1 ring-amber-300 dark:bg-amber-500/10 dark:ring-amber-500/40",
|
|
36
|
+
high: "bg-red-50/70 ring-1 ring-red-300 dark:bg-red-500/10 dark:ring-red-500/40"
|
|
37
|
+
}, M = {
|
|
38
|
+
none: "bg-white text-slate-500 ring-slate-200 dark:bg-card dark:text-muted-foreground dark:ring-border",
|
|
39
|
+
some: "bg-amber-50 text-amber-800 ring-amber-200 dark:bg-amber-500/15 dark:text-amber-200 dark:ring-amber-500/30",
|
|
40
|
+
high: "bg-red-50 text-red-700 ring-red-200 dark:bg-red-500/15 dark:text-red-200 dark:ring-red-500/30"
|
|
41
|
+
};
|
|
42
|
+
function A({
|
|
43
|
+
f: e,
|
|
44
|
+
attempts: r,
|
|
45
|
+
days: t
|
|
46
|
+
}) {
|
|
47
|
+
const n = p(e.rate);
|
|
48
|
+
return /* @__PURE__ */ k(
|
|
49
|
+
"span",
|
|
50
|
+
{
|
|
51
|
+
"data-design-refusal": m(e.rate),
|
|
52
|
+
"data-refusal-tone": n,
|
|
53
|
+
"data-tip": v(e, r, t),
|
|
54
|
+
className: T(
|
|
55
|
+
"pointer-events-auto inline-flex items-center rounded px-1 text-[10.5px] tabular-nums ring-1",
|
|
56
|
+
M[n]
|
|
57
|
+
),
|
|
58
|
+
children: [
|
|
59
|
+
m(e.rate),
|
|
60
|
+
" refused",
|
|
61
|
+
/* @__PURE__ */ g("span", { className: "sr-only", children: " saves on this field" })
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
function C(e, r) {
|
|
67
|
+
if (!e || e.attempts < N || r.kind !== "field" && r.kind !== "header") return null;
|
|
68
|
+
const t = e.fields.find((n) => n.field === r.field);
|
|
69
|
+
return !t || t.refusals === 0 ? null : {
|
|
70
|
+
className: F[p(t.rate)],
|
|
71
|
+
chip: /* @__PURE__ */ g(A, { f: t, attempts: e.attempts, days: e.days })
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const b = "nvr:layout-editor:show-refusals", i = /* @__PURE__ */ new Set();
|
|
75
|
+
let a = null;
|
|
76
|
+
function I() {
|
|
77
|
+
if (a != null) return a;
|
|
78
|
+
try {
|
|
79
|
+
a = window.localStorage.getItem(b) === "1";
|
|
80
|
+
} catch {
|
|
81
|
+
a = !1;
|
|
82
|
+
}
|
|
83
|
+
return a;
|
|
84
|
+
}
|
|
85
|
+
function _(e) {
|
|
86
|
+
a = e;
|
|
87
|
+
try {
|
|
88
|
+
window.localStorage.setItem(b, e ? "1" : "0");
|
|
89
|
+
} catch {
|
|
90
|
+
}
|
|
91
|
+
for (const r of i) r();
|
|
92
|
+
}
|
|
93
|
+
function j() {
|
|
94
|
+
return [w(
|
|
95
|
+
(r) => (i.add(r), () => i.delete(r)),
|
|
96
|
+
I,
|
|
97
|
+
() => !1
|
|
98
|
+
), _];
|
|
99
|
+
}
|
|
100
|
+
function G(e) {
|
|
101
|
+
const [r, t] = j(), { data: n = null } = L(e, r), o = f(
|
|
102
|
+
() => r && n ? (s) => C(n, s) : null,
|
|
103
|
+
[r, n]
|
|
104
|
+
), u = f(() => /* @__PURE__ */ new WeakMap(), [o]), h = S(
|
|
105
|
+
(s) => {
|
|
106
|
+
if (!o) return s;
|
|
107
|
+
if (!s) return o;
|
|
108
|
+
const l = u.get(s);
|
|
109
|
+
if (l) return l;
|
|
110
|
+
const d = (c) => s(c) ?? o(c);
|
|
111
|
+
return u.set(s, d), d;
|
|
112
|
+
},
|
|
113
|
+
[o, u]
|
|
114
|
+
);
|
|
115
|
+
return { on: r, setOn: t, data: n, wrap: h };
|
|
116
|
+
}
|
|
117
|
+
export {
|
|
118
|
+
E as REFUSAL_HIGH,
|
|
119
|
+
q as REFUSAL_LOW,
|
|
120
|
+
N as REFUSAL_MIN_ATTEMPTS,
|
|
121
|
+
A as RefusalChip,
|
|
122
|
+
C as refusalOverlayFor,
|
|
123
|
+
m as refusalPct,
|
|
124
|
+
v as refusalTip,
|
|
125
|
+
p as refusalTone,
|
|
126
|
+
_ as setShowRefusals,
|
|
127
|
+
G as useRefusalLens,
|
|
128
|
+
L as useSaveRefusals,
|
|
129
|
+
j as useShowRefusals
|
|
130
|
+
};
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import { useQuery as a } from "@tanstack/react-query";
|
|
2
|
-
import { useState as
|
|
2
|
+
import { useState as f, useCallback as d, useMemo as y } from "react";
|
|
3
3
|
import { useNivaroClient as s } from "../../../context.js";
|
|
4
4
|
import { get as u } from "../../../lib/commands.js";
|
|
5
|
-
const
|
|
5
|
+
const l = {
|
|
6
6
|
fill: (e) => ["layout-editor", "usage", "fill", e],
|
|
7
7
|
today: (e) => ["layout-editor", "usage", "today", e],
|
|
8
8
|
friction: (e) => ["layout-editor", "usage", "friction", e],
|
|
9
|
-
coChanges: (e) => ["layout-editor", "usage", "co-changes", e]
|
|
9
|
+
coChanges: (e) => ["layout-editor", "usage", "co-changes", e],
|
|
10
|
+
refusals: (e) => ["layout-editor", "usage", "refusals", e]
|
|
10
11
|
};
|
|
11
12
|
function $(e, n = !0) {
|
|
12
13
|
const r = s();
|
|
13
14
|
return a({
|
|
14
|
-
queryKey:
|
|
15
|
+
queryKey: l.fill(e),
|
|
15
16
|
queryFn: async () => {
|
|
16
17
|
const t = await r.request(u(`/data-model/${encodeURIComponent(e)}/field-usage`)), o = t == null ? void 0 : t.data;
|
|
17
18
|
return {
|
|
18
19
|
total: Number((o == null ? void 0 : o.total) ?? 0),
|
|
19
|
-
pct: new Map(((o == null ? void 0 : o.fields) ?? []).map((
|
|
20
|
+
pct: new Map(((o == null ? void 0 : o.fields) ?? []).map((i) => [i.field, Number(i.pct)]))
|
|
20
21
|
};
|
|
21
22
|
},
|
|
22
23
|
enabled: n && !!e,
|
|
@@ -30,7 +31,7 @@ function q(e, n) {
|
|
|
30
31
|
function F(e, n = !0) {
|
|
31
32
|
const r = s();
|
|
32
33
|
return a({
|
|
33
|
-
queryKey:
|
|
34
|
+
queryKey: l.today(e ?? 0),
|
|
34
35
|
queryFn: () => r.request(u(`/layout-usage/${e}/today`)).then((t) => (t == null ? void 0 : t.data) ?? null),
|
|
35
36
|
enabled: n && e != null,
|
|
36
37
|
staleTime: 6e4,
|
|
@@ -48,7 +49,7 @@ function w(e) {
|
|
|
48
49
|
function C(e, n = !0) {
|
|
49
50
|
const r = s();
|
|
50
51
|
return a({
|
|
51
|
-
queryKey:
|
|
52
|
+
queryKey: l.friction(e),
|
|
52
53
|
queryFn: () => r.request(u(`/layout-usage/${e}/friction`)).then((t) => (t == null ? void 0 : t.data) ?? null),
|
|
53
54
|
enabled: n,
|
|
54
55
|
staleTime: 5 * 6e4,
|
|
@@ -58,7 +59,7 @@ function C(e, n = !0) {
|
|
|
58
59
|
function T(e, n = !0) {
|
|
59
60
|
const r = s();
|
|
60
61
|
return a({
|
|
61
|
-
queryKey:
|
|
62
|
+
queryKey: l.coChanges(e),
|
|
62
63
|
queryFn: () => r.request(
|
|
63
64
|
u(`/layout-usage/co-changes/${encodeURIComponent(e)}`)
|
|
64
65
|
).then((t) => (t == null ? void 0 : t.data) ?? null),
|
|
@@ -76,13 +77,13 @@ function b(e) {
|
|
|
76
77
|
}
|
|
77
78
|
const c = "nvr:layout-editor:show-fill";
|
|
78
79
|
function K() {
|
|
79
|
-
const [e, n] =
|
|
80
|
+
const [e, n] = f(() => {
|
|
80
81
|
try {
|
|
81
82
|
return window.localStorage.getItem(c) === "1";
|
|
82
83
|
} catch {
|
|
83
84
|
return !1;
|
|
84
85
|
}
|
|
85
|
-
}), r =
|
|
86
|
+
}), r = d((t) => {
|
|
86
87
|
n(t);
|
|
87
88
|
try {
|
|
88
89
|
window.localStorage.setItem(c, t ? "1" : "0");
|
|
@@ -94,7 +95,7 @@ function K() {
|
|
|
94
95
|
export {
|
|
95
96
|
q as fillText,
|
|
96
97
|
b as formatDuration,
|
|
97
|
-
|
|
98
|
+
l as usageKeys,
|
|
98
99
|
w as usageTodayText,
|
|
99
100
|
T as useCoChanges,
|
|
100
101
|
$ as useFieldFillRates,
|