@handled-ai/design-system 0.16.0 → 0.16.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/components/badge.d.ts +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/data-table-condition-filter.d.ts +37 -0
- package/dist/components/data-table-condition-filter.js +407 -0
- package/dist/components/data-table-condition-filter.js.map +1 -0
- package/dist/components/data-table-filter.d.ts +12 -1
- package/dist/components/data-table-filter.js +92 -10
- package/dist/components/data-table-filter.js.map +1 -1
- package/dist/components/data-table-toolbar.d.ts +1 -0
- package/dist/components/data-table.d.ts +1 -0
- package/dist/components/tabs.d.ts +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/prototype/index.d.ts +1 -0
- package/dist/prototype/prototype-accounts-view.d.ts +1 -0
- package/dist/prototype/prototype-admin-view.d.ts +1 -0
- package/dist/prototype/prototype-config.d.ts +1 -0
- package/dist/prototype/prototype-inbox-view.d.ts +4 -1
- package/dist/prototype/prototype-inbox-view.js +6 -1
- package/dist/prototype/prototype-inbox-view.js.map +1 -1
- package/dist/prototype/prototype-insights-view.d.ts +1 -0
- package/dist/prototype/prototype-shell.d.ts +1 -0
- package/package.json +1 -1
- package/src/components/__tests__/contact-list.test.tsx +1 -1
- package/src/components/__tests__/data-table-condition-filter.test.tsx +397 -0
- package/src/components/__tests__/data-table-filter-presets.test.tsx +1 -1
- package/src/components/__tests__/data-table-filter.test.tsx +270 -3
- package/src/components/data-table-condition-filter.tsx +513 -0
- package/src/components/data-table-filter.tsx +102 -4
- package/src/index.ts +1 -0
- package/src/prototype/__tests__/detail-view-attention.test.tsx +101 -0
- package/src/prototype/prototype-inbox-view.tsx +8 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { render, fireEvent } from "@testing-library/react";
|
|
4
|
+
import { DetailView, type DetailViewProps } from "../prototype-inbox-view";
|
|
5
|
+
import type { QueueItem, SignalScoreData } from "../prototype-config";
|
|
6
|
+
import type { TimelineEvent } from "../../components/timeline-activity";
|
|
7
|
+
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Helpers
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
const baseItem: QueueItem = {
|
|
13
|
+
id: "1",
|
|
14
|
+
title: "Test Signal",
|
|
15
|
+
details: "Some details",
|
|
16
|
+
statusColor: "green",
|
|
17
|
+
time: "2h ago",
|
|
18
|
+
company: "Acme Inc",
|
|
19
|
+
tag1: "renewal",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function makeSignalScore(): SignalScoreData {
|
|
23
|
+
return {
|
|
24
|
+
score: 75,
|
|
25
|
+
factors: [
|
|
26
|
+
{ key: "trigger", label: "Trigger strength", score: 70, why: "Strong signal" },
|
|
27
|
+
],
|
|
28
|
+
whyNow: "Strong signals detected.",
|
|
29
|
+
evidence: ["Evidence line 1"],
|
|
30
|
+
confidence: 80,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const sampleTimelineEvents: TimelineEvent[] = [
|
|
35
|
+
{ id: "t1", icon: React.createElement("span", null, "📧"), title: "Email sent", time: "1h ago" },
|
|
36
|
+
{ id: "t2", icon: React.createElement("span", null, "📞"), title: "Call logged", time: "3h ago" },
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
function baseProps(overrides: Partial<DetailViewProps> = {}): DetailViewProps {
|
|
40
|
+
return {
|
|
41
|
+
item: baseItem,
|
|
42
|
+
sections: { signalBrief: true, suggestedActions: false, timeline: true },
|
|
43
|
+
getSignalScore: () => makeSignalScore(),
|
|
44
|
+
buildSuggestedActions: () => [],
|
|
45
|
+
buildSourceItems: () => [],
|
|
46
|
+
getTimelineEvents: () => sampleTimelineEvents,
|
|
47
|
+
accountContacts: [],
|
|
48
|
+
emailSignature: "",
|
|
49
|
+
iconMap: {},
|
|
50
|
+
...overrides,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// Tests
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
|
|
58
|
+
describe("DetailView attentionCount", () => {
|
|
59
|
+
it("renders attention pill with count when attentionCount > 0 and timeline collapsed", () => {
|
|
60
|
+
const props = baseProps({ attentionCount: 3 });
|
|
61
|
+
const { container } = render(<DetailView {...props} />);
|
|
62
|
+
const pill = container.querySelector("span.inline-flex");
|
|
63
|
+
expect(pill).not.toBeNull();
|
|
64
|
+
expect(pill!.textContent).toContain("3");
|
|
65
|
+
expect(pill!.textContent).toContain("new");
|
|
66
|
+
expect(pill!.className).toContain("bg-destructive/10");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("does NOT render pill when attentionCount is 0", () => {
|
|
70
|
+
const props = baseProps({ attentionCount: 0 });
|
|
71
|
+
const { container } = render(<DetailView {...props} />);
|
|
72
|
+
const pill = container.querySelector("span.inline-flex");
|
|
73
|
+
expect(pill).toBeNull();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("does NOT render pill when attentionCount is undefined", () => {
|
|
77
|
+
const props = baseProps({ attentionCount: undefined });
|
|
78
|
+
const { container } = render(<DetailView {...props} />);
|
|
79
|
+
const pill = container.querySelector("span.inline-flex");
|
|
80
|
+
expect(pill).toBeNull();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("does NOT render pill when timeline is expanded", () => {
|
|
84
|
+
const props = baseProps({ attentionCount: 5 });
|
|
85
|
+
const { container } = render(<DetailView {...props} />);
|
|
86
|
+
|
|
87
|
+
// Pill should be visible while collapsed
|
|
88
|
+
let pill = container.querySelector("span.inline-flex");
|
|
89
|
+
expect(pill).not.toBeNull();
|
|
90
|
+
expect(pill!.textContent).toContain("5");
|
|
91
|
+
|
|
92
|
+
// Click the timeline header button to expand
|
|
93
|
+
const timelineButton = container.querySelector("button.group\\/timeline") as HTMLElement;
|
|
94
|
+
expect(timelineButton).not.toBeNull();
|
|
95
|
+
fireEvent.click(timelineButton);
|
|
96
|
+
|
|
97
|
+
// After expanding, pill should be gone
|
|
98
|
+
pill = container.querySelector("span.inline-flex");
|
|
99
|
+
expect(pill).toBeNull();
|
|
100
|
+
});
|
|
101
|
+
});
|
|
@@ -142,6 +142,8 @@ export interface DetailViewProps {
|
|
|
142
142
|
approveButtonIconUrl?: string
|
|
143
143
|
opportunityPreview?: OpportunityPreview
|
|
144
144
|
onRequestApproval?: () => Promise<void>
|
|
145
|
+
/** Number of important/attention-worthy events to highlight on the collapsed timeline header. */
|
|
146
|
+
attentionCount?: number
|
|
145
147
|
}
|
|
146
148
|
|
|
147
149
|
export function DetailView({
|
|
@@ -172,6 +174,7 @@ export function DetailView({
|
|
|
172
174
|
approveButtonIconUrl,
|
|
173
175
|
opportunityPreview,
|
|
174
176
|
onRequestApproval,
|
|
177
|
+
attentionCount,
|
|
175
178
|
}: DetailViewProps) {
|
|
176
179
|
const [evidenceExpanded, setEvidenceExpanded] = React.useState(false)
|
|
177
180
|
const [showTimeline, setShowTimeline] = React.useState(false)
|
|
@@ -422,6 +425,11 @@ export function DetailView({
|
|
|
422
425
|
>
|
|
423
426
|
<div className="flex items-center gap-2">
|
|
424
427
|
<h3 className="text-xs font-bold text-muted-foreground uppercase tracking-wider group-hover/timeline:text-foreground transition-colors">Activity timeline</h3>
|
|
428
|
+
{!showTimeline && attentionCount != null && attentionCount > 0 && (
|
|
429
|
+
<span className="inline-flex items-center gap-1 rounded-full bg-destructive/10 px-1.5 py-0.5 text-[10px] font-semibold text-destructive border border-destructive/20">
|
|
430
|
+
{attentionCount} new
|
|
431
|
+
</span>
|
|
432
|
+
)}
|
|
425
433
|
{!showTimeline && (lastActivityTime || (timelineEvents.length > 0 && timelineEvents[0].time)) && (
|
|
426
434
|
<span className="text-[11px] text-muted-foreground/60">
|
|
427
435
|
· Last activity {lastActivityTime ?? timelineEvents[0]?.time ?? ''}
|