@object-ui/plugin-detail 5.1.1 → 5.3.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/CHANGELOG.md +137 -0
- package/dist/index.js +176 -81
- package/dist/index.umd.cjs +3 -3
- package/dist/packages/plugin-detail/src/DetailTabs.d.ts.map +1 -1
- package/dist/packages/plugin-detail/src/DetailView.d.ts.map +1 -1
- package/dist/packages/plugin-detail/src/extractMentions.d.ts +27 -0
- package/dist/packages/plugin-detail/src/extractMentions.d.ts.map +1 -0
- package/dist/packages/plugin-detail/src/index.d.ts +2 -0
- package/dist/packages/plugin-detail/src/index.d.ts.map +1 -1
- package/dist/packages/plugin-detail/src/renderers/record-path.d.ts.map +1 -1
- package/dist/packages/plugin-detail/src/renderers/record-reference-rail.d.ts +8 -0
- package/dist/packages/plugin-detail/src/renderers/record-reference-rail.d.ts.map +1 -1
- package/dist/packages/plugin-detail/src/synth/buildDefaultPageSchema.d.ts +9 -0
- package/dist/packages/plugin-detail/src/synth/buildDefaultPageSchema.d.ts.map +1 -1
- package/dist/packages/plugin-detail/src/useDetailTranslation.d.ts.map +1 -1
- package/package.json +12 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,142 @@
|
|
|
1
1
|
# @object-ui/plugin-detail
|
|
2
2
|
|
|
3
|
+
## 5.3.0
|
|
4
|
+
|
|
5
|
+
## 5.2.1
|
|
6
|
+
|
|
7
|
+
## 5.2.0
|
|
8
|
+
|
|
9
|
+
### Minor Changes
|
|
10
|
+
|
|
11
|
+
- 7c441f5: End-to-end @-mention notifications.
|
|
12
|
+
|
|
13
|
+
`@object-ui/plugin-detail` now exports `extractMentions(text, suggestions)`
|
|
14
|
+
— a small utility that resolves `@<label>` tokens in a comment body to
|
|
15
|
+
user ids, using the same suggestion list that drives the in-editor
|
|
16
|
+
dropdown. Handles labels with spaces ("@QA Test"), CJK ("@王小明"),
|
|
17
|
+
longest-match disambiguation ("Anna Lee" wins over "Anna"), and ignores
|
|
18
|
+
unknown @-tokens. 9 unit tests.
|
|
19
|
+
|
|
20
|
+
`@object-ui/app-shell` `RecordDetailView` now:
|
|
21
|
+
1. Serializes the resolved mention ids into `sys_comment.mentions`
|
|
22
|
+
(previously hard-coded `'[]'`, so servers had no idea who was being
|
|
23
|
+
pinged).
|
|
24
|
+
2. Fan-outs a `sys_notification` row per mentioned recipient
|
|
25
|
+
(self-mentions are filtered as noise) with the canonical bell-inbox
|
|
26
|
+
shape: `type: 'mention'`, `recipient_id`, `actor_name`, `title`,
|
|
27
|
+
`body` preview (≤140 chars), `source_object`/`source_id`/
|
|
28
|
+
`source_comment_id`, `is_read: false`, `created_at`.
|
|
29
|
+
|
|
30
|
+
The notification write tolerates 404 silently, so deployments without
|
|
31
|
+
a notification collection degrade to the previous behavior (mention
|
|
32
|
+
text + highlight, no inbox row). Spec-compliant servers that emit
|
|
33
|
+
notifications via their own sys_comment after-create hook can ignore
|
|
34
|
+
the client-side write — the bell de-dupes by id at the polling layer.
|
|
35
|
+
|
|
36
|
+
- 70b5570: `record:path` now distinguishes won/lost terminal stages. Stages can opt
|
|
37
|
+
in via the new `terminal: 'won' | 'lost'` property on each stage entry,
|
|
38
|
+
and the renderer also falls back to a value/label heuristic (matches
|
|
39
|
+
`closed_lost`, `lost`, `failed`, `cancelled`, `失败`, `流失`, `丢单`, etc.)
|
|
40
|
+
so existing CRM-style picklists get the treatment without migration.
|
|
41
|
+
- **Lost** stages render in a visually separated group with a left
|
|
42
|
+
border, destructive (red) tint, pill shape, and `✗` glyph — mirroring
|
|
43
|
+
the Salesforce / HubSpot alt-terminus pattern that signals "this
|
|
44
|
+
breaks the forward path, not steps past it."
|
|
45
|
+
- **Won** terminus (the last stage of the forward chevron) gets a subtle
|
|
46
|
+
emerald wash + 🏆 glyph to read as "the goal," even before the record
|
|
47
|
+
reaches it.
|
|
48
|
+
- Mobile pill row distinguishes lost via color, since the layout doesn't
|
|
49
|
+
have room to fork the row.
|
|
50
|
+
|
|
51
|
+
- 3216f8a: `buildDefaultPageSchema` now accepts a `slots.rightRail` override that
|
|
52
|
+
contributes nodes to the aside (right-rail) region. The aside region is
|
|
53
|
+
emitted whenever either the auto-detected reference rail OR
|
|
54
|
+
`slots.rightRail` is non-empty (previously: only when 2+ related lists
|
|
55
|
+
were declared). Slot contributions are appended after the canonical
|
|
56
|
+
`record:reference_rail` so the "related summary" stays anchored at the
|
|
57
|
+
top while plugins can drop activity feeds, workflow status cards,
|
|
58
|
+
presence lists, etc. beneath it.
|
|
59
|
+
|
|
60
|
+
No change for existing schemas — the aside region only renders if
|
|
61
|
+
something opts in.
|
|
62
|
+
|
|
63
|
+
### Patch Changes
|
|
64
|
+
|
|
65
|
+
- a3cb88f: CRM UX polish batch:
|
|
66
|
+
- Kanban columns: drop the per-column rainbow top stripe. Lane border + header divider are sufficient; cards are now the loudest thing on screen (Linear / HubSpot pattern).
|
|
67
|
+
- Stage chevron (`record:path`): bump completed-stage contrast (emerald-800 text on emerald-500/15, was 700 on /10) and future-stage text from `foreground/70` to `foreground/85` for legibility.
|
|
68
|
+
- i18n: add `notifications.emptyUnread`, `notifications.filterUnread`, `notifications.filterAll` (en + zh) so the InboxPopover Unread/All sub-filter renders in the active locale.
|
|
69
|
+
- 5425608: CRM UX polish pass — calmer enterprise look across detail + kanban.
|
|
70
|
+
- **plugin-kanban**: column headers now use a 2px muted accent stripe with
|
|
71
|
+
neutral foreground titles + a quiet grey count pill instead of full
|
|
72
|
+
rainbow gradient + colored title + colored count. Pipeline boards
|
|
73
|
+
(Opportunity, Case, Task, Lead) look like Salesforce/Linear instead of
|
|
74
|
+
a toy. WIP-limit overflow remains destructive-red so urgency stays loud.
|
|
75
|
+
- **plugin-detail (`record:reference_rail`)**: new `hideEmpty` prop
|
|
76
|
+
(default true) collapses entries whose total === 0 into a single
|
|
77
|
+
`+ N empty (Quotes · Products …)` chip at the bottom of the rail.
|
|
78
|
+
Removes the 4–7 "No records" stack that dominated the aside.
|
|
79
|
+
- **plugin-detail (`record:path`)**: completed stages now render with an
|
|
80
|
+
emerald-tinted background + bold green check instead of low-contrast
|
|
81
|
+
`bg-muted text-muted-foreground` (which read as "light grey on white"
|
|
82
|
+
and was borderline unreadable).
|
|
83
|
+
- **app-shell (`RecordDetailView`)**: record-not-found short-circuit.
|
|
84
|
+
Previously a stale/missing recordId still rendered the page chrome
|
|
85
|
+
(rail, discussion, breadcrumb with the raw id), making invalid links
|
|
86
|
+
look like a partially broken page. Now renders a clean centered
|
|
87
|
+
`Empty` state with database icon + i18n'd "Record not found" copy.
|
|
88
|
+
- **i18n**: added `detail.showEmptyRelated_{one,other}` and
|
|
89
|
+
`empty.recordNotFound{,Description}` keys (en + zh).
|
|
90
|
+
|
|
91
|
+
- 5633edd: feat(detail,grid): tab + selection motion polish
|
|
92
|
+
|
|
93
|
+
**plugin-detail**
|
|
94
|
+
- `DetailTabs` and the auto-tabs path in `DetailView` (5 inline
|
|
95
|
+
`<TabsContent>` instances: details, related, activity, discussion,
|
|
96
|
+
history) now fade in when their tab becomes active, eliminating
|
|
97
|
+
the harsh flash when switching tabs.
|
|
98
|
+
|
|
99
|
+
**plugin-grid**
|
|
100
|
+
- `BulkActionBar` slides in from the bottom + fades in when a
|
|
101
|
+
selection is made, instead of popping into existence.
|
|
102
|
+
- The "N items selected" counter re-animates on every count change
|
|
103
|
+
(re-keyed on the count value with a small `zoom-in-90`), so users
|
|
104
|
+
see clear feedback as they tick/untick rows. `tabular-nums` keeps
|
|
105
|
+
the number from jittering during the animation.
|
|
106
|
+
|
|
107
|
+
All animations are wrapped in `motion-safe:` so prefers-reduced-motion
|
|
108
|
+
users keep the original instant UI. No new deps.
|
|
109
|
+
|
|
110
|
+
**Dialog / Sheet motion audit (informational, no code change)**
|
|
111
|
+
|
|
112
|
+
Verified `packages/components/src/ui/{dialog,alert-dialog,sheet}.tsx`:
|
|
113
|
+
Dialog + AlertDialog use a consistent `duration-200`. Sheet uses an
|
|
114
|
+
asymmetric `open:500ms / close:300ms` — this is the intentional
|
|
115
|
+
shadcn upstream default ("slower open feels purposeful"). No fixes
|
|
116
|
+
needed; these primitives live in the no-touch zone anyway.
|
|
117
|
+
|
|
118
|
+
- e919433: Stop silently assuming USD when a currency field has no `currency`
|
|
119
|
+
configured. For non-USD orgs (e.g. a CNY-based CRM seeded without an
|
|
120
|
+
explicit currency) the cells now render as plain locale-formatted
|
|
121
|
+
numbers (`150,000.00`) instead of `$150,000.00` — which was the #1
|
|
122
|
+
"why is my RMB showing as dollars?" bug.
|
|
123
|
+
|
|
124
|
+
Behavior change is opt-in via omission: when `currency` /
|
|
125
|
+
`defaultCurrency` is set on the field/column, formatting is unchanged.
|
|
126
|
+
|
|
127
|
+
Fixed call sites:
|
|
128
|
+
- `@object-ui/fields`: `formatCurrency`, `formatCompactCurrency`, and
|
|
129
|
+
`CurrencyCellRenderer` no longer default-param `'USD'`.
|
|
130
|
+
- `@object-ui/i18n`: `formatCurrency()` falls back to `formatNumber`
|
|
131
|
+
semantics when `currency` is omitted.
|
|
132
|
+
- `@object-ui/plugin-grid`: column-summary formatter (`Sum: 5,000,000`
|
|
133
|
+
instead of `Sum: $5,000,000.00`).
|
|
134
|
+
- `@object-ui/plugin-detail`: header-highlight currency formatter.
|
|
135
|
+
- `@object-ui/plugin-dashboard`: `ObjectMetricWidget` inferred
|
|
136
|
+
currency now resolves to `undefined` (not `'USD'`) for un-tagged
|
|
137
|
+
fields, so `MetricWidget`'s `isCurrency` heuristic falls through
|
|
138
|
+
to plain number formatting.
|
|
139
|
+
|
|
3
140
|
## 5.1.1
|
|
4
141
|
|
|
5
142
|
## 5.1.0
|
package/dist/index.js
CHANGED
|
@@ -159,6 +159,8 @@ var Ct = {
|
|
|
159
159
|
"detail.nextRecordKey": "Next record (→)",
|
|
160
160
|
"detail.lastRecord": "Last record (End)",
|
|
161
161
|
"detail.noRecords": "No records",
|
|
162
|
+
"detail.showEmptyRelated_one": "+ {{count}} empty",
|
|
163
|
+
"detail.showEmptyRelated_other": "+ {{count}} empty",
|
|
162
164
|
"detail.searchWhileNavigating": "Search while navigating",
|
|
163
165
|
"detail.searchRecords": "Search records…",
|
|
164
166
|
"detail.allActivity": "All Activity",
|
|
@@ -416,7 +418,7 @@ var Tt = ({ section: e, data: t, className: r, objectSchema: i, objectName: a, i
|
|
|
416
418
|
}, e.key))
|
|
417
419
|
}), o.map((e) => /* @__PURE__ */ Z(L, {
|
|
418
420
|
value: e.key,
|
|
419
|
-
className: "mt-4",
|
|
421
|
+
className: "mt-4 motion-safe:data-[state=active]:animate-in motion-safe:data-[state=active]:fade-in-0 motion-safe:duration-150",
|
|
420
422
|
children: /* @__PURE__ */ Z(n.Suspense, {
|
|
421
423
|
fallback: null,
|
|
422
424
|
children: Array.isArray(e.content) ? /* @__PURE__ */ Z("div", {
|
|
@@ -1845,11 +1847,14 @@ var tn = ({ schema: e, dataSource: r, className: i, onEdit: a, onDelete: o, onBa
|
|
|
1845
1847
|
try {
|
|
1846
1848
|
if (i === "currency") {
|
|
1847
1849
|
let e = Number(t);
|
|
1848
|
-
Number.isNaN(e)
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1850
|
+
if (!Number.isNaN(e)) {
|
|
1851
|
+
let t = n?.currency || r?.currency;
|
|
1852
|
+
a = t ? new Intl.NumberFormat(void 0, {
|
|
1853
|
+
style: "currency",
|
|
1854
|
+
currency: t,
|
|
1855
|
+
maximumFractionDigits: 0
|
|
1856
|
+
}).format(e) : new Intl.NumberFormat(void 0, { maximumFractionDigits: 0 }).format(e);
|
|
1857
|
+
}
|
|
1853
1858
|
} else if (i === "date" || i === "datetime") {
|
|
1854
1859
|
let e = new Date(t);
|
|
1855
1860
|
Number.isNaN(e.getTime()) || (a = i === "datetime" ? e.toLocaleString(void 0, {
|
|
@@ -2176,12 +2181,12 @@ var tn = ({ schema: e, dataSource: r, className: i, onEdit: a, onDelete: o, onBa
|
|
|
2176
2181
|
}),
|
|
2177
2182
|
/* @__PURE__ */ Z(L, {
|
|
2178
2183
|
value: "details",
|
|
2179
|
-
className: "mt-4",
|
|
2184
|
+
className: "mt-4 motion-safe:data-[state=active]:animate-in motion-safe:data-[state=active]:fade-in-0 motion-safe:duration-150",
|
|
2180
2185
|
children: a
|
|
2181
2186
|
}),
|
|
2182
2187
|
e && /* @__PURE__ */ Z(L, {
|
|
2183
2188
|
value: "related",
|
|
2184
|
-
className: "mt-4",
|
|
2189
|
+
className: "mt-4 motion-safe:data-[state=active]:animate-in motion-safe:data-[state=active]:fade-in-0 motion-safe:duration-150",
|
|
2185
2190
|
children: /* @__PURE__ */ Z("div", {
|
|
2186
2191
|
className: "space-y-3",
|
|
2187
2192
|
children: we.map((e, t) => /* @__PURE__ */ Z(Ot, {
|
|
@@ -2207,17 +2212,17 @@ var tn = ({ schema: e, dataSource: r, className: i, onEdit: a, onDelete: o, onBa
|
|
|
2207
2212
|
}),
|
|
2208
2213
|
t && /* @__PURE__ */ Z(L, {
|
|
2209
2214
|
value: "activity",
|
|
2210
|
-
className: "mt-4",
|
|
2215
|
+
className: "mt-4 motion-safe:data-[state=active]:animate-in motion-safe:data-[state=active]:fade-in-0 motion-safe:duration-150",
|
|
2211
2216
|
children: /* @__PURE__ */ Z(Rt, { activities: q.activities })
|
|
2212
2217
|
}),
|
|
2213
2218
|
n && /* @__PURE__ */ Z(L, {
|
|
2214
2219
|
value: "discussion",
|
|
2215
|
-
className: "mt-4",
|
|
2220
|
+
className: "mt-4 motion-safe:data-[state=active]:animate-in motion-safe:data-[state=active]:fade-in-0 motion-safe:duration-150",
|
|
2216
2221
|
children: u
|
|
2217
2222
|
}),
|
|
2218
2223
|
i && /* @__PURE__ */ Z(L, {
|
|
2219
2224
|
value: "history",
|
|
2220
|
-
className: "mt-4",
|
|
2225
|
+
className: "mt-4 motion-safe:data-[state=active]:animate-in motion-safe:data-[state=active]:fade-in-0 motion-safe:duration-150",
|
|
2221
2226
|
children: /* @__PURE__ */ Z(Gt, {
|
|
2222
2227
|
entries: q.history.entries,
|
|
2223
2228
|
loading: q.history.loading,
|
|
@@ -3595,14 +3600,24 @@ var Mn = ({ items: e, config: t, filterMode: r, onFilterChange: i, hasMore: a =
|
|
|
3595
3600
|
let i = it(), { translateOptions: a } = ot(), { designer: o } = Rn(n), s = Array.isArray(e.stages) ? e.stages : [], c = e.statusField, l = r.useMemo(() => {
|
|
3596
3601
|
if (s.length === 0 || !c || !i?.objectName) return s;
|
|
3597
3602
|
let e = a(i.objectName, c, s);
|
|
3598
|
-
return Array.isArray(e) && e.length === s.length ?
|
|
3603
|
+
return Array.isArray(e) && e.length === s.length ? s.map((t, n) => ({
|
|
3604
|
+
...t,
|
|
3605
|
+
label: e[n]?.label ?? t.label
|
|
3606
|
+
})) : s;
|
|
3599
3607
|
}, [
|
|
3600
3608
|
s,
|
|
3601
3609
|
c,
|
|
3602
3610
|
i?.objectName,
|
|
3603
3611
|
a
|
|
3604
|
-
]), u = c && i?.data ? i.data[c] : void 0, d = l.
|
|
3605
|
-
|
|
3612
|
+
]), u = c && i?.data ? i.data[c] : void 0, d = /(^|[_-\s])(closed_)?(lost|failed?|cancell?ed|失败|流失|丢单|败)([_-\s]|$)/i, f = /(^|[_-\s])(closed_)?(won|success|成交|赢|完成)([_-\s]|$)/i, p = l.map((e) => {
|
|
3613
|
+
if (e.terminal) return e.terminal;
|
|
3614
|
+
let t = `${String(e.value ?? "")} ${String(e.label ?? "")}`;
|
|
3615
|
+
if (d.test(t)) return "lost";
|
|
3616
|
+
if (f.test(t)) return "won";
|
|
3617
|
+
}), m = p.findIndex((e) => e === "lost"), h = m === -1 ? l : l.slice(0, m), g = m === -1 ? [] : l.slice(m), _ = m === -1 ? p : p.slice(0, m), v = l.findIndex((e) => e.value === u);
|
|
3618
|
+
v < 0 && (v = -1);
|
|
3619
|
+
let y = m !== -1 && v >= m;
|
|
3620
|
+
if (l.length === 0) return /* @__PURE__ */ Z("div", {
|
|
3606
3621
|
className: t,
|
|
3607
3622
|
...o,
|
|
3608
3623
|
children: /* @__PURE__ */ Z("div", {
|
|
@@ -3610,55 +3625,95 @@ var Mn = ({ items: e, config: t, filterMode: r, onFilterChange: i, hasMore: a =
|
|
|
3610
3625
|
children: "record:path — no stages configured"
|
|
3611
3626
|
})
|
|
3612
3627
|
});
|
|
3613
|
-
let
|
|
3628
|
+
let b = (e, t) => {
|
|
3614
3629
|
if (l.length !== 1) return e === 0 ? "polygon(0 0, calc(100% - 14px) 0, 100% 50%, calc(100% - 14px) 100%, 0 100%)" : e === t ? "polygon(0 0, 100% 0, 100% 100%, 0 100%, 14px 50%)" : "polygon(0 0, calc(100% - 14px) 0, 100% 50%, calc(100% - 14px) 100%, 0 100%, 14px 50%)";
|
|
3615
|
-
},
|
|
3630
|
+
}, x = h.length - 1;
|
|
3616
3631
|
return /* @__PURE__ */ Q("div", {
|
|
3617
3632
|
className: U("w-full", t),
|
|
3618
3633
|
...o,
|
|
3619
|
-
children: [/* @__PURE__ */
|
|
3620
|
-
className: "hidden sm:flex w-full items-stretch",
|
|
3634
|
+
children: [/* @__PURE__ */ Q("div", {
|
|
3635
|
+
className: "hidden sm:flex w-full items-stretch gap-2",
|
|
3621
3636
|
role: "list",
|
|
3622
3637
|
"aria-label": e.aria?.label || "Record path",
|
|
3623
|
-
children:
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
className: "
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
children:
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3638
|
+
children: [/* @__PURE__ */ Z("div", {
|
|
3639
|
+
className: "flex flex-1 items-stretch",
|
|
3640
|
+
children: h.map((e, t) => {
|
|
3641
|
+
let n = !y && v >= 0 && t < v, r = !y && t === v, i = _[t] === "won" && t === x, a = b(t, x);
|
|
3642
|
+
return /* @__PURE__ */ Z("div", {
|
|
3643
|
+
role: "listitem",
|
|
3644
|
+
"aria-current": r ? "step" : void 0,
|
|
3645
|
+
style: a ? {
|
|
3646
|
+
clipPath: a,
|
|
3647
|
+
WebkitClipPath: a
|
|
3648
|
+
} : void 0,
|
|
3649
|
+
className: U("relative flex-1 min-w-0 px-5 py-2 text-xs font-medium text-center", t > 0 && "-ml-2", h.length === 1 && "rounded-md border", r && "bg-primary text-primary-foreground shadow-sm ring-1 ring-primary/40", n && "bg-emerald-500/15 text-emerald-800 dark:text-emerald-200", !r && !n && i && "bg-emerald-500/5 text-emerald-700/85 dark:text-emerald-300/85 border border-emerald-500/20", !r && !n && !i && "bg-background text-foreground/85 border border-border/60"),
|
|
3650
|
+
children: /* @__PURE__ */ Q("span", {
|
|
3651
|
+
className: "inline-flex items-center gap-1.5 truncate",
|
|
3652
|
+
style: {
|
|
3653
|
+
paddingLeft: t === 0 ? 0 : `${14 / 2}px`,
|
|
3654
|
+
paddingRight: t === x ? 0 : `${14 / 2}px`
|
|
3655
|
+
},
|
|
3656
|
+
children: [
|
|
3657
|
+
n && /* @__PURE__ */ Z("span", {
|
|
3658
|
+
"aria-hidden": !0,
|
|
3659
|
+
className: "text-emerald-600 dark:text-emerald-400 font-semibold",
|
|
3660
|
+
children: "✓"
|
|
3661
|
+
}),
|
|
3662
|
+
i && !r && /* @__PURE__ */ Z("span", {
|
|
3663
|
+
"aria-hidden": !0,
|
|
3664
|
+
className: "opacity-70",
|
|
3665
|
+
children: "🏆"
|
|
3666
|
+
}),
|
|
3667
|
+
e.label
|
|
3668
|
+
]
|
|
3669
|
+
})
|
|
3670
|
+
}, `${e.value}-${t}`);
|
|
3671
|
+
})
|
|
3672
|
+
}), g.length > 0 && /* @__PURE__ */ Z("div", {
|
|
3673
|
+
className: "flex items-stretch gap-1 pl-2 border-l border-border/40",
|
|
3674
|
+
"aria-label": "Alternative terminal stages",
|
|
3675
|
+
children: g.map((e, t) => {
|
|
3676
|
+
let n = m + t === v;
|
|
3677
|
+
return /* @__PURE__ */ Z("div", {
|
|
3678
|
+
role: "listitem",
|
|
3679
|
+
"aria-current": n ? "step" : void 0,
|
|
3680
|
+
className: U("shrink-0 px-3 py-2 text-xs font-medium rounded-md border whitespace-nowrap", n && "bg-destructive text-destructive-foreground border-destructive shadow-sm ring-1 ring-destructive/40", !n && "bg-destructive/5 text-destructive/85 border-destructive/20"),
|
|
3681
|
+
children: /* @__PURE__ */ Q("span", {
|
|
3682
|
+
className: "inline-flex items-center gap-1",
|
|
3683
|
+
children: [/* @__PURE__ */ Z("span", {
|
|
3684
|
+
"aria-hidden": !0,
|
|
3685
|
+
className: "opacity-70",
|
|
3686
|
+
children: "✗"
|
|
3687
|
+
}), e.label]
|
|
3688
|
+
})
|
|
3689
|
+
}, `${e.value}-lost-${t}`);
|
|
3690
|
+
})
|
|
3691
|
+
})]
|
|
3646
3692
|
}), /* @__PURE__ */ Z("div", {
|
|
3647
3693
|
className: "flex sm:hidden w-full items-stretch gap-1 overflow-x-auto pb-1 -mx-1 px-1 [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
3648
3694
|
role: "list",
|
|
3649
3695
|
"aria-label": e.aria?.label || "Record path",
|
|
3650
3696
|
children: l.map((e, t) => {
|
|
3651
|
-
let n =
|
|
3697
|
+
let n = p[t] === "lost", r = !n && !y && v >= 0 && t < v, i = t === v;
|
|
3652
3698
|
return /* @__PURE__ */ Z("div", {
|
|
3653
3699
|
role: "listitem",
|
|
3654
|
-
"aria-current":
|
|
3655
|
-
className: U("shrink-0 px-3 py-1.5 rounded-full text-xs font-medium border whitespace-nowrap",
|
|
3700
|
+
"aria-current": i ? "step" : void 0,
|
|
3701
|
+
className: U("shrink-0 px-3 py-1.5 rounded-full text-xs font-medium border whitespace-nowrap", n && i && "bg-destructive text-destructive-foreground border-destructive shadow-sm", n && !i && "bg-destructive/5 text-destructive/85 border-destructive/20", !n && i && "bg-primary text-primary-foreground border-primary shadow-sm ring-1 ring-primary/40", !n && r && "bg-emerald-500/15 text-emerald-800 dark:text-emerald-200 border-emerald-500/30", !n && !i && !r && "bg-background text-foreground/85 border-border/60"),
|
|
3656
3702
|
children: /* @__PURE__ */ Q("span", {
|
|
3657
3703
|
className: "inline-flex items-center gap-1",
|
|
3658
|
-
children: [
|
|
3659
|
-
"
|
|
3660
|
-
|
|
3661
|
-
|
|
3704
|
+
children: [
|
|
3705
|
+
n && /* @__PURE__ */ Z("span", {
|
|
3706
|
+
"aria-hidden": !0,
|
|
3707
|
+
className: "opacity-70",
|
|
3708
|
+
children: "✗"
|
|
3709
|
+
}),
|
|
3710
|
+
!n && r && /* @__PURE__ */ Z("span", {
|
|
3711
|
+
"aria-hidden": !0,
|
|
3712
|
+
className: "text-emerald-600 dark:text-emerald-400 font-semibold",
|
|
3713
|
+
children: "✓"
|
|
3714
|
+
}),
|
|
3715
|
+
e.label
|
|
3716
|
+
]
|
|
3662
3717
|
})
|
|
3663
3718
|
}, `${e.value}-${t}-m`);
|
|
3664
3719
|
})
|
|
@@ -3758,7 +3813,7 @@ var Mn = ({ items: e, config: t, filterMode: r, onFilterChange: i, hasMore: a =
|
|
|
3758
3813
|
};
|
|
3759
3814
|
}, Gn = (e) => e.replace(/[_-]+/g, " ").replace(/\b\w/g, (e) => e.toUpperCase()).trim(), Kn = (e) => e?.name || e?.title || e?.subject || e?.label || e?.id || "—", qn = ({ schema: e = {}, className: t, ...n }) => {
|
|
3760
3815
|
let i = it(), a = ot(), { t: o } = $(), { designer: s } = Wn(n), c = gt().appName, l = Array.isArray(e.entries) ? e.entries : Array.isArray(e.properties?.entries) ? e.properties.entries : [], u = i?.recordId, d = i?.dataSource, [f, p] = r.useState({});
|
|
3761
|
-
|
|
3816
|
+
if (r.useEffect(() => {
|
|
3762
3817
|
if (!d?.find || !u || l.length === 0) return;
|
|
3763
3818
|
let e = !1;
|
|
3764
3819
|
return l.forEach((t) => {
|
|
@@ -3803,10 +3858,18 @@ var Mn = ({ items: e, config: t, filterMode: r, onFilterChange: i, hasMore: a =
|
|
|
3803
3858
|
d,
|
|
3804
3859
|
u,
|
|
3805
3860
|
JSON.stringify(l.map((e) => `${e.objectName}:${e.relationshipField}:${e.limit ?? 3}`))
|
|
3806
|
-
]), l.length === 0
|
|
3861
|
+
]), l.length === 0) return null;
|
|
3862
|
+
let m = e.hideEmpty !== !1, [g, x] = r.useState(!1), S = new Set(l.filter((e) => {
|
|
3863
|
+
let t = f[e.objectName];
|
|
3864
|
+
return m && t && !t.loading && !t.error && t.total === 0;
|
|
3865
|
+
}).map((e) => e.objectName)), C = l.filter((e) => g || !S.has(e.objectName)), w = l.filter((e) => S.has(e.objectName)).map((e) => e.title || (a?.objectLabel ? a.objectLabel({
|
|
3866
|
+
name: e.objectName,
|
|
3867
|
+
label: Gn(e.objectName)
|
|
3868
|
+
}) : Gn(e.objectName)));
|
|
3869
|
+
return /* @__PURE__ */ Q("div", {
|
|
3807
3870
|
className: U("flex flex-col gap-3", e.className, t),
|
|
3808
3871
|
...s,
|
|
3809
|
-
children:
|
|
3872
|
+
children: [C.map((e) => {
|
|
3810
3873
|
let t = e.objectName, n = f[t] || {
|
|
3811
3874
|
loading: !0,
|
|
3812
3875
|
total: 0,
|
|
@@ -3869,7 +3932,23 @@ var Mn = ({ items: e, config: t, filterMode: r, onFilterChange: i, hasMore: a =
|
|
|
3869
3932
|
})
|
|
3870
3933
|
})]
|
|
3871
3934
|
}, t);
|
|
3872
|
-
})
|
|
3935
|
+
}), !g && w.length > 0 && /* @__PURE__ */ Q("button", {
|
|
3936
|
+
type: "button",
|
|
3937
|
+
onClick: () => x(!0),
|
|
3938
|
+
className: "self-start inline-flex items-center gap-1.5 text-[11px] text-muted-foreground hover:text-foreground transition-colors px-2.5 py-1 rounded-md border border-dashed border-border/60 hover:border-border bg-background",
|
|
3939
|
+
title: w.join(" · "),
|
|
3940
|
+
children: [/* @__PURE__ */ Z("span", { children: o("detail.showEmptyRelated", {
|
|
3941
|
+
defaultValue: "+ {{count}} empty",
|
|
3942
|
+
count: w.length
|
|
3943
|
+
}) }), /* @__PURE__ */ Q("span", {
|
|
3944
|
+
className: "truncate max-w-[180px] text-muted-foreground/70",
|
|
3945
|
+
children: [
|
|
3946
|
+
"(",
|
|
3947
|
+
w.join(" · "),
|
|
3948
|
+
")"
|
|
3949
|
+
]
|
|
3950
|
+
})]
|
|
3951
|
+
})]
|
|
3873
3952
|
});
|
|
3874
3953
|
}, Jn = new Set([
|
|
3875
3954
|
"id",
|
|
@@ -4934,11 +5013,23 @@ function gr(e, t, n) {
|
|
|
4934
5013
|
};
|
|
4935
5014
|
}
|
|
4936
5015
|
//#endregion
|
|
5016
|
+
//#region src/extractMentions.ts
|
|
5017
|
+
function _r(e, t) {
|
|
5018
|
+
if (!e || !t.length) return [];
|
|
5019
|
+
let n = [...t].sort((e, t) => t.label.length - e.label.length), r = e, i = /* @__PURE__ */ new Set();
|
|
5020
|
+
for (let e of n) {
|
|
5021
|
+
if (!e.label) continue;
|
|
5022
|
+
let t = e.label.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), n = RegExp(`@${t}(?![\\p{L}\\p{N}_])`, "gu");
|
|
5023
|
+
n.test(r) && (i.add(e.id), r = r.replace(n, (e) => " ".repeat(e.length)));
|
|
5024
|
+
}
|
|
5025
|
+
return [...i];
|
|
5026
|
+
}
|
|
5027
|
+
//#endregion
|
|
4937
5028
|
//#region src/synth/buildDefaultPageSchema.ts
|
|
4938
|
-
function
|
|
5029
|
+
function vr(e) {
|
|
4939
5030
|
return e == null ? [] : Array.isArray(e) ? e.filter((e) => e != null) : [e];
|
|
4940
5031
|
}
|
|
4941
|
-
function
|
|
5032
|
+
function yr(e) {
|
|
4942
5033
|
if (!e) return null;
|
|
4943
5034
|
if (e.stageField) return e.stageField;
|
|
4944
5035
|
let t = e.fields || {};
|
|
@@ -4954,7 +5045,7 @@ function vr(e) {
|
|
|
4954
5045
|
}
|
|
4955
5046
|
return null;
|
|
4956
5047
|
}
|
|
4957
|
-
function
|
|
5048
|
+
function br(e, t) {
|
|
4958
5049
|
if (!e || !t) return null;
|
|
4959
5050
|
let n = e.fields?.[t]?.options;
|
|
4960
5051
|
return !Array.isArray(n) || n.length === 0 ? null : n.map((e) => ({
|
|
@@ -4962,7 +5053,7 @@ function yr(e, t) {
|
|
|
4962
5053
|
label: e.label
|
|
4963
5054
|
}));
|
|
4964
5055
|
}
|
|
4965
|
-
function
|
|
5056
|
+
function xr(e, t, n = 4) {
|
|
4966
5057
|
if (!e) return [];
|
|
4967
5058
|
if (Array.isArray(e.highlightFields) && e.highlightFields.length > 0) return e.highlightFields.slice(0, n);
|
|
4968
5059
|
let r = new Set([
|
|
@@ -5036,22 +5127,22 @@ function br(e, t, n = 4) {
|
|
|
5036
5127
|
}
|
|
5037
5128
|
return o;
|
|
5038
5129
|
}
|
|
5039
|
-
function
|
|
5130
|
+
function Sr(e, t = {}) {
|
|
5040
5131
|
return {
|
|
5041
5132
|
type: "page:header",
|
|
5042
5133
|
recordChrome: t.recordChrome !== !1,
|
|
5043
5134
|
...Array.isArray(t.actions) && t.actions.length > 0 ? { actions: t.actions } : {}
|
|
5044
5135
|
};
|
|
5045
5136
|
}
|
|
5046
|
-
function
|
|
5137
|
+
function Cr(e, t) {
|
|
5047
5138
|
return !Array.isArray(t) || t.length === 0 ? null : {
|
|
5048
5139
|
type: "record:quick_actions",
|
|
5049
5140
|
actions: t,
|
|
5050
5141
|
location: "record_header"
|
|
5051
5142
|
};
|
|
5052
5143
|
}
|
|
5053
|
-
function
|
|
5054
|
-
let n = t.statusField ??
|
|
5144
|
+
function wr(e, t = {}) {
|
|
5145
|
+
let n = t.statusField ?? yr(e), r = t.stages ?? (n ? br(e, n) : null), i = t.highlightFields ?? xr(e, n), a = [];
|
|
5055
5146
|
return !t.hideHighlights && i.length > 0 && a.push({
|
|
5056
5147
|
type: "record:highlights",
|
|
5057
5148
|
fields: i
|
|
@@ -5061,17 +5152,17 @@ function Cr(e, t = {}) {
|
|
|
5061
5152
|
stages: r
|
|
5062
5153
|
}), a;
|
|
5063
5154
|
}
|
|
5064
|
-
function
|
|
5155
|
+
function Tr(e, t, n) {
|
|
5065
5156
|
return {
|
|
5066
5157
|
type: "record:details",
|
|
5067
5158
|
sections: t,
|
|
5068
5159
|
...n && n.length > 0 ? { hideFields: n } : {}
|
|
5069
5160
|
};
|
|
5070
5161
|
}
|
|
5071
|
-
function
|
|
5072
|
-
let n = t.statusField ??
|
|
5162
|
+
function Er(e, t = {}) {
|
|
5163
|
+
let n = t.statusField ?? yr(e), r = t.highlightFields ?? xr(e, n), i = [{
|
|
5073
5164
|
label: "Details",
|
|
5074
|
-
children: [
|
|
5165
|
+
children: [Tr(e, t.sections, r)]
|
|
5075
5166
|
}];
|
|
5076
5167
|
return !t.hideRelatedTab && Array.isArray(t.related) && t.related.length > 0 && i.push({
|
|
5077
5168
|
label: "Related",
|
|
@@ -5100,15 +5191,15 @@ function Tr(e, t = {}) {
|
|
|
5100
5191
|
items: i
|
|
5101
5192
|
};
|
|
5102
5193
|
}
|
|
5103
|
-
function
|
|
5194
|
+
function Dr() {
|
|
5104
5195
|
return { type: "record:discussion" };
|
|
5105
5196
|
}
|
|
5106
|
-
function
|
|
5197
|
+
function Or(e, t = {}) {
|
|
5107
5198
|
let n = t.slots || {}, r = [];
|
|
5108
|
-
"header" in n && n.header !== void 0 ? r.push(...
|
|
5199
|
+
"header" in n && n.header !== void 0 ? r.push(...vr(n.header)) : r.push(Sr(e, {
|
|
5109
5200
|
recordChrome: t.recordChrome,
|
|
5110
5201
|
actions: t.headerActions
|
|
5111
|
-
})), "actions" in n && n.actions !== void 0 && r.push(...
|
|
5202
|
+
})), "actions" in n && n.actions !== void 0 && r.push(...vr(n.actions)), "highlights" in n && n.highlights !== void 0 ? r.push(...vr(n.highlights)) : r.push(...wr(e, {
|
|
5112
5203
|
highlightFields: t.highlightFields,
|
|
5113
5204
|
statusField: t.statusField,
|
|
5114
5205
|
stages: t.stages,
|
|
@@ -5116,9 +5207,9 @@ function Dr(e, t = {}) {
|
|
|
5116
5207
|
hidePath: t.hidePath
|
|
5117
5208
|
}));
|
|
5118
5209
|
let i = !t.hideReferenceRail && Array.isArray(t.related) && t.related.length >= 2, a = t.hideRelatedTab ?? i;
|
|
5119
|
-
if ("tabs" in n && n.tabs !== void 0) r.push(...
|
|
5210
|
+
if ("tabs" in n && n.tabs !== void 0) r.push(...vr(n.tabs));
|
|
5120
5211
|
else if ("details" in n && n.details !== void 0) {
|
|
5121
|
-
let i =
|
|
5212
|
+
let i = vr(n.details), o = Er(e, {
|
|
5122
5213
|
sections: t.sections,
|
|
5123
5214
|
related: t.related,
|
|
5124
5215
|
showActivity: t.showActivity,
|
|
@@ -5131,7 +5222,7 @@ function Dr(e, t = {}) {
|
|
|
5131
5222
|
...o.items[0],
|
|
5132
5223
|
children: i
|
|
5133
5224
|
}), r.push(o);
|
|
5134
|
-
} else r.push(
|
|
5225
|
+
} else r.push(Er(e, {
|
|
5135
5226
|
sections: t.sections,
|
|
5136
5227
|
related: t.related,
|
|
5137
5228
|
showActivity: t.showActivity,
|
|
@@ -5140,17 +5231,15 @@ function Dr(e, t = {}) {
|
|
|
5140
5231
|
statusField: t.statusField,
|
|
5141
5232
|
hideRelatedTab: a
|
|
5142
5233
|
}));
|
|
5143
|
-
"discussion" in n && n.discussion !== void 0 ? r.push(...
|
|
5234
|
+
"discussion" in n && n.discussion !== void 0 ? r.push(...vr(n.discussion)) : t.hideDiscussion || r.push(Dr());
|
|
5144
5235
|
let o = [{
|
|
5145
5236
|
name: "main",
|
|
5146
5237
|
width: "full",
|
|
5147
5238
|
components: r
|
|
5148
|
-
}];
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
className: "hidden xl:flex flex-col gap-4",
|
|
5153
|
-
components: [{
|
|
5239
|
+
}], s = vr(n.rightRail);
|
|
5240
|
+
if (i || s.length > 0) {
|
|
5241
|
+
let e = [];
|
|
5242
|
+
i && e.push({
|
|
5154
5243
|
type: "record:reference_rail",
|
|
5155
5244
|
entries: t.related.map((e) => ({
|
|
5156
5245
|
objectName: e.objectName,
|
|
@@ -5159,8 +5248,14 @@ function Dr(e, t = {}) {
|
|
|
5159
5248
|
icon: e.icon,
|
|
5160
5249
|
limit: 3
|
|
5161
5250
|
}))
|
|
5162
|
-
}
|
|
5163
|
-
|
|
5251
|
+
}), s.length > 0 && e.push(...s), o.push({
|
|
5252
|
+
name: "aside",
|
|
5253
|
+
width: "small",
|
|
5254
|
+
className: "hidden xl:flex flex-col gap-4",
|
|
5255
|
+
components: e
|
|
5256
|
+
});
|
|
5257
|
+
}
|
|
5258
|
+
return {
|
|
5164
5259
|
type: "record",
|
|
5165
5260
|
pageType: "record",
|
|
5166
5261
|
object: e?.name,
|
|
@@ -5471,4 +5566,4 @@ e.register("detail-view", tn, {
|
|
|
5471
5566
|
icon: "PanelRight"
|
|
5472
5567
|
});
|
|
5473
5568
|
//#endregion
|
|
5474
|
-
export { Rt as ActivityTimeline, En as CommentAttachment, mr as CommentInput, an as ConcurrentUpdateDialog, Ct as DETAIL_DEFAULT_TRANSLATIONS, Tt as DetailSection, Et as DetailTabs, tn as DetailView, ir as DiffView, hn as FieldChangeItem, At as HeaderHighlight, Gt as HistoryTimeline, $n as InlineCreateRelated, hr as MentionAutocomplete, pr as PointInTimeRestore, _n as ReactionPicker, Pn as RecordActivityRenderer, Mn as RecordActivityTimeline, Fn as RecordChatterPanel, Ln as RecordChatterRenderer, Mt as RecordComments, Zn as RecordDetailDrawer, ln as RecordDetailsRenderer, mn as RecordHighlightsRenderer, Un as RecordHistoryRenderer, Qt as RecordMetaFooter, ar as RecordNavigationEnhanced, zn as RecordPathRenderer, Vn as RecordQuickActionsRenderer, qn as RecordReferenceRailRenderer, fn as RecordRelatedListRenderer, Ot as RelatedList, dr as RelationshipGraph, Sn as RichTextCommentInput, kt as SectionGroup, bn as SubscriptionToggle, yn as ThreadedReplies, bt as applyAutoSpan, xt as applyDetailAutoLayout,
|
|
5569
|
+
export { Rt as ActivityTimeline, En as CommentAttachment, mr as CommentInput, an as ConcurrentUpdateDialog, Ct as DETAIL_DEFAULT_TRANSLATIONS, Tt as DetailSection, Et as DetailTabs, tn as DetailView, ir as DiffView, hn as FieldChangeItem, At as HeaderHighlight, Gt as HistoryTimeline, $n as InlineCreateRelated, hr as MentionAutocomplete, pr as PointInTimeRestore, _n as ReactionPicker, Pn as RecordActivityRenderer, Mn as RecordActivityTimeline, Fn as RecordChatterPanel, Ln as RecordChatterRenderer, Mt as RecordComments, Zn as RecordDetailDrawer, ln as RecordDetailsRenderer, mn as RecordHighlightsRenderer, Un as RecordHistoryRenderer, Qt as RecordMetaFooter, ar as RecordNavigationEnhanced, zn as RecordPathRenderer, Vn as RecordQuickActionsRenderer, qn as RecordReferenceRailRenderer, fn as RecordRelatedListRenderer, Ot as RelatedList, dr as RelationshipGraph, Sn as RichTextCommentInput, kt as SectionGroup, bn as SubscriptionToggle, yn as ThreadedReplies, bt as applyAutoSpan, xt as applyDetailAutoLayout, Cr as buildDefaultActions, Tr as buildDefaultDetails, Dr as buildDefaultDiscussion, Sr as buildDefaultHeader, wr as buildDefaultHighlights, Or as buildDefaultPageSchema, Er as buildDefaultTabs, gr as createMentionFromSuggestion, St as createSafeTranslationHook, xr as deriveHighlightFields, Qn as deriveRecordPageHref, br as deriveStages, yr as detectStatusField, _r as extractMentions, yt as inferDetailColumns, on as isConcurrentUpdateError, vt as isWideFieldType, $ as useDetailTranslation };
|