@happyvertical/smrt-support 0.53.1 → 0.53.2
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/index.js +1 -1
- package/dist/manifest.json +1 -1
- package/dist/smrt-knowledge.json +3 -3
- package/package.json +12 -12
- package/dist/svelte/components/__tests__/CaseDetail.test.js +0 -86
- package/dist/svelte/components/__tests__/CaseQueue.test.js +0 -67
- package/dist/svelte/components/__tests__/RoutingRationale.test.js +0 -69
- package/dist/svelte/components/__tests__/TargetList.test.js +0 -84
- package/dist/svelte/components/__tests__/TimesheetsReexports.test.js +0 -16
package/dist/manifest.json
CHANGED
package/dist/smrt-knowledge.json
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
"sensitiveFieldsExcluded": true,
|
|
4
4
|
"generatedAt": "1970-01-01T00:00:00.000Z",
|
|
5
5
|
"packageName": "@happyvertical/smrt-support",
|
|
6
|
-
"packageVersion": "0.53.
|
|
6
|
+
"packageVersion": "0.53.2",
|
|
7
7
|
"sourceManifestPath": "dist/manifest.json",
|
|
8
8
|
"agentDocPath": "AGENTS.md",
|
|
9
9
|
"sourceHashes": {
|
|
10
|
-
"manifest": "
|
|
11
|
-
"packageJson": "
|
|
10
|
+
"manifest": "0b3eb6fb7e4cc07359935c5323619142dbf3398b6c1962fdf0ada66e900763b5",
|
|
11
|
+
"packageJson": "963791a8db82b3e31f0b10fb1712a6d9bba9d0b46923c10606fe8b8ca9b0270a",
|
|
12
12
|
"agents": "2ad2109ce8b2880f6144b97076a94ed185c68e84dfcd468f368d6a571ece0ef7"
|
|
13
13
|
},
|
|
14
14
|
"exports": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@happyvertical/smrt-support",
|
|
3
|
-
"version": "0.53.
|
|
3
|
+
"version": "0.53.2",
|
|
4
4
|
"smrtJsdoc": "strict",
|
|
5
5
|
"description": "AI-first Support Cases: channel-neutral intake, lifecycle, routing, service targets, and service time for the SMRT framework",
|
|
6
6
|
"type": "module",
|
|
@@ -27,15 +27,15 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@happyvertical/logger": "^0.98.0",
|
|
30
|
-
"@happyvertical/smrt-chat": "0.53.
|
|
31
|
-
"@happyvertical/smrt-core": "0.53.
|
|
32
|
-
"@happyvertical/smrt-jobs": "0.53.
|
|
33
|
-
"@happyvertical/smrt-messages": "0.53.
|
|
34
|
-
"@happyvertical/smrt-projects": "0.53.
|
|
35
|
-
"@happyvertical/smrt-tenancy": "0.53.
|
|
36
|
-
"@happyvertical/smrt-timesheets": "0.53.
|
|
37
|
-
"@happyvertical/smrt-ui": "0.53.
|
|
38
|
-
"@happyvertical/smrt-users": "0.53.
|
|
30
|
+
"@happyvertical/smrt-chat": "0.53.2",
|
|
31
|
+
"@happyvertical/smrt-core": "0.53.2",
|
|
32
|
+
"@happyvertical/smrt-jobs": "0.53.2",
|
|
33
|
+
"@happyvertical/smrt-messages": "0.53.2",
|
|
34
|
+
"@happyvertical/smrt-projects": "0.53.2",
|
|
35
|
+
"@happyvertical/smrt-tenancy": "0.53.2",
|
|
36
|
+
"@happyvertical/smrt-timesheets": "0.53.2",
|
|
37
|
+
"@happyvertical/smrt-ui": "0.53.2",
|
|
38
|
+
"@happyvertical/smrt-users": "0.53.2",
|
|
39
39
|
"@happyvertical/sql": "^0.98.0"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@happyvertical/smrt-vitest": "0.53.
|
|
50
|
+
"@happyvertical/smrt-vitest": "0.53.2",
|
|
51
51
|
"@sveltejs/package": "^2.5.8",
|
|
52
52
|
"@sveltejs/vite-plugin-svelte": "^7.3.0",
|
|
53
53
|
"@types/node": "24.13.6",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"directory": "packages/support"
|
|
78
78
|
},
|
|
79
79
|
"scripts": {
|
|
80
|
-
"build": "vite build --mode library && svelte-package -i src/svelte -o dist/svelte --tsconfig tsconfig.svelte.json",
|
|
80
|
+
"build": "vite build --mode library && svelte-package -i src/svelte -o dist/svelte --tsconfig tsconfig.svelte.json && node ../../scripts/prune-svelte-package-artifacts.js dist",
|
|
81
81
|
"build:watch": "vite build --mode library --watch",
|
|
82
82
|
"clean": "rm -rf dist",
|
|
83
83
|
"dev": "vite dev",
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
/**
|
|
3
|
-
* Component coverage for CaseDetail via the shared S11 harness (#1416).
|
|
4
|
-
*/
|
|
5
|
-
import { expectNoA11yViolations, render, screen, } from '@happyvertical/smrt-vitest/svelte';
|
|
6
|
-
import { describe, expect, it } from 'vitest';
|
|
7
|
-
import CaseDetail from '../CaseDetail.svelte';
|
|
8
|
-
const caseView = {
|
|
9
|
-
id: 'case-1',
|
|
10
|
-
caseNumber: 'SUP-9',
|
|
11
|
-
subject: 'Checkout errors under load',
|
|
12
|
-
status: 'escalated',
|
|
13
|
-
priority: 'urgent',
|
|
14
|
-
severity: 'sev1',
|
|
15
|
-
channelKind: 'email',
|
|
16
|
-
clientProfileId: 'client-1',
|
|
17
|
-
projectId: 'shop-rebuild',
|
|
18
|
-
assignedSpecialistId: 'spec-2',
|
|
19
|
-
assignedSpecialistName: 'Grace',
|
|
20
|
-
reopenCount: 1,
|
|
21
|
-
createdAt: '2026-07-01T09:00:00.000Z',
|
|
22
|
-
updatedAt: '2026-07-03T16:00:00.000Z',
|
|
23
|
-
resolutionSummary: '',
|
|
24
|
-
};
|
|
25
|
-
const timeline = [
|
|
26
|
-
{
|
|
27
|
-
kind: 'interaction',
|
|
28
|
-
occurredAt: '2026-07-01T09:00:00.000Z',
|
|
29
|
-
actorKind: 'client',
|
|
30
|
-
summary: 'inbound email',
|
|
31
|
-
body: 'Checkout is failing for many users.',
|
|
32
|
-
direction: 'inbound',
|
|
33
|
-
channelKind: 'email',
|
|
34
|
-
eventType: null,
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
kind: 'event',
|
|
38
|
-
occurredAt: '2026-07-01T09:05:00.000Z',
|
|
39
|
-
actorKind: 'system',
|
|
40
|
-
summary: 'Status new → triaged',
|
|
41
|
-
body: '',
|
|
42
|
-
direction: null,
|
|
43
|
-
channelKind: null,
|
|
44
|
-
eventType: 'transition',
|
|
45
|
-
},
|
|
46
|
-
];
|
|
47
|
-
const workLinks = [
|
|
48
|
-
{
|
|
49
|
-
id: 'link-1',
|
|
50
|
-
linkKind: 'development_work_item',
|
|
51
|
-
targetLabel: 'shop#101: fix checkout race',
|
|
52
|
-
externalUrl: 'https://github.com/acme/shop/issues/101',
|
|
53
|
-
status: 'in_progress',
|
|
54
|
-
},
|
|
55
|
-
];
|
|
56
|
-
describe('CaseDetail', () => {
|
|
57
|
-
it('renders header, meta, linked work, and the merged timeline', async () => {
|
|
58
|
-
const { container } = render(CaseDetail, {
|
|
59
|
-
props: { caseView, timeline, workLinks },
|
|
60
|
-
});
|
|
61
|
-
expect(screen.getByText('SUP-9')).toBeInTheDocument();
|
|
62
|
-
expect(screen.getByText('Checkout errors under load')).toBeInTheDocument();
|
|
63
|
-
expect(screen.getByText('escalated')).toBeInTheDocument();
|
|
64
|
-
expect(screen.getByText('reopened ×1')).toBeInTheDocument();
|
|
65
|
-
expect(screen.getByText('Grace')).toBeInTheDocument();
|
|
66
|
-
expect(screen.getByText('shop-rebuild')).toBeInTheDocument();
|
|
67
|
-
expect(screen.getByRole('link', { name: 'shop#101: fix checkout race' })).toHaveAttribute('href', 'https://github.com/acme/shop/issues/101');
|
|
68
|
-
expect(screen.getByText('Checkout is failing for many users.')).toBeInTheDocument();
|
|
69
|
-
expect(screen.getByText('Status new → triaged')).toBeInTheDocument();
|
|
70
|
-
await expectNoA11yViolations(container);
|
|
71
|
-
});
|
|
72
|
-
it('shows the empty history state and resolution when present', () => {
|
|
73
|
-
render(CaseDetail, {
|
|
74
|
-
props: {
|
|
75
|
-
caseView: {
|
|
76
|
-
...caseView,
|
|
77
|
-
status: 'resolved',
|
|
78
|
-
resolutionSummary: 'Scaled the checkout workers.',
|
|
79
|
-
},
|
|
80
|
-
timeline: [],
|
|
81
|
-
},
|
|
82
|
-
});
|
|
83
|
-
expect(screen.getByText('No activity yet')).toBeInTheDocument();
|
|
84
|
-
expect(screen.getByText('Scaled the checkout workers.')).toBeInTheDocument();
|
|
85
|
-
});
|
|
86
|
-
});
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
/**
|
|
3
|
-
* Component coverage for CaseQueue via the shared S11 harness (#1416).
|
|
4
|
-
*/
|
|
5
|
-
import { expectNoA11yViolations, render, screen, userEvent, } from '@happyvertical/smrt-vitest/svelte';
|
|
6
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
7
|
-
import CaseQueue from '../CaseQueue.svelte';
|
|
8
|
-
function caseView(overrides = {}) {
|
|
9
|
-
return {
|
|
10
|
-
id: 'case-1',
|
|
11
|
-
caseNumber: 'SUP-1',
|
|
12
|
-
subject: 'Login is broken',
|
|
13
|
-
status: 'in_progress',
|
|
14
|
-
priority: 'high',
|
|
15
|
-
severity: 'sev2',
|
|
16
|
-
channelKind: 'chat',
|
|
17
|
-
clientProfileId: 'client-1',
|
|
18
|
-
projectId: 'project-1',
|
|
19
|
-
assignedSpecialistId: 'spec-1',
|
|
20
|
-
assignedSpecialistName: 'Ada',
|
|
21
|
-
reopenCount: 0,
|
|
22
|
-
createdAt: '2026-07-01T10:00:00.000Z',
|
|
23
|
-
updatedAt: '2026-07-02T11:30:00.000Z',
|
|
24
|
-
resolutionSummary: '',
|
|
25
|
-
...overrides,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
describe('CaseQueue', () => {
|
|
29
|
-
it('renders case number, subject, badges, and assignee', async () => {
|
|
30
|
-
const { container } = render(CaseQueue, {
|
|
31
|
-
props: { cases: [caseView()] },
|
|
32
|
-
});
|
|
33
|
-
expect(screen.getByText('SUP-1')).toBeInTheDocument();
|
|
34
|
-
expect(screen.getByText('Login is broken')).toBeInTheDocument();
|
|
35
|
-
expect(screen.getByText('high')).toBeInTheDocument();
|
|
36
|
-
expect(screen.getByText('in progress')).toBeInTheDocument();
|
|
37
|
-
expect(screen.getByText('Ada')).toBeInTheDocument();
|
|
38
|
-
await expectNoA11yViolations(container);
|
|
39
|
-
});
|
|
40
|
-
it('invokes onselect with the case id', async () => {
|
|
41
|
-
const onselect = vi.fn();
|
|
42
|
-
render(CaseQueue, { props: { cases: [caseView()], onselect } });
|
|
43
|
-
await userEvent.click(screen.getByRole('button', {
|
|
44
|
-
name: 'Open case SUP-1: Login is broken',
|
|
45
|
-
}));
|
|
46
|
-
expect(onselect).toHaveBeenCalledWith('case-1');
|
|
47
|
-
});
|
|
48
|
-
it('shows the empty message when there are no cases', () => {
|
|
49
|
-
render(CaseQueue, {
|
|
50
|
-
props: { cases: [], emptyMessage: 'Queue is clear' },
|
|
51
|
-
});
|
|
52
|
-
expect(screen.getByText('Queue is clear')).toBeInTheDocument();
|
|
53
|
-
});
|
|
54
|
-
it('falls back to unassigned when no specialist is set', () => {
|
|
55
|
-
render(CaseQueue, {
|
|
56
|
-
props: {
|
|
57
|
-
cases: [
|
|
58
|
-
caseView({
|
|
59
|
-
assignedSpecialistId: null,
|
|
60
|
-
assignedSpecialistName: null,
|
|
61
|
-
}),
|
|
62
|
-
],
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
expect(screen.getByText('unassigned')).toBeInTheDocument();
|
|
66
|
-
});
|
|
67
|
-
});
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
/**
|
|
3
|
-
* Component coverage for RoutingRationale via the shared S11 harness (#1416).
|
|
4
|
-
*/
|
|
5
|
-
import { expectNoA11yViolations, render, screen, userEvent, } from '@happyvertical/smrt-vitest/svelte';
|
|
6
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
7
|
-
import RoutingRationale from '../RoutingRationale.svelte';
|
|
8
|
-
function rankedView(overrides = {}) {
|
|
9
|
-
return {
|
|
10
|
-
specialistId: 'spec-1',
|
|
11
|
-
displayName: 'Ada Lovelace',
|
|
12
|
-
score: 45,
|
|
13
|
-
eligible: true,
|
|
14
|
-
factors: {
|
|
15
|
-
status: 'active',
|
|
16
|
-
projectQualification: 'expert',
|
|
17
|
-
weeklyAvailable: true,
|
|
18
|
-
openCases: 2,
|
|
19
|
-
},
|
|
20
|
-
...overrides,
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
describe('RoutingRationale', () => {
|
|
24
|
-
it('renders name, score, eligibility, and factor chips', async () => {
|
|
25
|
-
const { container } = render(RoutingRationale, {
|
|
26
|
-
props: {
|
|
27
|
-
ranking: [
|
|
28
|
-
rankedView(),
|
|
29
|
-
rankedView({
|
|
30
|
-
specialistId: 'spec-2',
|
|
31
|
-
displayName: 'Grace Hopper',
|
|
32
|
-
score: 0,
|
|
33
|
-
eligible: false,
|
|
34
|
-
factors: { status: 'active', projectQualification: 'none' },
|
|
35
|
-
}),
|
|
36
|
-
],
|
|
37
|
-
},
|
|
38
|
-
});
|
|
39
|
-
expect(screen.getByText('Ada Lovelace')).toBeInTheDocument();
|
|
40
|
-
expect(screen.getByText('score 45')).toBeInTheDocument();
|
|
41
|
-
expect(screen.getByText('eligible')).toBeInTheDocument();
|
|
42
|
-
expect(screen.getByText('ineligible')).toBeInTheDocument();
|
|
43
|
-
// Boolean-true factors render as bare chips; others as key: value.
|
|
44
|
-
expect(screen.getByText('weeklyAvailable')).toBeInTheDocument();
|
|
45
|
-
expect(screen.getByText('projectQualification: expert')).toBeInTheDocument();
|
|
46
|
-
expect(screen.getByText('projectQualification: none')).toBeInTheDocument();
|
|
47
|
-
expect(screen.getByText('openCases: 2')).toBeInTheDocument();
|
|
48
|
-
await expectNoA11yViolations(container);
|
|
49
|
-
});
|
|
50
|
-
it('fires onreassign with the specialist id', async () => {
|
|
51
|
-
const onreassign = vi.fn();
|
|
52
|
-
const { container } = render(RoutingRationale, {
|
|
53
|
-
props: { ranking: [rankedView()], onreassign },
|
|
54
|
-
});
|
|
55
|
-
await userEvent.click(screen.getByRole('button', { name: 'Reassign to Ada Lovelace' }));
|
|
56
|
-
expect(onreassign).toHaveBeenCalledWith('spec-1');
|
|
57
|
-
await expectNoA11yViolations(container);
|
|
58
|
-
});
|
|
59
|
-
it('renders no reassign action without an onreassign handler', () => {
|
|
60
|
-
render(RoutingRationale, { props: { ranking: [rankedView()] } });
|
|
61
|
-
expect(screen.queryByRole('button')).not.toBeInTheDocument();
|
|
62
|
-
});
|
|
63
|
-
it('shows the empty message for an empty ranking', () => {
|
|
64
|
-
render(RoutingRationale, {
|
|
65
|
-
props: { ranking: [], emptyMessage: 'Nobody to rank' },
|
|
66
|
-
});
|
|
67
|
-
expect(screen.getByText('Nobody to rank')).toBeInTheDocument();
|
|
68
|
-
});
|
|
69
|
-
});
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
/**
|
|
3
|
-
* Component coverage for TargetList via the shared S11 harness (#1416).
|
|
4
|
-
*/
|
|
5
|
-
import { expectNoA11yViolations, render, screen, } from '@happyvertical/smrt-vitest/svelte';
|
|
6
|
-
import { describe, expect, it } from 'vitest';
|
|
7
|
-
import TargetList from '../TargetList.svelte';
|
|
8
|
-
function targetView(overrides = {}) {
|
|
9
|
-
return {
|
|
10
|
-
id: 'target-1',
|
|
11
|
-
targetType: 'acknowledgement',
|
|
12
|
-
cycle: 0,
|
|
13
|
-
status: 'pending',
|
|
14
|
-
severity: 'sev2',
|
|
15
|
-
baseMinutes: 30,
|
|
16
|
-
startedAt: '2026-01-05T10:00:00.000Z',
|
|
17
|
-
dueAt: '2026-01-05T10:30:00.000Z',
|
|
18
|
-
satisfiedAt: null,
|
|
19
|
-
breachedAt: null,
|
|
20
|
-
paused: false,
|
|
21
|
-
...overrides,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
describe('TargetList', () => {
|
|
25
|
-
it('renders target type, due time, and status badge', async () => {
|
|
26
|
-
const { container } = render(TargetList, {
|
|
27
|
-
props: {
|
|
28
|
-
targets: [
|
|
29
|
-
targetView(),
|
|
30
|
-
targetView({
|
|
31
|
-
id: 'target-2',
|
|
32
|
-
targetType: 'resolution',
|
|
33
|
-
status: 'satisfied',
|
|
34
|
-
satisfiedAt: '2026-01-05T11:00:00.000Z',
|
|
35
|
-
}),
|
|
36
|
-
],
|
|
37
|
-
},
|
|
38
|
-
});
|
|
39
|
-
expect(screen.getByText('acknowledgement')).toBeInTheDocument();
|
|
40
|
-
expect(screen.getByText('resolution')).toBeInTheDocument();
|
|
41
|
-
expect(screen.getAllByText(/due /)).toHaveLength(2);
|
|
42
|
-
expect(screen.getByText('pending')).toBeInTheDocument();
|
|
43
|
-
expect(screen.getByText('satisfied')).toBeInTheDocument();
|
|
44
|
-
await expectNoA11yViolations(container);
|
|
45
|
-
});
|
|
46
|
-
it('shows the paused indicator and the recurrence cycle', async () => {
|
|
47
|
-
const { container } = render(TargetList, {
|
|
48
|
-
props: {
|
|
49
|
-
targets: [
|
|
50
|
-
targetView({
|
|
51
|
-
id: 'target-3',
|
|
52
|
-
targetType: 'update',
|
|
53
|
-
status: 'paused',
|
|
54
|
-
paused: true,
|
|
55
|
-
cycle: 2,
|
|
56
|
-
}),
|
|
57
|
-
],
|
|
58
|
-
},
|
|
59
|
-
});
|
|
60
|
-
expect(screen.getByText('paused', { selector: '.target-list-paused' })).toBeInTheDocument();
|
|
61
|
-
expect(screen.getByText('cycle 2')).toBeInTheDocument();
|
|
62
|
-
await expectNoA11yViolations(container);
|
|
63
|
-
});
|
|
64
|
-
it('renders a breached clock with the error badge label', () => {
|
|
65
|
-
render(TargetList, {
|
|
66
|
-
props: {
|
|
67
|
-
targets: [
|
|
68
|
-
targetView({
|
|
69
|
-
id: 'target-4',
|
|
70
|
-
status: 'breached',
|
|
71
|
-
breachedAt: '2026-01-05T11:00:00.000Z',
|
|
72
|
-
}),
|
|
73
|
-
],
|
|
74
|
-
},
|
|
75
|
-
});
|
|
76
|
-
expect(screen.getByText('breached')).toBeInTheDocument();
|
|
77
|
-
});
|
|
78
|
-
it('shows the empty message when there are no targets', () => {
|
|
79
|
-
render(TargetList, {
|
|
80
|
-
props: { targets: [], emptyMessage: 'No clocks running' },
|
|
81
|
-
});
|
|
82
|
-
expect(screen.getByText('No clocks running')).toBeInTheDocument();
|
|
83
|
-
});
|
|
84
|
-
});
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
/**
|
|
3
|
-
* #3288: `TimeEntryApprovalQueue` moved to smrt-timesheets and stays
|
|
4
|
-
* importable from `@happyvertical/smrt-support/svelte`; support's time-entry
|
|
5
|
-
* view still adapts a support entry for it.
|
|
6
|
-
*/
|
|
7
|
-
import * as timesheets from '@happyvertical/smrt-timesheets/svelte';
|
|
8
|
-
import { describe, expect, it } from 'vitest';
|
|
9
|
-
import * as support from '../../index.js';
|
|
10
|
-
describe('smrt-support/svelte time-entry re-exports', () => {
|
|
11
|
-
it('re-exports the approval queue and its status badge mapping', () => {
|
|
12
|
-
expect(support.TimeEntryApprovalQueue).toBe(timesheets.TimeEntryApprovalQueue);
|
|
13
|
-
expect(support.timeEntryStatusBadgeKey).toBe(timesheets.timeEntryStatusBadgeKey);
|
|
14
|
-
expect(support.timeEntryStatusBadgeKey('corrected')).toBe('warning');
|
|
15
|
-
});
|
|
16
|
-
});
|