@sentry/junior-dashboard 0.259.0 → 0.260.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/README.md +5 -3
- package/dist/app.js +88 -37
- package/dist/chunks/github-light-QHW3AEMR.js +1 -0
- package/dist/client.js +86 -50
- package/dist/index.js +88 -37
- package/dist/tailwind.css +1 -1
- package/package.json +3 -3
- package/src/client/App.tsx +0 -1
- package/src/client/code.tsx +10 -4
- package/src/client/components/ProfileMenu.tsx +3 -0
- package/src/client/components/README.md +12 -2
- package/src/client/components/ThemeSwitcher.tsx +48 -0
- package/src/client/components/charts/ActivityChart.tsx +6 -7
- package/src/client/components/charts/InputCacheChart.tsx +1 -1
- package/src/client/components/charts/SystemMetricCharts.tsx +3 -3
- package/src/client/components/charts/WorkspaceUsageChart.tsx +1 -1
- package/src/client/components/charts/cache-input.ts +11 -3
- package/src/client/components/layout/DashboardHeader.tsx +2 -9
- package/src/client/conversations/ConversationBrief.tsx +35 -9
- package/src/client/conversations/ConversationHomeList.tsx +7 -1
- package/src/client/conversations/ConversationMeta.tsx +19 -7
- package/src/client/conversations/ConversationTranscript.tsx +8 -11
- package/src/client/conversations/EventDetails.tsx +9 -5
- package/src/client/conversations/README.md +6 -0
- package/src/client/conversations/TranscriptContextEventView.tsx +5 -1
- package/src/client/conversations/TranscriptEventView.tsx +48 -9
- package/src/client/conversations/TranscriptMessageView.tsx +6 -1
- package/src/client/conversations/TranscriptStructuredEventView.tsx +4 -2
- package/src/client/conversations/TranscriptText.tsx +28 -20
- package/src/client/conversations/conversationActivityPreview.ts +6 -0
- package/src/client/conversations/eventTranscript.ts +4 -1
- package/src/client/conversations/transcriptMentions.tsx +27 -10
- package/src/client/pages/automations/AutomationCostChart.tsx +2 -2
- package/src/client/pages/automations/AutomationDetailsDrawer.tsx +4 -1
- package/src/client/pages/automations/AutomationExecutionChart.tsx +2 -2
- package/src/client/pages/automations/AutomationExecutionStatusChart.tsx +3 -3
- package/src/client/pages/code/CodeActivityChart.tsx +4 -4
- package/src/client/pages/dev/ComponentsPage.tsx +7 -3
- package/src/client/pages/dev/ConversationFixture.tsx +29 -0
- package/src/client/pages/locations/LocationActivityChart.tsx +14 -4
- package/src/client/pages/locations/LocationDirectoryActivityChart.tsx +14 -9
- package/src/client/pages/memory/MemoryCostChart.tsx +5 -5
- package/src/client/pages/memory/MemoryDetailsDrawer.tsx +9 -2
- package/src/client/pages/memory/MemoryTimeline.tsx +2 -2
- package/src/client/pages/people/ContributionGrid.tsx +8 -8
- package/src/client/pages/people/PeopleActivityChart.tsx +23 -10
- package/src/client/pages/system/BaseSandboxCard.tsx +76 -0
- package/src/client/pages/system/ConversationActivityChart.tsx +2 -2
- package/src/client/pages/system/PluginBarChart.tsx +12 -6
- package/src/client/pages/system/SandboxSizeSummary.tsx +47 -0
- package/src/client/pages/system/WorkspaceDetails.tsx +11 -1
- package/src/client/pages/system/WorkspaceEditor.tsx +19 -0
- package/src/client/pages/system/WorkspaceFormPage.tsx +28 -19
- package/src/client/pages/system/WorkspaceList.tsx +6 -1
- package/src/client/pages/system/WorkspacesPage.tsx +18 -12
- package/src/client/pages/system/workspaceDraft.ts +8 -0
- package/src/client/theme.ts +52 -0
- package/src/client/types.ts +8 -1
- package/src/mock-reporting/fixtures.ts +48 -35
- package/src/shell.ts +4 -1
- package/src/tailwind.css +109 -0
- package/src/theme.ts +49 -0
- package/src/client/pages/system/BaselineSnapshotCard.tsx +0 -18
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { memo } from "react";
|
|
2
|
+
import type { ActorIdentity } from "@sentry/junior/api/schema";
|
|
2
3
|
|
|
3
4
|
import { HighlightedCode } from "../code";
|
|
4
5
|
import { parseMarkdownBlocks, transcriptRoleKind } from "../format";
|
|
5
6
|
import { TranscriptMarkdown } from "./TranscriptMarkdown";
|
|
7
|
+
import { MentionPeopleProvider } from "./transcriptMentions";
|
|
6
8
|
|
|
7
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* Render transcript prose as Markdown with explicit fenced code blocks.
|
|
11
|
+
* `mentions` are the people that the API resolved for this text.
|
|
12
|
+
*/
|
|
8
13
|
export const TranscriptText = memo(function TranscriptText(props: {
|
|
14
|
+
mentions: readonly ActorIdentity[];
|
|
9
15
|
role?: string;
|
|
10
16
|
text: string;
|
|
11
17
|
}) {
|
|
@@ -13,27 +19,29 @@ export const TranscriptText = memo(function TranscriptText(props: {
|
|
|
13
19
|
const blocks = parseMarkdownBlocks(props.text);
|
|
14
20
|
|
|
15
21
|
return (
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
<MentionPeopleProvider mentions={props.mentions}>
|
|
23
|
+
<div className="grid min-w-0 gap-2">
|
|
24
|
+
{blocks.map((block, index) => {
|
|
25
|
+
if (block.language === "markdown" && !block.fenced) {
|
|
26
|
+
return (
|
|
27
|
+
<TranscriptMarkdown
|
|
28
|
+
compact={roleKind === "assistant" || roleKind === "user"}
|
|
29
|
+
key={index}
|
|
30
|
+
text={block.code}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
19
35
|
return (
|
|
20
|
-
<
|
|
21
|
-
|
|
36
|
+
<div
|
|
37
|
+
className="min-w-0 overflow-hidden rounded-md border border-dashboard-border-subtle bg-dashboard-surface-panel px-3 py-2.5"
|
|
22
38
|
key={index}
|
|
23
|
-
|
|
24
|
-
|
|
39
|
+
>
|
|
40
|
+
<HighlightedCode code={block.code} language={block.language} />
|
|
41
|
+
</div>
|
|
25
42
|
);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
<div
|
|
30
|
-
className="min-w-0 overflow-hidden rounded-md border border-dashboard-border-subtle bg-dashboard-surface-panel px-3 py-2.5"
|
|
31
|
-
key={index}
|
|
32
|
-
>
|
|
33
|
-
<HighlightedCode code={block.code} language={block.language} />
|
|
34
|
-
</div>
|
|
35
|
-
);
|
|
36
|
-
})}
|
|
37
|
-
</div>
|
|
43
|
+
})}
|
|
44
|
+
</div>
|
|
45
|
+
</MentionPeopleProvider>
|
|
38
46
|
);
|
|
39
47
|
});
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
// Slack writes links as `<https://example.com>` or `<https://example.com|label>`.
|
|
2
|
+
const SLACK_LINK_RE = /<((?:https?|mailto):[^\s|<>]+)(?:\|([^<>]*))?>/g;
|
|
3
|
+
|
|
1
4
|
/** Reduce message Markdown to compact plain text for conversation previews. */
|
|
2
5
|
export function formatConversationActivityPreview(text: string): string {
|
|
3
6
|
return text
|
|
7
|
+
.replace(SLACK_LINK_RE, (_, url: string, label?: string) =>
|
|
8
|
+
label?.trim() ? label.trim() : url,
|
|
9
|
+
)
|
|
4
10
|
.replace(/\[([^\]]+)\]\([^\s)]+(?:\s+"[^"]*")?\)/g, "$1")
|
|
5
11
|
.replace(/(^|\s)([*_~`]{1,3})(?=\S)/g, "$1")
|
|
6
12
|
.replace(/([*_~`]{1,3})(?=\s|$|[.,!?;:])/g, "")
|
|
@@ -37,6 +37,7 @@ function eventMessage(
|
|
|
37
37
|
role,
|
|
38
38
|
sourceSeq: event.seq,
|
|
39
39
|
timestamp: eventTimestamp(event),
|
|
40
|
+
...(event.mentions ? { mentions: event.mentions } : undefined),
|
|
40
41
|
};
|
|
41
42
|
}
|
|
42
43
|
|
|
@@ -213,12 +214,12 @@ export function transcriptMessagesFromEvents(
|
|
|
213
214
|
...(data.actorIdentity
|
|
214
215
|
? { actorIdentity: data.actorIdentity }
|
|
215
216
|
: undefined),
|
|
216
|
-
...(data.mentions ? { mentions: data.mentions } : undefined),
|
|
217
217
|
...(data.eventType ? { eventType: data.eventType } : undefined),
|
|
218
218
|
eventObjectType: data.eventObjectType,
|
|
219
219
|
...(data.trustedSummary
|
|
220
220
|
? { trustedSummary: data.trustedSummary }
|
|
221
221
|
: undefined),
|
|
222
|
+
...(data.events ? { events: data.events } : undefined),
|
|
222
223
|
...(data.explicitMention !== undefined
|
|
223
224
|
? { explicitMention: data.explicitMention }
|
|
224
225
|
: undefined),
|
|
@@ -388,6 +389,7 @@ export function transcriptMessagesFromEvents(
|
|
|
388
389
|
eventMessage(event, "system", [
|
|
389
390
|
{
|
|
390
391
|
type: "structured_event",
|
|
392
|
+
...(event.mentions ? { mentions: event.mentions } : undefined),
|
|
391
393
|
namespace: data.namespace,
|
|
392
394
|
name: data.name,
|
|
393
395
|
version: data.version,
|
|
@@ -415,6 +417,7 @@ export function transcriptMessagesFromEvents(
|
|
|
415
417
|
eventMessage(event, "system", [
|
|
416
418
|
{
|
|
417
419
|
type: "context_event",
|
|
420
|
+
...(event.mentions ? { mentions: event.mentions } : undefined),
|
|
418
421
|
event:
|
|
419
422
|
data.type === "handoff"
|
|
420
423
|
? {
|
|
@@ -3,7 +3,7 @@ import { Link } from "react-router";
|
|
|
3
3
|
import type { ActorIdentity } from "@sentry/junior/api/schema";
|
|
4
4
|
|
|
5
5
|
import { peoplePath } from "../format";
|
|
6
|
-
import
|
|
6
|
+
import { cn } from "../styles";
|
|
7
7
|
import { TRANSCRIPT_ANCHOR_CLASS } from "./transcriptMarkdownLinks";
|
|
8
8
|
import { HighlightText } from "./transcriptSearch";
|
|
9
9
|
|
|
@@ -22,16 +22,17 @@ const TranscriptMentionPeople = createContext<
|
|
|
22
22
|
ReadonlyMap<string, ActorIdentity>
|
|
23
23
|
>(new Map());
|
|
24
24
|
|
|
25
|
-
/**
|
|
26
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Share the people that the API resolved for one block of display text.
|
|
27
|
+
* Use `TranscriptText` or `MentionText`, which require the API mentions.
|
|
28
|
+
*/
|
|
29
|
+
export function MentionPeopleProvider(props: {
|
|
27
30
|
children: ReactNode;
|
|
28
|
-
|
|
31
|
+
mentions: readonly ActorIdentity[];
|
|
29
32
|
}) {
|
|
30
33
|
const people = new Map<string, ActorIdentity>();
|
|
31
|
-
for (const
|
|
32
|
-
|
|
33
|
-
if (person.slackUserId) people.set(person.slackUserId, person);
|
|
34
|
-
}
|
|
34
|
+
for (const person of props.mentions) {
|
|
35
|
+
if (person.slackUserId) people.set(person.slackUserId, person);
|
|
35
36
|
}
|
|
36
37
|
return (
|
|
37
38
|
<TranscriptMentionPeople.Provider value={people}>
|
|
@@ -40,7 +41,22 @@ export function TranscriptMentionPeopleProvider(props: {
|
|
|
40
41
|
);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
/** Render text with
|
|
44
|
+
/** Render one line of display text with the people the API resolved for it. */
|
|
45
|
+
export function MentionText(props: {
|
|
46
|
+
mentions: readonly ActorIdentity[];
|
|
47
|
+
text: string;
|
|
48
|
+
}) {
|
|
49
|
+
return (
|
|
50
|
+
<MentionPeopleProvider mentions={props.mentions}>
|
|
51
|
+
{renderMentionText(props.text, "mention-text")}
|
|
52
|
+
</MentionPeopleProvider>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Render text with Slack `<@U123>` and `<#C123|name>` tokens as readable
|
|
58
|
+
* mentions. It reads people from the nearest `MentionPeopleProvider`.
|
|
59
|
+
*/
|
|
44
60
|
export function renderMentionText(text: string, keyBase: string): ReactNode[] {
|
|
45
61
|
const nodes: ReactNode[] = [];
|
|
46
62
|
let cursor = 0;
|
|
@@ -88,7 +104,8 @@ function MentionView(props: { mention: TranscriptMention }) {
|
|
|
88
104
|
if (person?.email) {
|
|
89
105
|
return (
|
|
90
106
|
<Link
|
|
91
|
-
|
|
107
|
+
// Previews sit in cards that disable pointer events on their text.
|
|
108
|
+
className={cn("pointer-events-auto", TRANSCRIPT_ANCHOR_CLASS)}
|
|
92
109
|
title={id}
|
|
93
110
|
to={peoplePath(person.email)}
|
|
94
111
|
>
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
import { Card } from "../../components/layout/Card";
|
|
19
19
|
import { formatCostSummary } from "../../format";
|
|
20
20
|
|
|
21
|
-
const COST_COLOR = "
|
|
21
|
+
const COST_COLOR = "var(--color-cyan-300)";
|
|
22
22
|
|
|
23
23
|
/** Render linked conversation spend for completed automation executions. */
|
|
24
24
|
export function AutomationCostChart(props: {
|
|
@@ -103,7 +103,7 @@ export function AutomationCostChart(props: {
|
|
|
103
103
|
format={(value) => formatCostSummary({ total: value })}
|
|
104
104
|
layout={layout}
|
|
105
105
|
maximum={maximum}
|
|
106
|
-
stroke="
|
|
106
|
+
stroke="var(--color-slate-200)"
|
|
107
107
|
/>
|
|
108
108
|
<ActivityChartDateLabels
|
|
109
109
|
dates={days.map((day) => day.date)}
|
|
@@ -88,7 +88,10 @@ export function AutomationDetailsDrawer(props: {
|
|
|
88
88
|
<h3 className="mt-0 mb-2 text-sm font-medium text-dashboard-text-muted">
|
|
89
89
|
What to do
|
|
90
90
|
</h3>
|
|
91
|
-
<TranscriptText
|
|
91
|
+
<TranscriptText
|
|
92
|
+
mentions={automation.mentions ?? []}
|
|
93
|
+
text={automation.instruction}
|
|
94
|
+
/>
|
|
92
95
|
</div>
|
|
93
96
|
<AutomationLifecycle
|
|
94
97
|
key={`${automation.kind}:${automation.id}`}
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
import { Card } from "../../components/layout/Card";
|
|
19
19
|
import { formatActivityChartAverage } from "../../format";
|
|
20
20
|
|
|
21
|
-
const EXECUTION_COLOR = "
|
|
21
|
+
const EXECUTION_COLOR = "var(--color-amber-400)";
|
|
22
22
|
|
|
23
23
|
/** Render completed automation executions over a trailing window. */
|
|
24
24
|
export function AutomationExecutionChart(props: {
|
|
@@ -95,7 +95,7 @@ export function AutomationExecutionChart(props: {
|
|
|
95
95
|
format={formatActivityChartAverage}
|
|
96
96
|
layout={layout}
|
|
97
97
|
maximum={maximum}
|
|
98
|
-
stroke="
|
|
98
|
+
stroke="var(--color-slate-200)"
|
|
99
99
|
/>
|
|
100
100
|
<ActivityChartDateLabels
|
|
101
101
|
dates={days.map((day) => day.date)}
|
|
@@ -15,9 +15,9 @@ import {
|
|
|
15
15
|
import { Card } from "../../components/layout/Card";
|
|
16
16
|
|
|
17
17
|
const series = [
|
|
18
|
-
{ color: "
|
|
19
|
-
{ color: "
|
|
20
|
-
{ color: "
|
|
18
|
+
{ color: "var(--color-emerald-300)", key: "completed", label: "Completed" },
|
|
19
|
+
{ color: "var(--color-rose-300)", key: "failed", label: "Failed" },
|
|
20
|
+
{ color: "var(--color-amber-300)", key: "blocked", label: "Blocked" },
|
|
21
21
|
] as const;
|
|
22
22
|
|
|
23
23
|
/** Render one automation's terminal executions by status over a trailing window. */
|
|
@@ -19,9 +19,9 @@ import { ChartLegend } from "../../components/charts/ChartLegend";
|
|
|
19
19
|
import { Card } from "../../components/layout/Card";
|
|
20
20
|
import { formatActivityChartAverage } from "../../format";
|
|
21
21
|
|
|
22
|
-
const CREATED_COLOR = "
|
|
23
|
-
const MERGED_COLOR = "
|
|
24
|
-
const CLOSED_COLOR = "
|
|
22
|
+
const CREATED_COLOR = "var(--color-cyan-300)";
|
|
23
|
+
const MERGED_COLOR = "var(--color-emerald-300)";
|
|
24
|
+
const CLOSED_COLOR = "var(--color-rose-400)";
|
|
25
25
|
|
|
26
26
|
/** Render created, merged, and closed code changes over a trailing window. */
|
|
27
27
|
export function CodeActivityChart(props: {
|
|
@@ -143,7 +143,7 @@ export function CodeActivityChart(props: {
|
|
|
143
143
|
format={formatActivityChartAverage}
|
|
144
144
|
layout={layout}
|
|
145
145
|
maximum={maximum}
|
|
146
|
-
stroke="
|
|
146
|
+
stroke="var(--color-slate-200)"
|
|
147
147
|
/>
|
|
148
148
|
<ActivityChartDateLabels
|
|
149
149
|
dates={days.map((day) => day.date)}
|
|
@@ -50,6 +50,7 @@ import { StatCard } from "../../components/metrics/StatCard";
|
|
|
50
50
|
import { StatusChip } from "../../components/StatusChip";
|
|
51
51
|
import { StatusDot } from "../../components/StatusDot";
|
|
52
52
|
import { TextArea, TextInput } from "../../components/TextInput";
|
|
53
|
+
import { ThemeSwitcher } from "../../components/ThemeSwitcher";
|
|
53
54
|
import { TranscriptMarkdown } from "../../conversations/TranscriptMarkdown";
|
|
54
55
|
import { TranscriptText } from "../../conversations/TranscriptText";
|
|
55
56
|
import { TranscriptMessageShell } from "../../conversations/TranscriptMessageShell";
|
|
@@ -231,7 +232,6 @@ function FoundationsGalleryPage() {
|
|
|
231
232
|
<Fixture title="Conversation navigation">
|
|
232
233
|
<DashboardChromeProvider>
|
|
233
234
|
<DashboardHeader
|
|
234
|
-
compact
|
|
235
235
|
mobileNavigationOpen={navigationOpen}
|
|
236
236
|
navItems={[
|
|
237
237
|
{ key: "code", label: "Code", to: "/code" },
|
|
@@ -301,6 +301,9 @@ function FoundationsGalleryPage() {
|
|
|
301
301
|
</Drawer>
|
|
302
302
|
) : null}
|
|
303
303
|
</Fixture>
|
|
304
|
+
<Fixture title="Theme">
|
|
305
|
+
<ThemeSwitcher className="max-w-64" />
|
|
306
|
+
</Fixture>
|
|
304
307
|
<Fixture title="Color tokens">
|
|
305
308
|
<div className="grid gap-4">
|
|
306
309
|
<TokenSwatchRow
|
|
@@ -733,6 +736,7 @@ function TranscriptsGalleryPage() {
|
|
|
733
736
|
Junior
|
|
734
737
|
</span>
|
|
735
738
|
<TranscriptText
|
|
739
|
+
mentions={[]}
|
|
736
740
|
role="assistant"
|
|
737
741
|
text={
|
|
738
742
|
"Your reminder is set.\n\nI'll remind you to drink water every 30 minutes until you ask me to stop."
|
|
@@ -793,10 +797,10 @@ function TranscriptsGalleryPage() {
|
|
|
793
797
|
<TranscriptMarkdown text={GFM_SAMPLE} />
|
|
794
798
|
</Fixture>
|
|
795
799
|
<Fixture title="TranscriptText assistant">
|
|
796
|
-
<TranscriptText role="assistant" text={MIXED_ASSISTANT} />
|
|
800
|
+
<TranscriptText mentions={[]} role="assistant" text={MIXED_ASSISTANT} />
|
|
797
801
|
</Fixture>
|
|
798
802
|
<Fixture title="TranscriptText user">
|
|
799
|
-
<TranscriptText role="user" text={EVENT_NOTIFICATION} />
|
|
803
|
+
<TranscriptText mentions={[]} role="user" text={EVENT_NOTIFICATION} />
|
|
800
804
|
</Fixture>
|
|
801
805
|
<Fixture title="Tool calls">
|
|
802
806
|
<ToolCallGallery />
|
|
@@ -107,6 +107,35 @@ const EVENTS: ConversationReportEventData[] = [
|
|
|
107
107
|
trustedSummary: "GitHub PR getsentry/junior#1200 received a review.",
|
|
108
108
|
text: "The preview is ready for visual review.",
|
|
109
109
|
},
|
|
110
|
+
{
|
|
111
|
+
type: "message",
|
|
112
|
+
messageId: "gallery-event-batch",
|
|
113
|
+
role: "user",
|
|
114
|
+
eventType: "pull_request.review.approved",
|
|
115
|
+
eventObjectType: "code_change",
|
|
116
|
+
trustedSummary: "GitHub PR getsentry/junior#1200 was approved by dcramer.",
|
|
117
|
+
events: [
|
|
118
|
+
{
|
|
119
|
+
eventType: "pull_request.review.approved",
|
|
120
|
+
label: "GitHub PR getsentry/junior#1200",
|
|
121
|
+
trustedSummary:
|
|
122
|
+
"GitHub PR getsentry/junior#1200 was approved by dcramer.",
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
eventType: "pull_request.review.commented",
|
|
126
|
+
label: "GitHub PR getsentry/junior#1200",
|
|
127
|
+
trustedSummary:
|
|
128
|
+
"GitHub PR getsentry/junior#1200 received a review comment from cursor[bot].",
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
eventType: "pull_request.review_comment.created",
|
|
132
|
+
label: "GitHub PR getsentry/junior#1200",
|
|
133
|
+
trustedSummary:
|
|
134
|
+
"GitHub PR getsentry/junior#1200 received an inline review comment from cursor[bot].",
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
text: "[task]\n\nThis is a task, not a message from a person.\n\nYou received 3 events.",
|
|
138
|
+
},
|
|
110
139
|
];
|
|
111
140
|
|
|
112
141
|
const CONVERSATION: ConversationDetailReport = {
|
|
@@ -43,7 +43,13 @@ export function LocationActivityChart(props: {
|
|
|
43
43
|
<ChartLegend
|
|
44
44
|
ariaLabel="Conversation activity period"
|
|
45
45
|
inline
|
|
46
|
-
items={[
|
|
46
|
+
items={[
|
|
47
|
+
{
|
|
48
|
+
color: "var(--color-cyan-400)",
|
|
49
|
+
key: "period",
|
|
50
|
+
label: "90 days",
|
|
51
|
+
},
|
|
52
|
+
]}
|
|
47
53
|
/>
|
|
48
54
|
}
|
|
49
55
|
/>
|
|
@@ -55,8 +61,12 @@ export function LocationActivityChart(props: {
|
|
|
55
61
|
>
|
|
56
62
|
<defs>
|
|
57
63
|
<linearGradient id="location-bars" x1="0" x2="0" y1="0" y2="1">
|
|
58
|
-
<stop offset="0%" stopColor="
|
|
59
|
-
<stop
|
|
64
|
+
<stop offset="0%" stopColor="var(--color-cyan-400)" />
|
|
65
|
+
<stop
|
|
66
|
+
offset="100%"
|
|
67
|
+
stopColor="var(--color-amber-500)"
|
|
68
|
+
stopOpacity="0.65"
|
|
69
|
+
/>
|
|
60
70
|
</linearGradient>
|
|
61
71
|
</defs>
|
|
62
72
|
<ActivityChartGrid layout={layout} maximum={maximum} />
|
|
@@ -98,7 +108,7 @@ export function LocationActivityChart(props: {
|
|
|
98
108
|
format={formatActivityChartAverage}
|
|
99
109
|
layout={layout}
|
|
100
110
|
maximum={maximum}
|
|
101
|
-
stroke="
|
|
111
|
+
stroke="var(--color-cyan-400)"
|
|
102
112
|
/>
|
|
103
113
|
<ActivityChartDateLabels
|
|
104
114
|
dates={props.days.map((day) => day.date)}
|
|
@@ -24,8 +24,7 @@ export function LocationDirectoryActivityChart(props: {
|
|
|
24
24
|
days: LocationActivityDayReport[];
|
|
25
25
|
}) {
|
|
26
26
|
const bucketUnit = props.bucketUnit ?? "day";
|
|
27
|
-
const perBucket =
|
|
28
|
-
`Conversations per ${timeRangeBucketPerLabel(bucketUnit)}`;
|
|
27
|
+
const perBucket = `Conversations per ${timeRangeBucketPerLabel(bucketUnit)}`;
|
|
29
28
|
|
|
30
29
|
const layout = createActivityChartLayout(260);
|
|
31
30
|
const maximum = Math.max(
|
|
@@ -42,17 +41,23 @@ export function LocationDirectoryActivityChart(props: {
|
|
|
42
41
|
return (
|
|
43
42
|
<Card>
|
|
44
43
|
<CardHeader
|
|
45
|
-
description={
|
|
46
|
-
`${timeRangeBucketAdjective(bucketUnit)} public volume compared with private activity in aggregate.`
|
|
47
|
-
}
|
|
44
|
+
description={`${timeRangeBucketAdjective(bucketUnit)} public volume compared with private activity in aggregate.`}
|
|
48
45
|
title={perBucket}
|
|
49
46
|
trailing={
|
|
50
47
|
<ChartLegend
|
|
51
48
|
ariaLabel="Conversation visibility legend"
|
|
52
49
|
inline
|
|
53
50
|
items={[
|
|
54
|
-
{
|
|
55
|
-
|
|
51
|
+
{
|
|
52
|
+
color: "var(--color-cyan-400)",
|
|
53
|
+
key: "public",
|
|
54
|
+
label: "public",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
color: "var(--color-amber-400)",
|
|
58
|
+
key: "private",
|
|
59
|
+
label: "private",
|
|
60
|
+
},
|
|
56
61
|
]}
|
|
57
62
|
/>
|
|
58
63
|
}
|
|
@@ -70,13 +75,13 @@ export function LocationDirectoryActivityChart(props: {
|
|
|
70
75
|
[
|
|
71
76
|
{
|
|
72
77
|
count: day.publicConversations,
|
|
73
|
-
fill: "
|
|
78
|
+
fill: "var(--color-cyan-400)",
|
|
74
79
|
key: "public",
|
|
75
80
|
x: groupX,
|
|
76
81
|
},
|
|
77
82
|
{
|
|
78
83
|
count: day.privateConversations,
|
|
79
|
-
fill: "
|
|
84
|
+
fill: "var(--color-amber-400)",
|
|
80
85
|
key: "private",
|
|
81
86
|
x: groupX + barWidth + gap,
|
|
82
87
|
},
|
|
@@ -74,13 +74,13 @@ export function MemoryCostChart(props: {
|
|
|
74
74
|
ariaLabel="Memory cost legend"
|
|
75
75
|
items={[
|
|
76
76
|
{
|
|
77
|
-
color: "
|
|
77
|
+
color: "var(--color-cyan-300)",
|
|
78
78
|
key: "extraction",
|
|
79
79
|
label: "Extraction",
|
|
80
80
|
value: formatCostSummary({ total: extractionTotal }),
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
|
-
color: "
|
|
83
|
+
color: "var(--color-fuchsia-400)",
|
|
84
84
|
key: "recall",
|
|
85
85
|
label: "Recall",
|
|
86
86
|
value: formatCostSummary({ total: recallTotal }),
|
|
@@ -130,7 +130,7 @@ export function MemoryCostChart(props: {
|
|
|
130
130
|
>
|
|
131
131
|
<g tabIndex={0}>
|
|
132
132
|
<rect
|
|
133
|
-
fill="
|
|
133
|
+
fill="var(--color-cyan-300)"
|
|
134
134
|
height={extractionHeight}
|
|
135
135
|
opacity={day.extraction.costUsd > 0 ? 0.82 : 0.1}
|
|
136
136
|
rx="1"
|
|
@@ -139,7 +139,7 @@ export function MemoryCostChart(props: {
|
|
|
139
139
|
y={layout.top + layout.plotHeight - extractionHeight}
|
|
140
140
|
/>
|
|
141
141
|
<rect
|
|
142
|
-
fill="
|
|
142
|
+
fill="var(--color-fuchsia-400)"
|
|
143
143
|
height={recallHeight}
|
|
144
144
|
opacity={day.recall.costUsd > 0 ? 0.82 : 0.1}
|
|
145
145
|
rx="1"
|
|
@@ -169,7 +169,7 @@ export function MemoryCostChart(props: {
|
|
|
169
169
|
format={(value) => formatCostSummary({ total: value })}
|
|
170
170
|
layout={layout}
|
|
171
171
|
maximum={maximum}
|
|
172
|
-
stroke="
|
|
172
|
+
stroke="var(--color-slate-200)"
|
|
173
173
|
/>
|
|
174
174
|
<ActivityChartDateLabels
|
|
175
175
|
dates={days.map((day) => day.date)}
|
|
@@ -10,6 +10,10 @@ import type {
|
|
|
10
10
|
PluginUserPageRecordAction,
|
|
11
11
|
} from "../user/pluginUserPageData";
|
|
12
12
|
|
|
13
|
+
// The memory plugin API does not resolve mentions yet, so memory text shows
|
|
14
|
+
// Slack ids instead of names.
|
|
15
|
+
const NO_MEMORY_MENTIONS: readonly [] = [];
|
|
16
|
+
|
|
13
17
|
type MemoryActionMutation = UseMutationResult<
|
|
14
18
|
void,
|
|
15
19
|
Error,
|
|
@@ -86,10 +90,13 @@ export function MemoryDetailsDrawer(props: {
|
|
|
86
90
|
<div className="mb-2 font-sans font-medium text-xs text-dashboard-text-muted">
|
|
87
91
|
Memory
|
|
88
92
|
</div>
|
|
89
|
-
<TranscriptText text={record.title} />
|
|
93
|
+
<TranscriptText mentions={NO_MEMORY_MENTIONS} text={record.title} />
|
|
90
94
|
{record.description ? (
|
|
91
95
|
<div className="mt-3">
|
|
92
|
-
<TranscriptText
|
|
96
|
+
<TranscriptText
|
|
97
|
+
mentions={NO_MEMORY_MENTIONS}
|
|
98
|
+
text={record.description}
|
|
99
|
+
/>
|
|
93
100
|
</div>
|
|
94
101
|
) : null}
|
|
95
102
|
</div>
|
|
@@ -15,8 +15,8 @@ import { Card } from "../../components/layout/Card";
|
|
|
15
15
|
import type { MemoryDay } from "./memoryDashboard";
|
|
16
16
|
|
|
17
17
|
const series = [
|
|
18
|
-
{ color: "
|
|
19
|
-
{ color: "
|
|
18
|
+
{ color: "var(--color-cyan-300)", key: "personal", label: "Personal" },
|
|
19
|
+
{ color: "var(--color-emerald-300)", key: "public", label: "Public" },
|
|
20
20
|
] as const;
|
|
21
21
|
|
|
22
22
|
/** Render viewer memory creation as a stacked personal/public timeline. */
|
|
@@ -124,10 +124,10 @@ export function ContributionGrid(props: { days: ContributionDay[] }) {
|
|
|
124
124
|
className={cn(
|
|
125
125
|
"size-3 border border-dashboard-overlay",
|
|
126
126
|
level === 0 && "bg-dashboard-surface-hover",
|
|
127
|
-
level === 1 && "bg-[#133225]",
|
|
128
|
-
level === 2 && "bg-[#176a4a]",
|
|
129
|
-
level === 3 && "bg-[#22a06b]",
|
|
130
|
-
level === 4 && "bg-[#8bdc97]",
|
|
127
|
+
level === 1 && "bg-[#133225] light:bg-[#9be9a8]",
|
|
128
|
+
level === 2 && "bg-[#176a4a] light:bg-[#40c463]",
|
|
129
|
+
level === 3 && "bg-[#22a06b] light:bg-[#30a14e]",
|
|
130
|
+
level === 4 && "bg-[#8bdc97] light:bg-[#216e39]",
|
|
131
131
|
)}
|
|
132
132
|
key={level}
|
|
133
133
|
/>
|
|
@@ -156,8 +156,8 @@ function activityRuntime(day: ContributionDay): string {
|
|
|
156
156
|
function activityClass(count: number, max: number): string {
|
|
157
157
|
if (count <= 0) return "bg-dashboard-surface-hover";
|
|
158
158
|
const ratio = count / max;
|
|
159
|
-
if (ratio >= 0.75) return "bg-[#8bdc97]";
|
|
160
|
-
if (ratio >= 0.45) return "bg-[#22a06b]";
|
|
161
|
-
if (ratio >= 0.2) return "bg-[#176a4a]";
|
|
162
|
-
return "bg-[#133225]";
|
|
159
|
+
if (ratio >= 0.75) return "bg-[#8bdc97] light:bg-[#216e39]";
|
|
160
|
+
if (ratio >= 0.45) return "bg-[#22a06b] light:bg-[#30a14e]";
|
|
161
|
+
if (ratio >= 0.2) return "bg-[#176a4a] light:bg-[#40c463]";
|
|
162
|
+
return "bg-[#133225] light:bg-[#9be9a8]";
|
|
163
163
|
}
|
|
@@ -44,8 +44,7 @@ export function PeopleActivityChart(props: {
|
|
|
44
44
|
days: PeopleActivityDayReport[];
|
|
45
45
|
}) {
|
|
46
46
|
const bucketUnit = props.bucketUnit ?? "day";
|
|
47
|
-
const chartTitle =
|
|
48
|
-
`Active people per ${timeRangeBucketPerLabel(bucketUnit)}`;
|
|
47
|
+
const chartTitle = `Active people per ${timeRangeBucketPerLabel(bucketUnit)}`;
|
|
49
48
|
|
|
50
49
|
const layout = createActivityChartLayout(260);
|
|
51
50
|
const values = props.days.map((day) => day.activePeople);
|
|
@@ -70,7 +69,13 @@ export function PeopleActivityChart(props: {
|
|
|
70
69
|
<ChartLegend
|
|
71
70
|
ariaLabel="People activity legend"
|
|
72
71
|
inline
|
|
73
|
-
items={[
|
|
72
|
+
items={[
|
|
73
|
+
{
|
|
74
|
+
color: "var(--color-amber-400)",
|
|
75
|
+
key: "people",
|
|
76
|
+
label: "people",
|
|
77
|
+
},
|
|
78
|
+
]}
|
|
74
79
|
/>
|
|
75
80
|
}
|
|
76
81
|
/>
|
|
@@ -82,13 +87,21 @@ export function PeopleActivityChart(props: {
|
|
|
82
87
|
>
|
|
83
88
|
<defs>
|
|
84
89
|
<linearGradient id="people-area" x1="0" x2="0" y1="0" y2="1">
|
|
85
|
-
<stop
|
|
86
|
-
|
|
90
|
+
<stop
|
|
91
|
+
offset="0%"
|
|
92
|
+
stopColor="var(--color-amber-500)"
|
|
93
|
+
stopOpacity="0.3"
|
|
94
|
+
/>
|
|
95
|
+
<stop
|
|
96
|
+
offset="100%"
|
|
97
|
+
stopColor="var(--color-amber-500)"
|
|
98
|
+
stopOpacity="0"
|
|
99
|
+
/>
|
|
87
100
|
</linearGradient>
|
|
88
101
|
<linearGradient id="people-line" x1="0" x2="1" y1="0" y2="0">
|
|
89
|
-
<stop offset="0%" stopColor="
|
|
90
|
-
<stop offset="55%" stopColor="
|
|
91
|
-
<stop offset="100%" stopColor="
|
|
102
|
+
<stop offset="0%" stopColor="var(--color-amber-500)" />
|
|
103
|
+
<stop offset="55%" stopColor="var(--color-amber-400)" />
|
|
104
|
+
<stop offset="100%" stopColor="var(--color-cyan-400)" />
|
|
92
105
|
</linearGradient>
|
|
93
106
|
</defs>
|
|
94
107
|
<ActivityChartGrid layout={layout} maximum={maximum} />
|
|
@@ -122,7 +135,7 @@ export function PeopleActivityChart(props: {
|
|
|
122
135
|
<circle
|
|
123
136
|
cx={point.x}
|
|
124
137
|
cy={point.y}
|
|
125
|
-
fill="
|
|
138
|
+
fill="var(--color-amber-400)"
|
|
126
139
|
opacity={props.days.length > 30 ? 0.35 : 0.75}
|
|
127
140
|
r={props.days.length > 30 ? 3 : 4}
|
|
128
141
|
tabIndex={0}
|
|
@@ -136,7 +149,7 @@ export function PeopleActivityChart(props: {
|
|
|
136
149
|
format={formatActivityChartAverage}
|
|
137
150
|
layout={layout}
|
|
138
151
|
maximum={maximum}
|
|
139
|
-
stroke="
|
|
152
|
+
stroke="var(--color-amber-400)"
|
|
140
153
|
/>
|
|
141
154
|
<ActivityChartDateLabels
|
|
142
155
|
dates={props.days.map((day) => day.date)}
|