@burdenoff/microfe-brainyrich 2026.720.1 → 2026.730.1
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/brainyrich/hooks/useBrainyRichApi.d.ts +22 -1
- package/dist/brainyrich/hooks/useBrainyRichApi.d.ts.map +1 -1
- package/dist/brainyrich/hooks/useBrainyRichApi.js +89 -47
- package/dist/brainyrich/hooks/useBrainyRichApi.js.map +1 -1
- package/dist/brainyrich/pages/RiskPage.d.ts.map +1 -1
- package/dist/brainyrich/pages/RiskPage.js +433 -213
- package/dist/brainyrich/pages/RiskPage.js.map +1 -1
- package/dist/brainyrich/types/bra.d.ts +27 -0
- package/dist/brainyrich/types/bra.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { useAcknowledgeInsight as e, useCreateRebalanceProposal as t, useDismissInsight as n,
|
|
2
|
-
import { LoadMore as
|
|
3
|
-
import { ConfirmDialog as
|
|
1
|
+
import { useAcknowledgeInsight as e, useCreateRebalanceProposal as t, useDismissInsight as n, useGenerateRiskInsights as r, usePagedInsights as i, usePortfolioRiskSignals as a, usePortfolioRiskSummary as o, usePortfolios as s, useRebalanceProposals as c, useResolveInsight as ee, useTransitionRebalanceProposal as te } from "../hooks/useBrainyRichApi.js";
|
|
2
|
+
import { LoadMore as ne } from "../components/LoadMore.js";
|
|
3
|
+
import { ConfirmDialog as re } from "../components/ConfirmDialog.js";
|
|
4
4
|
import { ActorName as l } from "../components/ActorName.js";
|
|
5
|
-
import { DonutChart as
|
|
5
|
+
import { DonutChart as ie, FadeIn as u, GlassCard as ae, LifecycleStepper as d, StatTile as f } from "../components/viz.js";
|
|
6
6
|
import "../components/index.js";
|
|
7
|
-
import { EmptyState as p, ErrorState as
|
|
8
|
-
import { CommentThread as
|
|
7
|
+
import { EmptyState as p, ErrorState as oe, LoadingState as se, SectionShell as ce, formatDate as m, formatMoney as le, formatPct as h, statusBadgeVariant as g } from "./_shared.js";
|
|
8
|
+
import { CommentThread as ue } from "../components/reuse/CommentThread.js";
|
|
9
9
|
import { useMemo as _, useState as v } from "react";
|
|
10
|
-
import { Activity as
|
|
11
|
-
import { Fragment as
|
|
12
|
-
import { Badge as E, Button as D, Card as
|
|
10
|
+
import { Activity as de, AlertTriangle as fe, ArrowRight as pe, Check as me, Eye as he, Gauge as y, Layers as ge, MoreHorizontal as _e, Plus as ve, RefreshCw as ye, Scale as b, ShieldAlert as x, ShieldCheck as S, Sparkles as be, TrendingUp as xe, X as C } from "lucide-react";
|
|
11
|
+
import { Fragment as Se, jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
12
|
+
import { Badge as E, Button as D, Card as Ce, CardContent as we, CardDescription as Te, CardHeader as O, CardTitle as k, Dialog as Ee, DialogClose as De, DialogContent as Oe, DialogDescription as ke, DialogFooter as Ae, DialogHeader as je, DialogTitle as Me, DropdownMenu as Ne, DropdownMenuContent as Pe, DropdownMenuItem as A, DropdownMenuLabel as Fe, DropdownMenuSeparator as Ie, DropdownMenuTrigger as Le, Input as Re, Label as j, Select as ze, SelectContent as Be, SelectItem as Ve, SelectTrigger as He, SelectValue as Ue, Table as We, TableBody as Ge, TableCell as M, TableHead as N, TableHeader as Ke, TableRow as P, Textarea as qe } from "@burdenoff/fe-libs/ui";
|
|
13
13
|
//#region src/brainyrich/pages/RiskPage.tsx
|
|
14
|
-
var
|
|
14
|
+
var Je = {
|
|
15
15
|
DRAFT: ["PROPOSED", "CANCELLED"],
|
|
16
16
|
PROPOSED: [
|
|
17
17
|
"APPROVED",
|
|
@@ -22,49 +22,49 @@ var He = {
|
|
|
22
22
|
REJECTED: [],
|
|
23
23
|
EXECUTED: [],
|
|
24
24
|
CANCELLED: []
|
|
25
|
-
},
|
|
25
|
+
}, Ye = new Set([
|
|
26
26
|
"DRIFT",
|
|
27
27
|
"CONCENTRATION_RISK",
|
|
28
28
|
"REBALANCE_DUE",
|
|
29
29
|
"CASH_DRAG",
|
|
30
30
|
"FEE_ANOMALY"
|
|
31
31
|
]);
|
|
32
|
-
function
|
|
32
|
+
function F(e) {
|
|
33
33
|
return e.toLowerCase().split("_").map((e) => e.charAt(0).toUpperCase() + e.slice(1)).join(" ");
|
|
34
34
|
}
|
|
35
|
-
var
|
|
35
|
+
var I = [
|
|
36
36
|
"Draft",
|
|
37
37
|
"Proposed",
|
|
38
38
|
"Approved",
|
|
39
39
|
"Executed"
|
|
40
|
-
],
|
|
40
|
+
], Xe = {
|
|
41
41
|
DRAFT: "neutral",
|
|
42
42
|
PROPOSED: "warning",
|
|
43
43
|
APPROVED: "blue",
|
|
44
44
|
EXECUTED: "success",
|
|
45
45
|
REJECTED: "error",
|
|
46
46
|
CANCELLED: "neutral"
|
|
47
|
-
},
|
|
47
|
+
}, Ze = [
|
|
48
48
|
"PROPOSED",
|
|
49
49
|
"DRAFT",
|
|
50
50
|
"APPROVED",
|
|
51
51
|
"EXECUTED",
|
|
52
52
|
"REJECTED",
|
|
53
53
|
"CANCELLED"
|
|
54
|
-
],
|
|
54
|
+
], Qe = {
|
|
55
55
|
CRITICAL: "error",
|
|
56
56
|
HIGH: "warning",
|
|
57
57
|
MEDIUM: "info",
|
|
58
58
|
LOW: "teal",
|
|
59
59
|
INFO: "neutral"
|
|
60
|
-
},
|
|
60
|
+
}, $e = [
|
|
61
61
|
"CRITICAL",
|
|
62
62
|
"HIGH",
|
|
63
63
|
"MEDIUM",
|
|
64
64
|
"LOW",
|
|
65
65
|
"INFO"
|
|
66
66
|
];
|
|
67
|
-
function
|
|
67
|
+
function et(e) {
|
|
68
68
|
if (!Array.isArray(e) || e.length === 0) return null;
|
|
69
69
|
let t = [];
|
|
70
70
|
for (let n of e) {
|
|
@@ -101,11 +101,14 @@ function Je(e) {
|
|
|
101
101
|
}
|
|
102
102
|
return t;
|
|
103
103
|
}
|
|
104
|
-
function
|
|
104
|
+
function tt(e) {
|
|
105
|
+
return e == null ? "—" : typeof e == "number" ? Number.isInteger(e) ? e.toLocaleString() : e.toLocaleString(void 0, { maximumFractionDigits: 2 }) : typeof e == "boolean" ? e ? "Yes" : "No" : typeof e == "string" ? e : JSON.stringify(e);
|
|
106
|
+
}
|
|
107
|
+
function L(e) {
|
|
105
108
|
let t = (e ?? "").toUpperCase();
|
|
106
109
|
return t.includes("BUY") || t.includes("ADD") ? "text-status-success-text" : t.includes("SELL") || t.includes("TRIM") || t.includes("REDUCE") ? "text-status-error-text" : "text-text-secondary";
|
|
107
110
|
}
|
|
108
|
-
function
|
|
111
|
+
function nt(e) {
|
|
109
112
|
if (e == null) return "—";
|
|
110
113
|
if (Array.isArray(e)) return `${e.length} trade${e.length === 1 ? "" : "s"}`;
|
|
111
114
|
if (typeof e == "object") {
|
|
@@ -114,86 +117,86 @@ function Xe(e) {
|
|
|
114
117
|
}
|
|
115
118
|
return String(e);
|
|
116
119
|
}
|
|
117
|
-
var
|
|
120
|
+
var rt = {
|
|
118
121
|
portfolioId: "",
|
|
119
122
|
driftPct: "",
|
|
120
123
|
rationale: "",
|
|
121
124
|
trades: ""
|
|
122
125
|
};
|
|
123
|
-
function
|
|
126
|
+
function it(e) {
|
|
124
127
|
if (e.trim() === "") return;
|
|
125
128
|
let t = Number(e);
|
|
126
129
|
return Number.isFinite(t) ? t : void 0;
|
|
127
130
|
}
|
|
128
|
-
function
|
|
129
|
-
let { data: l, isLoading: d, isError:
|
|
131
|
+
function R() {
|
|
132
|
+
let { data: l, isLoading: d, isError: ue, refetch: me } = c(), { data: I } = s(), [et, tt] = v(void 0), L = et ?? I[0]?.id ?? "", { data: R, isLoading: ct, isError: lt, refetch: ut } = a(L || void 0), z = r(), { data: B, isFetching: V, refetch: dt } = o(L || void 0), { items: H, hasMore: ft, loadMore: pt, isLoading: mt, isFetchingNextPage: ht, isError: gt, refetch: _t } = i(), U = t(), W = te(), vt = e(), yt = n(), bt = ee(), [xt, G] = v(!1), [K, q] = v(rt), [St, J] = v(null), [Y, Ct] = v(null), [X, Z] = v(null), Q = _(() => {
|
|
130
133
|
let e = /* @__PURE__ */ new Map();
|
|
131
|
-
for (let t of
|
|
134
|
+
for (let t of I) e.set(t.id, t);
|
|
132
135
|
return e;
|
|
133
|
-
}, [
|
|
134
|
-
let t =
|
|
136
|
+
}, [I]), wt = _(() => H.filter((e) => Ye.has(e.type)), [H]), Tt = l.filter((e) => e.status === "DRAFT" || e.status === "PROPOSED" || e.status === "APPROVED"), $ = wt.filter((e) => e.status === "OPEN"), Et = l.length > 0 ? l.reduce((e, t) => e + (t.driftPct ?? 0), 0) / l.length : null, Dt = _(() => l.filter((e) => {
|
|
137
|
+
let t = Q.get(e.portfolioId)?.driftThresholdPct;
|
|
135
138
|
return t != null && Number.isFinite(t) && e.driftPct >= t;
|
|
136
|
-
}).length, [l,
|
|
139
|
+
}).length, [l, Q]), Ot = _(() => [...l].sort((e, t) => new Date(e.createdAt).getTime() - new Date(t.createdAt).getTime()).map((e) => e.driftPct).filter((e) => Number.isFinite(e)), [l]), kt = _(() => {
|
|
137
140
|
let e = /* @__PURE__ */ new Map();
|
|
138
141
|
for (let t of l) e.set(t.status, (e.get(t.status) ?? 0) + 1);
|
|
139
|
-
return
|
|
140
|
-
label:
|
|
142
|
+
return Ze.filter((t) => (e.get(t) ?? 0) > 0).map((t) => ({
|
|
143
|
+
label: F(t),
|
|
141
144
|
value: e.get(t) ?? 0,
|
|
142
|
-
tone:
|
|
145
|
+
tone: Xe[t]
|
|
143
146
|
}));
|
|
144
|
-
}, [l]),
|
|
147
|
+
}, [l]), At = _(() => {
|
|
145
148
|
let e = /* @__PURE__ */ new Map();
|
|
146
|
-
for (let t of
|
|
147
|
-
return
|
|
148
|
-
label:
|
|
149
|
+
for (let t of $) e.set(t.severity, (e.get(t.severity) ?? 0) + 1);
|
|
150
|
+
return $e.filter((t) => (e.get(t) ?? 0) > 0).map((t) => ({
|
|
151
|
+
label: F(t),
|
|
149
152
|
value: e.get(t) ?? 0,
|
|
150
|
-
tone:
|
|
153
|
+
tone: Qe[t]
|
|
151
154
|
}));
|
|
152
|
-
}, [
|
|
153
|
-
function
|
|
154
|
-
|
|
155
|
+
}, [$]), jt = I.length > 0;
|
|
156
|
+
function Mt() {
|
|
157
|
+
q(rt), J(null), G(!0);
|
|
155
158
|
}
|
|
156
|
-
function
|
|
157
|
-
if (!
|
|
159
|
+
function Nt() {
|
|
160
|
+
if (!K.portfolioId) return;
|
|
158
161
|
let e;
|
|
159
|
-
if (
|
|
160
|
-
e = JSON.parse(
|
|
162
|
+
if (K.trades.trim() !== "") try {
|
|
163
|
+
e = JSON.parse(K.trades);
|
|
161
164
|
} catch {
|
|
162
|
-
|
|
165
|
+
J("Trades must be valid JSON.");
|
|
163
166
|
return;
|
|
164
167
|
}
|
|
165
|
-
let t =
|
|
166
|
-
|
|
167
|
-
portfolioId:
|
|
168
|
+
let t = Q.get(K.portfolioId);
|
|
169
|
+
U.mutate({
|
|
170
|
+
portfolioId: K.portfolioId,
|
|
168
171
|
householdId: t?.householdId ?? null,
|
|
169
|
-
driftPct:
|
|
170
|
-
rationale:
|
|
172
|
+
driftPct: it(K.driftPct),
|
|
173
|
+
rationale: K.rationale.trim() || null,
|
|
171
174
|
...e === void 0 ? {} : { trades: e }
|
|
172
|
-
}, { onSuccess: () =>
|
|
175
|
+
}, { onSuccess: () => G(!1) });
|
|
173
176
|
}
|
|
174
|
-
function
|
|
177
|
+
function Pt(e, t) {
|
|
175
178
|
if (t === "REJECTED" || t === "CANCELLED") {
|
|
176
|
-
|
|
179
|
+
Z({
|
|
177
180
|
proposal: e,
|
|
178
181
|
status: t
|
|
179
182
|
});
|
|
180
183
|
return;
|
|
181
184
|
}
|
|
182
|
-
|
|
185
|
+
W.mutate({
|
|
183
186
|
id: e.id,
|
|
184
187
|
status: t
|
|
185
188
|
});
|
|
186
189
|
}
|
|
187
|
-
function
|
|
188
|
-
let t =
|
|
190
|
+
function Ft(e) {
|
|
191
|
+
let t = Q.get(e.portfolioId)?.driftThresholdPct;
|
|
189
192
|
return t != null && Number.isFinite(t) && e.driftPct >= t;
|
|
190
193
|
}
|
|
191
|
-
return /* @__PURE__ */ T(
|
|
194
|
+
return /* @__PURE__ */ T(ce, {
|
|
192
195
|
title: "Risk & Rebalancing",
|
|
193
196
|
description: "Review drift-driven rebalance proposals and act on portfolio risk insights.",
|
|
194
|
-
badges: [`${
|
|
197
|
+
badges: [`${Tt.length} active`, `${$.length} open insight${$.length === 1 ? "" : "s"}`],
|
|
195
198
|
actionLabel: "New proposal",
|
|
196
|
-
onAction:
|
|
199
|
+
onAction: Mt,
|
|
197
200
|
children: [
|
|
198
201
|
/* @__PURE__ */ T("div", {
|
|
199
202
|
className: "grid gap-4 sm:grid-cols-2 xl:grid-cols-4",
|
|
@@ -202,11 +205,11 @@ function $e() {
|
|
|
202
205
|
index: 0,
|
|
203
206
|
children: /* @__PURE__ */ w(f, {
|
|
204
207
|
label: "Average drift",
|
|
205
|
-
value:
|
|
206
|
-
spark:
|
|
207
|
-
sparkTone:
|
|
208
|
+
value: Et === null ? "—" : h(Et),
|
|
209
|
+
spark: Ot.length > 1 ? Ot : void 0,
|
|
210
|
+
sparkTone: Dt > 0 ? "error" : "brand",
|
|
208
211
|
glow: !0,
|
|
209
|
-
icon: /* @__PURE__ */ w(
|
|
212
|
+
icon: /* @__PURE__ */ w(y, {
|
|
210
213
|
className: "size-4",
|
|
211
214
|
"aria-hidden": "true"
|
|
212
215
|
})
|
|
@@ -216,8 +219,8 @@ function $e() {
|
|
|
216
219
|
index: 1,
|
|
217
220
|
children: /* @__PURE__ */ w(f, {
|
|
218
221
|
label: "Active proposals",
|
|
219
|
-
value: String(
|
|
220
|
-
icon: /* @__PURE__ */ w(
|
|
222
|
+
value: String(Tt.length),
|
|
223
|
+
icon: /* @__PURE__ */ w(de, {
|
|
221
224
|
className: "size-4",
|
|
222
225
|
"aria-hidden": "true"
|
|
223
226
|
})
|
|
@@ -228,7 +231,7 @@ function $e() {
|
|
|
228
231
|
children: /* @__PURE__ */ w(f, {
|
|
229
232
|
label: "Total proposals",
|
|
230
233
|
value: String(l.length),
|
|
231
|
-
icon: /* @__PURE__ */ w(
|
|
234
|
+
icon: /* @__PURE__ */ w(ge, {
|
|
232
235
|
className: "size-4",
|
|
233
236
|
"aria-hidden": "true"
|
|
234
237
|
})
|
|
@@ -238,8 +241,8 @@ function $e() {
|
|
|
238
241
|
index: 3,
|
|
239
242
|
children: /* @__PURE__ */ w(f, {
|
|
240
243
|
label: "Open risk insights",
|
|
241
|
-
value: String(
|
|
242
|
-
deltaTone:
|
|
244
|
+
value: String($.length),
|
|
245
|
+
deltaTone: $.length > 0 ? "negative" : "neutral",
|
|
243
246
|
icon: /* @__PURE__ */ w(x, {
|
|
244
247
|
className: "size-4",
|
|
245
248
|
"aria-hidden": "true"
|
|
@@ -248,24 +251,24 @@ function $e() {
|
|
|
248
251
|
})
|
|
249
252
|
]
|
|
250
253
|
}),
|
|
251
|
-
(
|
|
254
|
+
(kt.length > 0 || At.length > 0) && !d ? /* @__PURE__ */ T("div", {
|
|
252
255
|
className: "grid gap-4 lg:grid-cols-2",
|
|
253
256
|
children: [/* @__PURE__ */ w(u, {
|
|
254
257
|
index: 0,
|
|
255
|
-
children: /* @__PURE__ */ T(
|
|
258
|
+
children: /* @__PURE__ */ T(ae, {
|
|
256
259
|
glow: !0,
|
|
257
260
|
className: "h-full",
|
|
258
261
|
children: [/* @__PURE__ */ T("div", {
|
|
259
262
|
className: "mb-3 flex items-center gap-2",
|
|
260
|
-
children: [/* @__PURE__ */ w(
|
|
263
|
+
children: [/* @__PURE__ */ w(xe, {
|
|
261
264
|
className: "size-4 text-text-secondary",
|
|
262
265
|
"aria-hidden": "true"
|
|
263
266
|
}), /* @__PURE__ */ w("h2", {
|
|
264
267
|
className: "text-sm font-semibold text-text-primary",
|
|
265
268
|
children: "Proposal pipeline"
|
|
266
269
|
})]
|
|
267
|
-
}), /* @__PURE__ */ w(
|
|
268
|
-
data:
|
|
270
|
+
}), /* @__PURE__ */ w(ie, {
|
|
271
|
+
data: kt,
|
|
269
272
|
centerValue: String(l.length),
|
|
270
273
|
centerLabel: "proposals",
|
|
271
274
|
height: 200
|
|
@@ -273,7 +276,7 @@ function $e() {
|
|
|
273
276
|
})
|
|
274
277
|
}), /* @__PURE__ */ w(u, {
|
|
275
278
|
index: 1,
|
|
276
|
-
children: /* @__PURE__ */ T(
|
|
279
|
+
children: /* @__PURE__ */ T(ae, {
|
|
277
280
|
className: "h-full",
|
|
278
281
|
children: [/* @__PURE__ */ T("div", {
|
|
279
282
|
className: "mb-3 flex items-center gap-2",
|
|
@@ -284,9 +287,9 @@ function $e() {
|
|
|
284
287
|
className: "text-sm font-semibold text-text-primary",
|
|
285
288
|
children: "Open risk signals"
|
|
286
289
|
})]
|
|
287
|
-
}),
|
|
288
|
-
data:
|
|
289
|
-
centerValue: String(
|
|
290
|
+
}), At.length > 0 ? /* @__PURE__ */ w(ie, {
|
|
291
|
+
data: At,
|
|
292
|
+
centerValue: String($.length),
|
|
290
293
|
centerLabel: "open",
|
|
291
294
|
height: 200
|
|
292
295
|
}) : /* @__PURE__ */ T("div", {
|
|
@@ -302,61 +305,236 @@ function $e() {
|
|
|
302
305
|
})
|
|
303
306
|
})]
|
|
304
307
|
}) : null,
|
|
305
|
-
/* @__PURE__ */ T(
|
|
308
|
+
/* @__PURE__ */ T(Ce, { children: [/* @__PURE__ */ T(O, { children: [/* @__PURE__ */ T(k, {
|
|
309
|
+
className: "flex items-center gap-2",
|
|
310
|
+
children: [/* @__PURE__ */ w(y, {
|
|
311
|
+
className: "h-5 w-5",
|
|
312
|
+
"aria-hidden": "true"
|
|
313
|
+
}), "Portfolio risk signals"]
|
|
314
|
+
}), /* @__PURE__ */ w(Te, { children: "Real, explainable signals computed live from this portfolio's own holdings and target allocation — every signal below shows the real inputs and formula/threshold behind it. Informational only, never a buy/sell recommendation." })] }), /* @__PURE__ */ T(we, {
|
|
315
|
+
className: "space-y-4",
|
|
316
|
+
children: [/* @__PURE__ */ T("div", {
|
|
317
|
+
className: "flex flex-wrap items-center gap-3",
|
|
318
|
+
children: [
|
|
319
|
+
/* @__PURE__ */ T("div", {
|
|
320
|
+
className: "min-w-[220px] space-y-1.5",
|
|
321
|
+
children: [/* @__PURE__ */ w(j, {
|
|
322
|
+
htmlFor: "risk-portfolio",
|
|
323
|
+
children: "Portfolio"
|
|
324
|
+
}), /* @__PURE__ */ T(ze, {
|
|
325
|
+
value: L,
|
|
326
|
+
onValueChange: tt,
|
|
327
|
+
children: [/* @__PURE__ */ w(He, {
|
|
328
|
+
id: "risk-portfolio",
|
|
329
|
+
children: /* @__PURE__ */ w(Ue, { placeholder: "Select a portfolio" })
|
|
330
|
+
}), /* @__PURE__ */ w(Be, { children: I.map((e) => /* @__PURE__ */ w(Ve, {
|
|
331
|
+
value: e.id,
|
|
332
|
+
children: e.name
|
|
333
|
+
}, e.id)) })]
|
|
334
|
+
})]
|
|
335
|
+
}),
|
|
336
|
+
/* @__PURE__ */ T(D, {
|
|
337
|
+
variant: "outline",
|
|
338
|
+
size: "sm",
|
|
339
|
+
className: "mt-auto",
|
|
340
|
+
disabled: !L || ct,
|
|
341
|
+
onClick: () => ut(),
|
|
342
|
+
children: [/* @__PURE__ */ w(ye, {
|
|
343
|
+
className: "size-4",
|
|
344
|
+
"aria-hidden": "true"
|
|
345
|
+
}), "Recompute"]
|
|
346
|
+
}),
|
|
347
|
+
/* @__PURE__ */ T(D, {
|
|
348
|
+
variant: "outline",
|
|
349
|
+
size: "sm",
|
|
350
|
+
className: "mt-auto",
|
|
351
|
+
disabled: !L || (R?.signals.length ?? 0) === 0 || z.isPending,
|
|
352
|
+
onClick: () => z.mutate(L),
|
|
353
|
+
children: [/* @__PURE__ */ w(x, {
|
|
354
|
+
className: "size-4",
|
|
355
|
+
"aria-hidden": "true"
|
|
356
|
+
}), z.isPending ? "Saving…" : "Save as insights"]
|
|
357
|
+
})
|
|
358
|
+
]
|
|
359
|
+
}), I.length === 0 ? /* @__PURE__ */ w(p, {
|
|
360
|
+
icon: /* @__PURE__ */ w(y, {
|
|
361
|
+
className: "size-6",
|
|
362
|
+
"aria-hidden": "true"
|
|
363
|
+
}),
|
|
364
|
+
title: "No portfolios yet",
|
|
365
|
+
description: "Create a portfolio to compute real risk signals from its holdings."
|
|
366
|
+
}) : ct ? /* @__PURE__ */ w(se, {}) : lt ? /* @__PURE__ */ w(oe, { onRetry: () => ut() }) : R ? /* @__PURE__ */ T("div", {
|
|
367
|
+
className: "space-y-4",
|
|
368
|
+
children: [
|
|
369
|
+
/* @__PURE__ */ T("div", {
|
|
370
|
+
className: "grid gap-3 sm:grid-cols-3",
|
|
371
|
+
children: [
|
|
372
|
+
/* @__PURE__ */ w(f, {
|
|
373
|
+
label: "Portfolio value",
|
|
374
|
+
value: le(R.totalValue),
|
|
375
|
+
icon: /* @__PURE__ */ w(ge, {
|
|
376
|
+
className: "size-4",
|
|
377
|
+
"aria-hidden": "true"
|
|
378
|
+
})
|
|
379
|
+
}),
|
|
380
|
+
/* @__PURE__ */ w(f, {
|
|
381
|
+
label: "Holdings considered",
|
|
382
|
+
value: String(R.holdingsConsidered),
|
|
383
|
+
icon: /* @__PURE__ */ w(de, {
|
|
384
|
+
className: "size-4",
|
|
385
|
+
"aria-hidden": "true"
|
|
386
|
+
})
|
|
387
|
+
}),
|
|
388
|
+
/* @__PURE__ */ w(f, {
|
|
389
|
+
label: "Signals breached",
|
|
390
|
+
value: String(R.signals.length),
|
|
391
|
+
deltaTone: R.signals.length > 0 ? "negative" : "neutral",
|
|
392
|
+
icon: /* @__PURE__ */ w(x, {
|
|
393
|
+
className: "size-4",
|
|
394
|
+
"aria-hidden": "true"
|
|
395
|
+
})
|
|
396
|
+
})
|
|
397
|
+
]
|
|
398
|
+
}),
|
|
399
|
+
R.signals.length === 0 ? /* @__PURE__ */ w(p, {
|
|
400
|
+
icon: /* @__PURE__ */ w(S, {
|
|
401
|
+
className: "size-6",
|
|
402
|
+
"aria-hidden": "true"
|
|
403
|
+
}),
|
|
404
|
+
title: "No configured threshold was breached",
|
|
405
|
+
description: "This portfolio's concentration, cash, drift and unrealized-loss metrics are all within their configured thresholds."
|
|
406
|
+
}) : /* @__PURE__ */ w("ul", {
|
|
407
|
+
className: "space-y-3",
|
|
408
|
+
children: R.signals.map((e, t) => /* @__PURE__ */ w(ot, { signal: e }, `${e.kind}-${t}`))
|
|
409
|
+
}),
|
|
410
|
+
/* @__PURE__ */ T("div", {
|
|
411
|
+
className: "rounded-xl border border-border-subtle bg-bg-surface p-4",
|
|
412
|
+
children: [/* @__PURE__ */ T("div", {
|
|
413
|
+
className: "flex flex-wrap items-center justify-between gap-2",
|
|
414
|
+
children: [/* @__PURE__ */ T("div", {
|
|
415
|
+
className: "flex items-center gap-2",
|
|
416
|
+
children: [
|
|
417
|
+
/* @__PURE__ */ w(be, {
|
|
418
|
+
className: "size-4 text-text-secondary",
|
|
419
|
+
"aria-hidden": "true"
|
|
420
|
+
}),
|
|
421
|
+
/* @__PURE__ */ w("h3", {
|
|
422
|
+
className: "text-sm font-semibold text-text-primary",
|
|
423
|
+
children: "AI summary"
|
|
424
|
+
}),
|
|
425
|
+
/* @__PURE__ */ w("span", {
|
|
426
|
+
className: "text-xs text-text-muted",
|
|
427
|
+
children: "(optional — plain-language restatement of the signals above; never a source of numbers)"
|
|
428
|
+
})
|
|
429
|
+
]
|
|
430
|
+
}), /* @__PURE__ */ T(D, {
|
|
431
|
+
variant: "outline",
|
|
432
|
+
size: "sm",
|
|
433
|
+
disabled: !L || V,
|
|
434
|
+
onClick: () => dt(),
|
|
435
|
+
children: [/* @__PURE__ */ w(be, {
|
|
436
|
+
className: "size-4",
|
|
437
|
+
"aria-hidden": "true"
|
|
438
|
+
}), V ? "Generating…" : "Generate AI summary"]
|
|
439
|
+
})]
|
|
440
|
+
}), V ? /* @__PURE__ */ w("p", {
|
|
441
|
+
className: "mt-2 text-sm text-text-secondary",
|
|
442
|
+
children: "Asking the AI provider…"
|
|
443
|
+
}) : B?.generated ? /* @__PURE__ */ T("div", {
|
|
444
|
+
className: "mt-2 space-y-1",
|
|
445
|
+
children: [/* @__PURE__ */ w("p", {
|
|
446
|
+
className: "text-sm text-text-primary",
|
|
447
|
+
children: B.summary
|
|
448
|
+
}), /* @__PURE__ */ T("p", {
|
|
449
|
+
className: "text-xs text-text-muted",
|
|
450
|
+
children: [
|
|
451
|
+
"AI-generated commentary",
|
|
452
|
+
B.provider ? ` · ${B.provider}` : "",
|
|
453
|
+
" · based on",
|
|
454
|
+
" ",
|
|
455
|
+
B.signalsConsidered,
|
|
456
|
+
" computed signal",
|
|
457
|
+
B.signalsConsidered === 1 ? "" : "s",
|
|
458
|
+
" above"
|
|
459
|
+
]
|
|
460
|
+
})]
|
|
461
|
+
}) : B && !B.generated ? /* @__PURE__ */ T("p", {
|
|
462
|
+
className: "mt-2 text-sm text-text-secondary",
|
|
463
|
+
children: [
|
|
464
|
+
"AI summary unavailable — ",
|
|
465
|
+
B.reason ?? "no provider configured",
|
|
466
|
+
". The deterministic signals above are unaffected."
|
|
467
|
+
]
|
|
468
|
+
}) : /* @__PURE__ */ w("p", {
|
|
469
|
+
className: "mt-2 text-sm text-text-muted",
|
|
470
|
+
children: "Not generated yet. The deterministic signals above always work without this."
|
|
471
|
+
})]
|
|
472
|
+
})
|
|
473
|
+
]
|
|
474
|
+
}) : /* @__PURE__ */ w(p, {
|
|
475
|
+
icon: /* @__PURE__ */ w(y, {
|
|
476
|
+
className: "size-6",
|
|
477
|
+
"aria-hidden": "true"
|
|
478
|
+
}),
|
|
479
|
+
title: "Select a portfolio",
|
|
480
|
+
description: "Choose a portfolio above to compute its real risk signals."
|
|
481
|
+
})]
|
|
482
|
+
})] }),
|
|
483
|
+
/* @__PURE__ */ T(Ce, { children: [/* @__PURE__ */ T(O, { children: [/* @__PURE__ */ T(k, {
|
|
306
484
|
className: "flex items-center gap-2",
|
|
307
485
|
children: [/* @__PURE__ */ w(b, {
|
|
308
486
|
className: "h-5 w-5",
|
|
309
487
|
"aria-hidden": "true"
|
|
310
488
|
}), "Rebalance proposals"]
|
|
311
|
-
}), /* @__PURE__ */ w(
|
|
489
|
+
}), /* @__PURE__ */ w(Te, { children: "Drift against target allocation, with lifecycle actions per proposal." })] }), /* @__PURE__ */ w(we, { children: d ? /* @__PURE__ */ w(se, {}) : ue ? /* @__PURE__ */ w(oe, { onRetry: () => me() }) : l.length === 0 ? /* @__PURE__ */ w(p, {
|
|
312
490
|
icon: /* @__PURE__ */ w(b, {
|
|
313
491
|
className: "size-6",
|
|
314
492
|
"aria-hidden": "true"
|
|
315
493
|
}),
|
|
316
494
|
title: "No rebalance proposals",
|
|
317
|
-
description:
|
|
318
|
-
action:
|
|
495
|
+
description: jt ? "Create a proposal when a portfolio drifts from its target allocation." : "Create a portfolio first, then propose a rebalance when it drifts.",
|
|
496
|
+
action: jt ? /* @__PURE__ */ T(D, {
|
|
319
497
|
size: "sm",
|
|
320
|
-
onClick:
|
|
321
|
-
children: [/* @__PURE__ */ w(
|
|
498
|
+
onClick: Mt,
|
|
499
|
+
children: [/* @__PURE__ */ w(ve, {
|
|
322
500
|
className: "size-4",
|
|
323
501
|
"aria-hidden": "true"
|
|
324
502
|
}), "New proposal"]
|
|
325
503
|
}) : void 0
|
|
326
504
|
}) : /* @__PURE__ */ w("div", {
|
|
327
505
|
className: "overflow-x-auto",
|
|
328
|
-
children: /* @__PURE__ */ T(
|
|
329
|
-
/* @__PURE__ */ w(
|
|
330
|
-
/* @__PURE__ */ w(
|
|
506
|
+
children: /* @__PURE__ */ T(We, { children: [/* @__PURE__ */ w(Ke, { children: /* @__PURE__ */ T(P, { children: [
|
|
507
|
+
/* @__PURE__ */ w(N, { children: "Portfolio" }),
|
|
508
|
+
/* @__PURE__ */ w(N, {
|
|
331
509
|
className: "text-right",
|
|
332
510
|
children: "Drift"
|
|
333
511
|
}),
|
|
334
|
-
/* @__PURE__ */ w(
|
|
335
|
-
/* @__PURE__ */ w(
|
|
336
|
-
/* @__PURE__ */ w(
|
|
337
|
-
/* @__PURE__ */ w(
|
|
338
|
-
/* @__PURE__ */ w(
|
|
512
|
+
/* @__PURE__ */ w(N, { children: "Status" }),
|
|
513
|
+
/* @__PURE__ */ w(N, { children: "Rationale" }),
|
|
514
|
+
/* @__PURE__ */ w(N, { children: "Trades" }),
|
|
515
|
+
/* @__PURE__ */ w(N, { children: "Created" }),
|
|
516
|
+
/* @__PURE__ */ w(N, {
|
|
339
517
|
className: "w-12 text-right",
|
|
340
518
|
children: "Actions"
|
|
341
519
|
})
|
|
342
|
-
] }) }), /* @__PURE__ */ w(
|
|
343
|
-
let t =
|
|
344
|
-
return /* @__PURE__ */ T(
|
|
345
|
-
onClick: () =>
|
|
520
|
+
] }) }), /* @__PURE__ */ w(Ge, { children: l.map((e) => {
|
|
521
|
+
let t = Q.get(e.portfolioId), n = Ft(e), r = Je[e.status], i = t?.driftThresholdPct, a = i != null && i > 0 ? Math.min(100, e.driftPct / i * 100) : null;
|
|
522
|
+
return /* @__PURE__ */ T(P, {
|
|
523
|
+
onClick: () => Ct(e),
|
|
346
524
|
className: "cursor-pointer transition-colors motion-safe:hover:bg-bg-elevated",
|
|
347
525
|
children: [
|
|
348
|
-
/* @__PURE__ */ T(
|
|
526
|
+
/* @__PURE__ */ T(M, { children: [/* @__PURE__ */ w("p", {
|
|
349
527
|
className: "font-medium text-text-primary",
|
|
350
528
|
children: t?.name ?? "Unknown portfolio"
|
|
351
529
|
}), /* @__PURE__ */ T("p", {
|
|
352
530
|
className: "text-xs text-text-secondary",
|
|
353
531
|
children: [t?.baseCurrency ?? "—", i == null ? "" : ` · threshold ${h(i)}`]
|
|
354
532
|
})] }),
|
|
355
|
-
/* @__PURE__ */ T(
|
|
533
|
+
/* @__PURE__ */ T(M, {
|
|
356
534
|
className: "text-right",
|
|
357
535
|
children: [/* @__PURE__ */ T("span", {
|
|
358
536
|
className: `inline-flex items-center justify-end gap-1 font-semibold tabular-nums ${n ? "text-status-error-text" : "text-text-primary"}`,
|
|
359
|
-
children: [n ? /* @__PURE__ */ w(
|
|
537
|
+
children: [n ? /* @__PURE__ */ w(fe, {
|
|
360
538
|
className: "size-4",
|
|
361
539
|
"aria-hidden": "true"
|
|
362
540
|
}) : null, h(e.driftPct)]
|
|
@@ -379,60 +557,60 @@ function $e() {
|
|
|
379
557
|
})
|
|
380
558
|
})]
|
|
381
559
|
}),
|
|
382
|
-
/* @__PURE__ */ w(
|
|
560
|
+
/* @__PURE__ */ w(M, { children: /* @__PURE__ */ w(E, {
|
|
383
561
|
variant: g(e.status),
|
|
384
|
-
children:
|
|
562
|
+
children: F(e.status)
|
|
385
563
|
}) }),
|
|
386
|
-
/* @__PURE__ */ w(
|
|
564
|
+
/* @__PURE__ */ w(M, {
|
|
387
565
|
className: "max-w-xs",
|
|
388
566
|
children: /* @__PURE__ */ w("p", {
|
|
389
567
|
className: "truncate text-sm text-text-secondary",
|
|
390
568
|
children: e.rationale ?? "—"
|
|
391
569
|
})
|
|
392
570
|
}),
|
|
393
|
-
/* @__PURE__ */ w(
|
|
571
|
+
/* @__PURE__ */ w(M, {
|
|
394
572
|
className: "text-sm text-text-secondary",
|
|
395
|
-
children:
|
|
573
|
+
children: nt(e.trades)
|
|
396
574
|
}),
|
|
397
|
-
/* @__PURE__ */ w(
|
|
575
|
+
/* @__PURE__ */ w(M, {
|
|
398
576
|
className: "text-sm text-text-secondary",
|
|
399
577
|
children: m(e.createdAt)
|
|
400
578
|
}),
|
|
401
|
-
/* @__PURE__ */ w(
|
|
579
|
+
/* @__PURE__ */ w(M, {
|
|
402
580
|
className: "text-right",
|
|
403
581
|
onClick: (e) => e.stopPropagation(),
|
|
404
|
-
children: /* @__PURE__ */ T(
|
|
582
|
+
children: /* @__PURE__ */ T(Ne, { children: [/* @__PURE__ */ w(Le, {
|
|
405
583
|
asChild: !0,
|
|
406
584
|
children: /* @__PURE__ */ w(D, {
|
|
407
585
|
variant: "ghost",
|
|
408
586
|
size: "sm",
|
|
409
587
|
"aria-label": `Actions for ${t?.name ?? "proposal"}`,
|
|
410
|
-
children: /* @__PURE__ */ w(
|
|
588
|
+
children: /* @__PURE__ */ w(_e, {
|
|
411
589
|
className: "size-4",
|
|
412
590
|
"aria-hidden": "true"
|
|
413
591
|
})
|
|
414
592
|
})
|
|
415
|
-
}), /* @__PURE__ */ T(
|
|
593
|
+
}), /* @__PURE__ */ T(Pe, {
|
|
416
594
|
align: "end",
|
|
417
595
|
children: [/* @__PURE__ */ T(A, {
|
|
418
|
-
onClick: () =>
|
|
419
|
-
children: [/* @__PURE__ */ w(
|
|
596
|
+
onClick: () => Ct(e),
|
|
597
|
+
children: [/* @__PURE__ */ w(he, {
|
|
420
598
|
className: "size-4",
|
|
421
599
|
"aria-hidden": "true"
|
|
422
600
|
}), "View details"]
|
|
423
|
-
}), r.length > 0 ? /* @__PURE__ */ T(
|
|
424
|
-
/* @__PURE__ */ w(
|
|
425
|
-
/* @__PURE__ */ w(
|
|
601
|
+
}), r.length > 0 ? /* @__PURE__ */ T(Se, { children: [
|
|
602
|
+
/* @__PURE__ */ w(Ie, {}),
|
|
603
|
+
/* @__PURE__ */ w(Fe, { children: "Advance to" }),
|
|
426
604
|
r.map((t) => {
|
|
427
605
|
let n = t === "REJECTED" || t === "CANCELLED";
|
|
428
606
|
return /* @__PURE__ */ T(A, {
|
|
429
|
-
disabled:
|
|
607
|
+
disabled: W.isPending,
|
|
430
608
|
className: n ? "text-status-error-text" : void 0,
|
|
431
|
-
onClick: () =>
|
|
432
|
-
children: [w(n ? C :
|
|
609
|
+
onClick: () => Pt(e, t),
|
|
610
|
+
children: [w(n ? C : pe, {
|
|
433
611
|
className: "size-4",
|
|
434
612
|
"aria-hidden": "true"
|
|
435
|
-
}),
|
|
613
|
+
}), F(t)]
|
|
436
614
|
}, t);
|
|
437
615
|
})
|
|
438
616
|
] }) : null]
|
|
@@ -442,13 +620,13 @@ function $e() {
|
|
|
442
620
|
}, e.id);
|
|
443
621
|
}) })] })
|
|
444
622
|
}) })] }),
|
|
445
|
-
/* @__PURE__ */ T(
|
|
623
|
+
/* @__PURE__ */ T(Ce, { children: [/* @__PURE__ */ T(O, { children: [/* @__PURE__ */ T(k, {
|
|
446
624
|
className: "flex items-center gap-2",
|
|
447
625
|
children: [/* @__PURE__ */ w(x, {
|
|
448
626
|
className: "h-5 w-5",
|
|
449
627
|
"aria-hidden": "true"
|
|
450
628
|
}), "Risk insights"]
|
|
451
|
-
}), /* @__PURE__ */ w(
|
|
629
|
+
}), /* @__PURE__ */ w(Te, { children: "Drift, concentration, cash-drag and fee-anomaly signals detected across your portfolios." })] }), /* @__PURE__ */ w(we, { children: mt ? /* @__PURE__ */ w(se, {}) : gt ? /* @__PURE__ */ w(oe, { onRetry: () => _t() }) : wt.length === 0 ? /* @__PURE__ */ w(p, {
|
|
452
630
|
icon: /* @__PURE__ */ w(S, {
|
|
453
631
|
className: "size-6",
|
|
454
632
|
"aria-hidden": "true"
|
|
@@ -457,28 +635,28 @@ function $e() {
|
|
|
457
635
|
description: "No drift, concentration, cash-drag or fee-anomaly signals are open right now."
|
|
458
636
|
}) : /* @__PURE__ */ T("div", {
|
|
459
637
|
className: "space-y-3",
|
|
460
|
-
children: [
|
|
638
|
+
children: [wt.map((e, t) => /* @__PURE__ */ w(u, {
|
|
461
639
|
index: t,
|
|
462
|
-
children: /* @__PURE__ */ w(
|
|
640
|
+
children: /* @__PURE__ */ w(st, {
|
|
463
641
|
insight: e,
|
|
464
|
-
onAcknowledge: () =>
|
|
465
|
-
onResolve: () =>
|
|
466
|
-
onDismiss: () =>
|
|
467
|
-
actionPending:
|
|
642
|
+
onAcknowledge: () => vt.mutate(e.id),
|
|
643
|
+
onResolve: () => bt.mutate(e.id),
|
|
644
|
+
onDismiss: () => yt.mutate(e.id),
|
|
645
|
+
actionPending: vt.isPending || bt.isPending || yt.isPending
|
|
468
646
|
})
|
|
469
|
-
}, e.id)), /* @__PURE__ */ w(
|
|
470
|
-
hasMore:
|
|
471
|
-
onClick:
|
|
472
|
-
loading:
|
|
647
|
+
}, e.id)), /* @__PURE__ */ w(ne, {
|
|
648
|
+
hasMore: ft,
|
|
649
|
+
onClick: pt,
|
|
650
|
+
loading: ht,
|
|
473
651
|
label: "Load more insights"
|
|
474
652
|
})]
|
|
475
653
|
}) })] }),
|
|
476
|
-
/* @__PURE__ */ w(
|
|
477
|
-
open:
|
|
478
|
-
onOpenChange:
|
|
479
|
-
children: /* @__PURE__ */ T(
|
|
480
|
-
/* @__PURE__ */ T(
|
|
481
|
-
|
|
654
|
+
/* @__PURE__ */ w(Ee, {
|
|
655
|
+
open: xt,
|
|
656
|
+
onOpenChange: G,
|
|
657
|
+
children: /* @__PURE__ */ T(Oe, { children: [
|
|
658
|
+
/* @__PURE__ */ T(je, { children: [/* @__PURE__ */ w(Me, { children: "New rebalance proposal" }), /* @__PURE__ */ w(ke, { children: "Propose a rebalance for a portfolio that has drifted from its target allocation." })] }),
|
|
659
|
+
jt ? /* @__PURE__ */ T("div", {
|
|
482
660
|
className: "grid gap-4",
|
|
483
661
|
children: [
|
|
484
662
|
/* @__PURE__ */ T("div", {
|
|
@@ -491,16 +669,16 @@ function $e() {
|
|
|
491
669
|
className: "text-status-error-text",
|
|
492
670
|
children: "*"
|
|
493
671
|
})]
|
|
494
|
-
}), /* @__PURE__ */ T(
|
|
495
|
-
value:
|
|
496
|
-
onValueChange: (e) =>
|
|
672
|
+
}), /* @__PURE__ */ T(ze, {
|
|
673
|
+
value: K.portfolioId,
|
|
674
|
+
onValueChange: (e) => q((t) => ({
|
|
497
675
|
...t,
|
|
498
676
|
portfolioId: e
|
|
499
677
|
})),
|
|
500
|
-
children: [/* @__PURE__ */ w(
|
|
678
|
+
children: [/* @__PURE__ */ w(He, {
|
|
501
679
|
id: "prop-portfolio",
|
|
502
|
-
children: /* @__PURE__ */ w(
|
|
503
|
-
}), /* @__PURE__ */ w(
|
|
680
|
+
children: /* @__PURE__ */ w(Ue, { placeholder: "Select a portfolio" })
|
|
681
|
+
}), /* @__PURE__ */ w(Be, { children: I.map((e) => /* @__PURE__ */ w(Ve, {
|
|
504
682
|
value: e.id,
|
|
505
683
|
children: e.name
|
|
506
684
|
}, e.id)) })]
|
|
@@ -510,11 +688,11 @@ function $e() {
|
|
|
510
688
|
children: [/* @__PURE__ */ w(j, {
|
|
511
689
|
htmlFor: "prop-drift",
|
|
512
690
|
children: "Drift %"
|
|
513
|
-
}), /* @__PURE__ */ w(
|
|
691
|
+
}), /* @__PURE__ */ w(Re, {
|
|
514
692
|
id: "prop-drift",
|
|
515
693
|
type: "number",
|
|
516
|
-
value:
|
|
517
|
-
onChange: (e) =>
|
|
694
|
+
value: K.driftPct,
|
|
695
|
+
onChange: (e) => q((t) => ({
|
|
518
696
|
...t,
|
|
519
697
|
driftPct: e.target.value
|
|
520
698
|
})),
|
|
@@ -527,10 +705,10 @@ function $e() {
|
|
|
527
705
|
children: [/* @__PURE__ */ w(j, {
|
|
528
706
|
htmlFor: "prop-rationale",
|
|
529
707
|
children: "Rationale"
|
|
530
|
-
}), /* @__PURE__ */ w(
|
|
708
|
+
}), /* @__PURE__ */ w(qe, {
|
|
531
709
|
id: "prop-rationale",
|
|
532
|
-
value:
|
|
533
|
-
onChange: (e) =>
|
|
710
|
+
value: K.rationale,
|
|
711
|
+
onChange: (e) => q((t) => ({
|
|
534
712
|
...t,
|
|
535
713
|
rationale: e.target.value
|
|
536
714
|
})),
|
|
@@ -544,21 +722,21 @@ function $e() {
|
|
|
544
722
|
htmlFor: "prop-trades",
|
|
545
723
|
children: "Trades (JSON, optional)"
|
|
546
724
|
}),
|
|
547
|
-
/* @__PURE__ */ w(
|
|
725
|
+
/* @__PURE__ */ w(qe, {
|
|
548
726
|
id: "prop-trades",
|
|
549
727
|
className: "font-mono text-xs",
|
|
550
|
-
value:
|
|
728
|
+
value: K.trades,
|
|
551
729
|
onChange: (e) => {
|
|
552
|
-
|
|
730
|
+
J(null), q((t) => ({
|
|
553
731
|
...t,
|
|
554
732
|
trades: e.target.value
|
|
555
733
|
}));
|
|
556
734
|
},
|
|
557
735
|
placeholder: "e.g. [{\"symbol\":\"VOO\",\"action\":\"SELL\",\"quantity\":10}]"
|
|
558
736
|
}),
|
|
559
|
-
|
|
737
|
+
St ? /* @__PURE__ */ w("p", {
|
|
560
738
|
className: "text-xs text-status-error-text",
|
|
561
|
-
children:
|
|
739
|
+
children: St
|
|
562
740
|
}) : null
|
|
563
741
|
]
|
|
564
742
|
})
|
|
@@ -571,70 +749,70 @@ function $e() {
|
|
|
571
749
|
title: "Create a portfolio first",
|
|
572
750
|
description: "A rebalance proposal targets a portfolio. Add a portfolio on the Portfolios page, then return here to propose a rebalance."
|
|
573
751
|
}),
|
|
574
|
-
/* @__PURE__ */ T(
|
|
752
|
+
/* @__PURE__ */ T(Ae, { children: [/* @__PURE__ */ w(De, {
|
|
575
753
|
asChild: !0,
|
|
576
754
|
children: /* @__PURE__ */ w(D, {
|
|
577
755
|
variant: "outline",
|
|
578
756
|
children: "Cancel"
|
|
579
757
|
})
|
|
580
758
|
}), /* @__PURE__ */ w(D, {
|
|
581
|
-
onClick:
|
|
582
|
-
disabled: !
|
|
583
|
-
children:
|
|
759
|
+
onClick: Nt,
|
|
760
|
+
disabled: !K.portfolioId || U.isPending,
|
|
761
|
+
children: U.isPending ? "Creating…" : "Create proposal"
|
|
584
762
|
})] })
|
|
585
763
|
] })
|
|
586
764
|
}),
|
|
587
765
|
(() => {
|
|
588
|
-
let e =
|
|
589
|
-
return /* @__PURE__ */ w(
|
|
766
|
+
let e = Y ? l.find((e) => e.id === Y.id) ?? Y : null, t = e ? H.filter((t) => t.subjectId === e.portfolioId) : [];
|
|
767
|
+
return /* @__PURE__ */ w(at, {
|
|
590
768
|
proposal: e,
|
|
591
|
-
portfolio: e ?
|
|
769
|
+
portfolio: e ? Q.get(e.portfolioId) ?? null : null,
|
|
592
770
|
relatedInsights: t,
|
|
593
|
-
nextStatuses: e ?
|
|
594
|
-
transitionPending:
|
|
771
|
+
nextStatuses: e ? Je[e.status] : [],
|
|
772
|
+
transitionPending: W.isPending,
|
|
595
773
|
onTransition: (t) => {
|
|
596
|
-
e &&
|
|
774
|
+
e && Pt(e, t);
|
|
597
775
|
},
|
|
598
776
|
onOpenChange: (e) => {
|
|
599
|
-
e ||
|
|
777
|
+
e || Ct(null);
|
|
600
778
|
}
|
|
601
779
|
});
|
|
602
780
|
})(),
|
|
603
|
-
/* @__PURE__ */ w(
|
|
604
|
-
open:
|
|
781
|
+
/* @__PURE__ */ w(re, {
|
|
782
|
+
open: X !== null,
|
|
605
783
|
onOpenChange: (e) => {
|
|
606
|
-
e ||
|
|
784
|
+
e || Z(null);
|
|
607
785
|
},
|
|
608
|
-
title:
|
|
609
|
-
description:
|
|
610
|
-
confirmLabel:
|
|
786
|
+
title: X?.status === "REJECTED" ? "Reject this proposal?" : "Cancel this proposal?",
|
|
787
|
+
description: X ? `This moves the rebalance proposal for ${Q.get(X.proposal.portfolioId)?.name ?? "this portfolio"} to ${F(X.status)}. This cannot be undone.` : void 0,
|
|
788
|
+
confirmLabel: X?.status === "REJECTED" ? "Reject" : "Cancel proposal",
|
|
611
789
|
cancelLabel: "Keep",
|
|
612
790
|
destructive: !0,
|
|
613
|
-
pending:
|
|
791
|
+
pending: W.isPending,
|
|
614
792
|
onConfirm: () => {
|
|
615
|
-
|
|
616
|
-
id:
|
|
617
|
-
status:
|
|
618
|
-
}, { onSuccess: () =>
|
|
793
|
+
X && W.mutate({
|
|
794
|
+
id: X.proposal.id,
|
|
795
|
+
status: X.status
|
|
796
|
+
}, { onSuccess: () => Z(null) });
|
|
619
797
|
}
|
|
620
798
|
})
|
|
621
799
|
]
|
|
622
800
|
});
|
|
623
801
|
}
|
|
624
|
-
function
|
|
625
|
-
let s = e ?
|
|
626
|
-
return /* @__PURE__ */ w(
|
|
802
|
+
function at({ proposal: e, portfolio: t, relatedInsights: n, nextStatuses: r, transitionPending: i, onTransition: a, onOpenChange: o }) {
|
|
803
|
+
let s = e ? et(e.trades) : null, c = e != null && t?.driftThresholdPct != null && Number.isFinite(t.driftThresholdPct) && e.driftPct >= t.driftThresholdPct;
|
|
804
|
+
return /* @__PURE__ */ w(Ee, {
|
|
627
805
|
open: e !== null,
|
|
628
806
|
onOpenChange: o,
|
|
629
|
-
children: /* @__PURE__ */ w(
|
|
807
|
+
children: /* @__PURE__ */ w(Oe, {
|
|
630
808
|
className: "max-h-[88vh] max-w-3xl overflow-y-auto",
|
|
631
|
-
children: e ? /* @__PURE__ */ T(
|
|
632
|
-
/* @__PURE__ */ T(
|
|
809
|
+
children: e ? /* @__PURE__ */ T(Se, { children: [
|
|
810
|
+
/* @__PURE__ */ T(je, { children: [
|
|
633
811
|
/* @__PURE__ */ w("p", {
|
|
634
812
|
className: "text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
635
813
|
children: "Detail"
|
|
636
814
|
}),
|
|
637
|
-
/* @__PURE__ */ T(
|
|
815
|
+
/* @__PURE__ */ T(Me, {
|
|
638
816
|
className: "flex flex-wrap items-center gap-2 text-xl",
|
|
639
817
|
children: [
|
|
640
818
|
t?.name ?? "Rebalance proposal",
|
|
@@ -644,11 +822,11 @@ function et({ proposal: e, portfolio: t, relatedInsights: n, nextStatuses: r, tr
|
|
|
644
822
|
}),
|
|
645
823
|
/* @__PURE__ */ w(E, {
|
|
646
824
|
variant: g(e.status),
|
|
647
|
-
children:
|
|
825
|
+
children: F(e.status)
|
|
648
826
|
})
|
|
649
827
|
]
|
|
650
828
|
}),
|
|
651
|
-
/* @__PURE__ */ T(
|
|
829
|
+
/* @__PURE__ */ T(ke, { children: [
|
|
652
830
|
"Created ",
|
|
653
831
|
m(e.createdAt),
|
|
654
832
|
e.executedAt ? ` · executed ${m(e.executedAt)}` : ""
|
|
@@ -657,8 +835,8 @@ function et({ proposal: e, portfolio: t, relatedInsights: n, nextStatuses: r, tr
|
|
|
657
835
|
/* @__PURE__ */ w("div", {
|
|
658
836
|
className: "rounded-xl border border-border-subtle bg-bg-surface p-4",
|
|
659
837
|
children: /* @__PURE__ */ w(d, {
|
|
660
|
-
steps:
|
|
661
|
-
current:
|
|
838
|
+
steps: I,
|
|
839
|
+
current: F(e.status)
|
|
662
840
|
})
|
|
663
841
|
}),
|
|
664
842
|
/* @__PURE__ */ T("div", {
|
|
@@ -669,7 +847,7 @@ function et({ proposal: e, portfolio: t, relatedInsights: n, nextStatuses: r, tr
|
|
|
669
847
|
value: h(e.driftPct),
|
|
670
848
|
deltaTone: c ? "negative" : "neutral",
|
|
671
849
|
glow: c,
|
|
672
|
-
icon: /* @__PURE__ */ w(
|
|
850
|
+
icon: /* @__PURE__ */ w(y, {
|
|
673
851
|
className: "size-4",
|
|
674
852
|
"aria-hidden": "true"
|
|
675
853
|
})
|
|
@@ -707,38 +885,38 @@ function et({ proposal: e, portfolio: t, relatedInsights: n, nextStatuses: r, tr
|
|
|
707
885
|
children: "Proposed trades"
|
|
708
886
|
}), s && s.length > 0 ? /* @__PURE__ */ w("div", {
|
|
709
887
|
className: "overflow-x-auto rounded-lg border border-border-subtle",
|
|
710
|
-
children: /* @__PURE__ */ T(
|
|
711
|
-
/* @__PURE__ */ w(
|
|
712
|
-
/* @__PURE__ */ w(
|
|
713
|
-
/* @__PURE__ */ w(
|
|
888
|
+
children: /* @__PURE__ */ T(We, { children: [/* @__PURE__ */ w(Ke, { children: /* @__PURE__ */ T(P, { children: [
|
|
889
|
+
/* @__PURE__ */ w(N, { children: "Action" }),
|
|
890
|
+
/* @__PURE__ */ w(N, { children: "Symbol" }),
|
|
891
|
+
/* @__PURE__ */ w(N, {
|
|
714
892
|
className: "text-right",
|
|
715
893
|
children: "Quantity"
|
|
716
894
|
}),
|
|
717
|
-
/* @__PURE__ */ w(
|
|
895
|
+
/* @__PURE__ */ w(N, {
|
|
718
896
|
className: "text-right",
|
|
719
897
|
children: "Est. value"
|
|
720
898
|
})
|
|
721
|
-
] }) }), /* @__PURE__ */ w(
|
|
722
|
-
/* @__PURE__ */ w(
|
|
723
|
-
className: `font-semibold ${
|
|
899
|
+
] }) }), /* @__PURE__ */ w(Ge, { children: s.map((e, n) => /* @__PURE__ */ T(P, { children: [
|
|
900
|
+
/* @__PURE__ */ w(M, {
|
|
901
|
+
className: `font-semibold ${L(e.action)}`,
|
|
724
902
|
children: e.action ? e.action.toUpperCase() : "—"
|
|
725
903
|
}),
|
|
726
|
-
/* @__PURE__ */ w(
|
|
904
|
+
/* @__PURE__ */ w(M, {
|
|
727
905
|
className: "font-medium text-text-primary",
|
|
728
906
|
children: e.symbol ?? "—"
|
|
729
907
|
}),
|
|
730
|
-
/* @__PURE__ */ w(
|
|
908
|
+
/* @__PURE__ */ w(M, {
|
|
731
909
|
className: "text-right tabular-nums text-text-secondary",
|
|
732
910
|
children: e.quantity == null ? "—" : e.quantity.toLocaleString()
|
|
733
911
|
}),
|
|
734
|
-
/* @__PURE__ */ w(
|
|
912
|
+
/* @__PURE__ */ w(M, {
|
|
735
913
|
className: "text-right tabular-nums text-text-secondary",
|
|
736
|
-
children: e.value == null ? "—" :
|
|
914
|
+
children: e.value == null ? "—" : le(e.value, t?.baseCurrency ?? "USD")
|
|
737
915
|
})
|
|
738
916
|
] }, n)) })] })
|
|
739
917
|
}) : /* @__PURE__ */ T("p", {
|
|
740
918
|
className: "text-sm text-text-secondary",
|
|
741
|
-
children: [
|
|
919
|
+
children: [nt(e.trades), " — no structured trade breakdown available."]
|
|
742
920
|
})]
|
|
743
921
|
}),
|
|
744
922
|
/* @__PURE__ */ T("div", {
|
|
@@ -761,10 +939,10 @@ function et({ proposal: e, portfolio: t, relatedInsights: n, nextStatuses: r, tr
|
|
|
761
939
|
disabled: i,
|
|
762
940
|
className: t ? "text-status-error-text" : void 0,
|
|
763
941
|
onClick: () => a(e),
|
|
764
|
-
children: [w(t ? C :
|
|
942
|
+
children: [w(t ? C : pe, {
|
|
765
943
|
className: "size-4",
|
|
766
944
|
"aria-hidden": "true"
|
|
767
|
-
}),
|
|
945
|
+
}), F(e)]
|
|
768
946
|
}, e);
|
|
769
947
|
})
|
|
770
948
|
}) : null,
|
|
@@ -789,15 +967,15 @@ function et({ proposal: e, portfolio: t, relatedInsights: n, nextStatuses: r, tr
|
|
|
789
967
|
}),
|
|
790
968
|
/* @__PURE__ */ w(E, {
|
|
791
969
|
variant: g(e.severity),
|
|
792
|
-
children:
|
|
970
|
+
children: F(e.severity)
|
|
793
971
|
}),
|
|
794
972
|
/* @__PURE__ */ w(E, {
|
|
795
973
|
variant: "outline",
|
|
796
|
-
children:
|
|
974
|
+
children: F(e.type)
|
|
797
975
|
}),
|
|
798
976
|
/* @__PURE__ */ w(E, {
|
|
799
977
|
variant: g(e.status),
|
|
800
|
-
children:
|
|
978
|
+
children: F(e.status)
|
|
801
979
|
})
|
|
802
980
|
]
|
|
803
981
|
}), e.detail ? /* @__PURE__ */ w("p", {
|
|
@@ -809,7 +987,7 @@ function et({ proposal: e, portfolio: t, relatedInsights: n, nextStatuses: r, tr
|
|
|
809
987
|
}) : null,
|
|
810
988
|
/* @__PURE__ */ w("div", {
|
|
811
989
|
className: "border-t border-border-subtle pt-4",
|
|
812
|
-
children: /* @__PURE__ */ w(
|
|
990
|
+
children: /* @__PURE__ */ w(ue, {
|
|
813
991
|
entityType: "brainyrich-rebalance",
|
|
814
992
|
entityId: e.id,
|
|
815
993
|
heading: "Discussion"
|
|
@@ -819,7 +997,49 @@ function et({ proposal: e, portfolio: t, relatedInsights: n, nextStatuses: r, tr
|
|
|
819
997
|
})
|
|
820
998
|
});
|
|
821
999
|
}
|
|
822
|
-
function
|
|
1000
|
+
function ot({ signal: e }) {
|
|
1001
|
+
let t = Object.entries(e.metrics ?? {});
|
|
1002
|
+
return /* @__PURE__ */ T("li", {
|
|
1003
|
+
className: "rounded-lg border border-border-subtle bg-bg-surface p-4",
|
|
1004
|
+
children: [
|
|
1005
|
+
/* @__PURE__ */ T("div", {
|
|
1006
|
+
className: "flex flex-wrap items-center gap-2",
|
|
1007
|
+
children: [
|
|
1008
|
+
/* @__PURE__ */ w("p", {
|
|
1009
|
+
className: "font-medium text-text-primary",
|
|
1010
|
+
children: e.title
|
|
1011
|
+
}),
|
|
1012
|
+
/* @__PURE__ */ w(E, {
|
|
1013
|
+
variant: g(e.severity),
|
|
1014
|
+
children: F(e.severity)
|
|
1015
|
+
}),
|
|
1016
|
+
/* @__PURE__ */ w(E, {
|
|
1017
|
+
variant: "outline",
|
|
1018
|
+
children: F(e.kind)
|
|
1019
|
+
})
|
|
1020
|
+
]
|
|
1021
|
+
}),
|
|
1022
|
+
e.detail ? /* @__PURE__ */ w("p", {
|
|
1023
|
+
className: "mt-1 text-sm text-text-secondary",
|
|
1024
|
+
children: e.detail
|
|
1025
|
+
}) : null,
|
|
1026
|
+
t.length > 0 ? /* @__PURE__ */ w("dl", {
|
|
1027
|
+
className: "mt-3 grid grid-cols-2 gap-x-4 gap-y-1 sm:grid-cols-3 lg:grid-cols-4",
|
|
1028
|
+
children: t.map(([e, t]) => /* @__PURE__ */ T("div", {
|
|
1029
|
+
className: "min-w-0",
|
|
1030
|
+
children: [/* @__PURE__ */ w("dt", {
|
|
1031
|
+
className: "truncate text-[11px] uppercase tracking-wide text-text-muted",
|
|
1032
|
+
children: F(e)
|
|
1033
|
+
}), /* @__PURE__ */ w("dd", {
|
|
1034
|
+
className: "truncate text-sm font-medium tabular-nums text-text-primary",
|
|
1035
|
+
children: tt(t)
|
|
1036
|
+
})]
|
|
1037
|
+
}, e))
|
|
1038
|
+
}) : null
|
|
1039
|
+
]
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
function st({ insight: e, onAcknowledge: t, onResolve: n, onDismiss: r, actionPending: i }) {
|
|
823
1043
|
let a = e.status === "RESOLVED" || e.status === "DISMISSED";
|
|
824
1044
|
return /* @__PURE__ */ T("div", {
|
|
825
1045
|
className: "flex items-start justify-between gap-4 rounded-lg border border-border-subtle bg-bg-surface p-4 transition-shadow motion-safe:hover:shadow-[var(--shadow-pop-hover,var(--shadow-elevation-2))]",
|
|
@@ -835,15 +1055,15 @@ function tt({ insight: e, onAcknowledge: t, onResolve: n, onDismiss: r, actionPe
|
|
|
835
1055
|
}),
|
|
836
1056
|
/* @__PURE__ */ w(E, {
|
|
837
1057
|
variant: g(e.severity),
|
|
838
|
-
children:
|
|
1058
|
+
children: F(e.severity)
|
|
839
1059
|
}),
|
|
840
1060
|
/* @__PURE__ */ w(E, {
|
|
841
1061
|
variant: "outline",
|
|
842
|
-
children:
|
|
1062
|
+
children: F(e.type)
|
|
843
1063
|
}),
|
|
844
1064
|
/* @__PURE__ */ w(E, {
|
|
845
1065
|
variant: g(e.status),
|
|
846
|
-
children:
|
|
1066
|
+
children: F(e.status)
|
|
847
1067
|
})
|
|
848
1068
|
]
|
|
849
1069
|
}),
|
|
@@ -859,24 +1079,24 @@ function tt({ insight: e, onAcknowledge: t, onResolve: n, onDismiss: r, actionPe
|
|
|
859
1079
|
}), a ? /* @__PURE__ */ w("span", {
|
|
860
1080
|
className: "mt-1 text-xs text-text-muted",
|
|
861
1081
|
children: "Closed"
|
|
862
|
-
}) : /* @__PURE__ */ T(
|
|
1082
|
+
}) : /* @__PURE__ */ T(Ne, { children: [/* @__PURE__ */ w(Le, {
|
|
863
1083
|
asChild: !0,
|
|
864
1084
|
children: /* @__PURE__ */ w(D, {
|
|
865
1085
|
variant: "ghost",
|
|
866
1086
|
size: "sm",
|
|
867
1087
|
"aria-label": `Actions for ${e.title}`,
|
|
868
1088
|
disabled: i,
|
|
869
|
-
children: /* @__PURE__ */ w(
|
|
1089
|
+
children: /* @__PURE__ */ w(_e, {
|
|
870
1090
|
className: "size-4",
|
|
871
1091
|
"aria-hidden": "true"
|
|
872
1092
|
})
|
|
873
1093
|
})
|
|
874
|
-
}), /* @__PURE__ */ T(
|
|
1094
|
+
}), /* @__PURE__ */ T(Pe, {
|
|
875
1095
|
align: "end",
|
|
876
1096
|
children: [
|
|
877
1097
|
e.status === "OPEN" ? /* @__PURE__ */ T(A, {
|
|
878
1098
|
onClick: t,
|
|
879
|
-
children: [/* @__PURE__ */ w(
|
|
1099
|
+
children: [/* @__PURE__ */ w(me, {
|
|
880
1100
|
className: "size-4",
|
|
881
1101
|
"aria-hidden": "true"
|
|
882
1102
|
}), "Acknowledge"]
|
|
@@ -901,6 +1121,6 @@ function tt({ insight: e, onAcknowledge: t, onResolve: n, onDismiss: r, actionPe
|
|
|
901
1121
|
});
|
|
902
1122
|
}
|
|
903
1123
|
//#endregion
|
|
904
|
-
export {
|
|
1124
|
+
export { R as RiskPage };
|
|
905
1125
|
|
|
906
1126
|
//# sourceMappingURL=RiskPage.js.map
|