@sentry/junior-dashboard 0.240.0 → 0.241.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +2 -2
- package/dist/client.js +48 -48
- package/dist/index.js +2 -2
- package/dist/tailwind.css +1 -1
- package/package.json +3 -3
- package/src/client/pages/automations/AutomationEditPage.tsx +2 -2
- package/src/client/pages/automations/AutomationLifecycle.tsx +1 -2
- package/src/client/pages/automations/AutomationRow.tsx +1 -1
- package/src/client/pages/memory/MemoryPage.tsx +16 -4
- package/src/client/pages/memory/MemorySearchHighlight.tsx +49 -0
- package/src/client/pages/memory/memoryDashboard.ts +34 -1
|
@@ -34,9 +34,11 @@ import { cn } from "../../styles";
|
|
|
34
34
|
import {
|
|
35
35
|
type MemoryDashboardData,
|
|
36
36
|
useMemoryDashboardData,
|
|
37
|
+
useMemorySearchCounts,
|
|
37
38
|
} from "./memoryDashboard";
|
|
38
39
|
import { MemoryDetailsDrawer } from "./MemoryDetailsDrawer";
|
|
39
40
|
import { MemoryPageLayout } from "./MemoryPageLayout";
|
|
41
|
+
import { MemorySearchHighlight } from "./MemorySearchHighlight";
|
|
40
42
|
import { MemoryTimeline } from "./MemoryTimeline";
|
|
41
43
|
import { MemoryCostChart } from "./MemoryCostChart";
|
|
42
44
|
import { useMemoryRecord } from "./memoryRecord";
|
|
@@ -151,6 +153,11 @@ function MemoryLibrary(props: {
|
|
|
151
153
|
setSearchText,
|
|
152
154
|
} = usePluginUserPageData(props.page);
|
|
153
155
|
const dashboardQuery = useMemoryDashboardData();
|
|
156
|
+
const searchCountsQuery = useMemorySearchCounts(searchQuery);
|
|
157
|
+
// Tab totals follow the search. Without a search, the summary owns them.
|
|
158
|
+
const counts = searchQuery
|
|
159
|
+
? searchCountsQuery.data
|
|
160
|
+
: dashboardQuery.data?.stats;
|
|
154
161
|
const navigate = useNavigate();
|
|
155
162
|
const location = useLocation();
|
|
156
163
|
const { memoryId } = useParams();
|
|
@@ -217,17 +224,17 @@ function MemoryLibrary(props: {
|
|
|
217
224
|
ariaLabel="Memory collections"
|
|
218
225
|
items={[
|
|
219
226
|
{
|
|
220
|
-
count:
|
|
227
|
+
count: counts?.active,
|
|
221
228
|
label: "All",
|
|
222
229
|
value: "",
|
|
223
230
|
},
|
|
224
231
|
{
|
|
225
|
-
count:
|
|
232
|
+
count: counts?.personal,
|
|
226
233
|
label: "Private",
|
|
227
234
|
value: "private",
|
|
228
235
|
},
|
|
229
236
|
{
|
|
230
|
-
count:
|
|
237
|
+
count: counts?.public,
|
|
231
238
|
label: "Public",
|
|
232
239
|
value: "public",
|
|
233
240
|
},
|
|
@@ -274,6 +281,7 @@ function MemoryLibrary(props: {
|
|
|
274
281
|
)
|
|
275
282
|
}
|
|
276
283
|
record={record}
|
|
284
|
+
searchQuery={searchQuery}
|
|
277
285
|
selected={record.id === memoryId}
|
|
278
286
|
/>
|
|
279
287
|
))}
|
|
@@ -472,6 +480,7 @@ function MemoryRow(props: {
|
|
|
472
480
|
first: boolean;
|
|
473
481
|
onSelect(): void;
|
|
474
482
|
record: PluginUserPageRecord;
|
|
483
|
+
searchQuery: string;
|
|
475
484
|
selected: boolean;
|
|
476
485
|
}) {
|
|
477
486
|
const kind = metadataValue(props.record, "Type");
|
|
@@ -506,7 +515,10 @@ function MemoryRow(props: {
|
|
|
506
515
|
size={14}
|
|
507
516
|
/>
|
|
508
517
|
<h3 className="m-0 truncate font-display text-base font-medium leading-snug text-dashboard-text">
|
|
509
|
-
|
|
518
|
+
<MemorySearchHighlight
|
|
519
|
+
query={props.searchQuery}
|
|
520
|
+
text={props.record.title}
|
|
521
|
+
/>
|
|
510
522
|
</h3>
|
|
511
523
|
</div>
|
|
512
524
|
<div className="mt-1.5 truncate font-mono text-xs leading-relaxed text-dashboard-text-muted">
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Split a search query into the terms that memory search matches. Keep this
|
|
3
|
+
* in step with `searchTerms` in `@sentry/junior-memory` `src/viewer.ts`.
|
|
4
|
+
*/
|
|
5
|
+
function memorySearchTerms(query: string): string[] {
|
|
6
|
+
return [
|
|
7
|
+
...new Set(
|
|
8
|
+
query
|
|
9
|
+
.toLowerCase()
|
|
10
|
+
.split(/[^a-z0-9_'-]+/)
|
|
11
|
+
.filter((term) => term.length >= 2),
|
|
12
|
+
),
|
|
13
|
+
];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function escapeRegExp(value: string): string {
|
|
17
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Render memory text with each matched search term marked. */
|
|
21
|
+
export function MemorySearchHighlight(props: { query: string; text: string }) {
|
|
22
|
+
const terms = memorySearchTerms(props.query);
|
|
23
|
+
if (terms.length === 0) return <>{props.text}</>;
|
|
24
|
+
// Longer terms first so a term that contains another term wins the match.
|
|
25
|
+
const pattern = new RegExp(
|
|
26
|
+
`(${terms
|
|
27
|
+
.sort((a, b) => b.length - a.length)
|
|
28
|
+
.map(escapeRegExp)
|
|
29
|
+
.join("|")})`,
|
|
30
|
+
"gi",
|
|
31
|
+
);
|
|
32
|
+
// `split` with one capture group puts the matches at odd indexes.
|
|
33
|
+
return (
|
|
34
|
+
<>
|
|
35
|
+
{props.text.split(pattern).map((part, index) =>
|
|
36
|
+
index % 2 === 1 ? (
|
|
37
|
+
<mark
|
|
38
|
+
className="rounded-sm bg-amber-300/25 text-dashboard-text"
|
|
39
|
+
key={index}
|
|
40
|
+
>
|
|
41
|
+
{part}
|
|
42
|
+
</mark>
|
|
43
|
+
) : (
|
|
44
|
+
part
|
|
45
|
+
),
|
|
46
|
+
)}
|
|
47
|
+
</>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useQuery } from "@tanstack/react-query";
|
|
1
|
+
import { keepPreviousData, useQuery } from "@tanstack/react-query";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
4
|
import { fetchDashboardJson } from "../../http";
|
|
@@ -64,3 +64,36 @@ export function useMemoryDashboardData() {
|
|
|
64
64
|
retry: false,
|
|
65
65
|
});
|
|
66
66
|
}
|
|
67
|
+
|
|
68
|
+
const memoryCountsSchema = z
|
|
69
|
+
.object({
|
|
70
|
+
active: z.number().int().min(0),
|
|
71
|
+
personal: z.number().int().min(0),
|
|
72
|
+
public: z.number().int().min(0),
|
|
73
|
+
})
|
|
74
|
+
.strict();
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Load viewer-scoped memory totals that match a search query. The query stays
|
|
78
|
+
* idle without a search, because the dashboard summary owns unfiltered totals.
|
|
79
|
+
*/
|
|
80
|
+
export function useMemorySearchCounts(searchQuery: string) {
|
|
81
|
+
return useQuery({
|
|
82
|
+
enabled: Boolean(searchQuery),
|
|
83
|
+
placeholderData: keepPreviousData,
|
|
84
|
+
queryFn: ({ signal }) =>
|
|
85
|
+
fetchDashboardJson(
|
|
86
|
+
memoryCountsSchema,
|
|
87
|
+
`/api/plugins/memory/counts?${new URLSearchParams({ q: searchQuery })}`,
|
|
88
|
+
signal,
|
|
89
|
+
),
|
|
90
|
+
queryKey: [
|
|
91
|
+
"dashboard",
|
|
92
|
+
"plugin-user-page",
|
|
93
|
+
"memory",
|
|
94
|
+
"counts",
|
|
95
|
+
searchQuery,
|
|
96
|
+
],
|
|
97
|
+
retry: false,
|
|
98
|
+
});
|
|
99
|
+
}
|