@spektra-cloudevents/application-copilot-widget 1.2.0 → 2.0.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 +126 -75
- package/dist/index.cjs +400 -63
- package/dist/index.d.cts +64 -8
- package/dist/index.d.ts +64 -8
- package/dist/index.js +400 -63
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,75 +1,126 @@
|
|
|
1
|
-
# @spektra/application-copilot-widget
|
|
2
|
-
|
|
3
|
-
A framework-agnostic, **CSS-library agnostic** copilot widget. It renders entirely
|
|
4
|
-
inside a **Shadow DOM**, so the host app's styles (Bootstrap, Angular Material,
|
|
5
|
-
Tailwind, etc.) cannot affect the widget and the widget's styles cannot leak out.
|
|
6
|
-
It works in Angular, React, Vue, or plain HTML.
|
|
7
|
-
|
|
8
|
-
##
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
ApplicationCopilotWidget.init(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
1
|
+
# @spektra-cloudevents/application-copilot-widget
|
|
2
|
+
|
|
3
|
+
A framework-agnostic, **CSS-library agnostic** copilot widget. It renders entirely
|
|
4
|
+
inside a **Shadow DOM**, so the host app's styles (Bootstrap, Angular Material,
|
|
5
|
+
Tailwind, etc.) cannot affect the widget and the widget's styles cannot leak out.
|
|
6
|
+
It works in Angular, React, Vue, or plain HTML.
|
|
7
|
+
|
|
8
|
+
## Breaking changes in 2.0.0
|
|
9
|
+
|
|
10
|
+
- The `environment` field was removed from `WidgetConfig` and `ApplicationContext`, and the
|
|
11
|
+
exported `Environment` type was removed. The Copilot API no longer uses an environment
|
|
12
|
+
parameter; each deployment has its own configuration.
|
|
13
|
+
- Migration: delete `environment` from the `init()` config and from the object returned by
|
|
14
|
+
`getContext()`, remove `devUserEmail`, and provide `getAuthToken` (see below).
|
|
15
|
+
- `devUserEmail` was removed and `getAuthToken` is now **required**: the Copilot API identifies the user only by
|
|
16
|
+
the validated bearer token (no `X-User-Email` header). The same token is used for the SignalR hub.
|
|
17
|
+
- Sessions are opened for `tenantUniqueName` and bound to the signed-in user; the API verifies tenant membership,
|
|
18
|
+
Copilot enablement and role on every request.
|
|
19
|
+
- Requires the Copilot API from Story 9453 B2 (token validation). Release the API before hosts upgrade to 2.x.
|
|
20
|
+
|
|
21
|
+
## Additions in 2.0.0 (Story 9453 B4, all optional / backwards compatible)
|
|
22
|
+
|
|
23
|
+
- **Knowledge-base references**: `CopilotAnswer.references: { title, url }[]` are shown under the answer as links.
|
|
24
|
+
Only absolute `https:` URLs are rendered (others are dropped); links are built with DOM APIs and open with
|
|
25
|
+
`target="_blank" rel="noopener noreferrer"`. Answer text is escaped and keeps line breaks (`white-space: pre-wrap`).
|
|
26
|
+
- **Support-ticket offer**: when an answer has `supportTicketEligible: true` the widget shows `supportTicketPrompt`
|
|
27
|
+
and a "Raise a support ticket" action. Accepting fetches the server draft
|
|
28
|
+
(`GET /api/sessions/{id}/support-ticket/draft?requestId=`), shows an editable subject/description, and Send posts
|
|
29
|
+
`POST /api/sessions/{id}/support-ticket`; the response `message` is shown as confirmation. If the draft endpoint
|
|
30
|
+
is unavailable the widget falls back to a locally built draft. Older servers that do not send
|
|
31
|
+
`supportTicketEligible` keep the previous client-side heuristic.
|
|
32
|
+
- **"This didn't help"**: shown under answers; resends the last question with `notHelpful: true`.
|
|
33
|
+
- **Sessions**: new `resetSession()`. The widget also resets automatically when `init()` is called with a different
|
|
34
|
+
`tenantUniqueName`, when the configured tenant or the signed-in user (read from the token's `oid`/`sub`/email claim
|
|
35
|
+
for change detection only — never trusted) differs from the one the session was opened for, and when the API
|
|
36
|
+
answers **403 or 404** for a session-scoped call. A reset clears the conversation.
|
|
37
|
+
- **`onOpenSupport?: () => void`**: when set, an "Open support" action appears with the ticket offer and confirmation.
|
|
38
|
+
The widget closes its panel first (synchronously) and then calls the callback, so the host can open its own
|
|
39
|
+
support UI (e.g. Zoho ASAP for the current tenant). `onOpenTicket` also closes the panel before it is called.
|
|
40
|
+
- **Responsive**: below 480px the panel is full width; it is never taller than `calc(100vh - 32px)`; long text wraps
|
|
41
|
+
so there is no horizontal scroll at 375 / 768 / 1440px.
|
|
42
|
+
- **`showKnowledgeUpload?: boolean`** (default `false`): the "Add to knowledge base" button in the panel header is
|
|
43
|
+
hidden unless the host sets this, e.g. only for users who may manage the knowledge base (CloudEvents Admin: System
|
|
44
|
+
Admin and Partner Admin). Re-applied on every `init()`. UI only: the Copilot API authorizes every upload.
|
|
45
|
+
**Behaviour change:** `promptUpload()` only opens the file picker when `showKnowledgeUpload` is true; otherwise it
|
|
46
|
+
just opens the panel.
|
|
47
|
+
- New exported types: `CopilotReference`, `SupportTicketDraft`, `SupportTicketResult`.
|
|
48
|
+
|
|
49
|
+
## Build
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm install
|
|
53
|
+
npm run build # outputs dist/ (ESM + CJS + types) via tsup
|
|
54
|
+
npx tsc --noEmit # type-check only
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Use (Angular example)
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { ApplicationCopilotWidget } from '@spektra-cloudevents/application-copilot-widget';
|
|
61
|
+
|
|
62
|
+
ApplicationCopilotWidget.init({
|
|
63
|
+
projectKey: 'cloud-events',
|
|
64
|
+
apiBaseUrl: copilotApiUrl,
|
|
65
|
+
signalRHubUrl: `${copilotApiUrl}/hubs/application-copilot`,
|
|
66
|
+
tenantUniqueName: this.tenantUniqueName,
|
|
67
|
+
getAuthToken: () => this.currentBearerToken(), // required: sent as Authorization: Bearer (and to SignalR)
|
|
68
|
+
|
|
69
|
+
getContext: () => ({
|
|
70
|
+
projectKey: 'cloud-events',
|
|
71
|
+
page: { pageKey: 'create-update-event', activeTab: this.activeTab, componentHint: 'ScheduleComponent' },
|
|
72
|
+
entities: { eventRequestId: this.eventRequestId },
|
|
73
|
+
uiState: {
|
|
74
|
+
disabledFields: [
|
|
75
|
+
...(this.scheduleForm.get('startDateTime')?.disabled ? ['eventStartDate'] : []),
|
|
76
|
+
...(this.scheduleForm.get('endDateTime')?.disabled ? ['eventEndDate'] : [])
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
// Hints only. The backend re-verifies anything security-relevant (role, visibility).
|
|
80
|
+
clientSnapshot: {
|
|
81
|
+
sectionMode: this.sectionMode,
|
|
82
|
+
isBudgetStatusClosed: this.isBudgetStatusClosed
|
|
83
|
+
},
|
|
84
|
+
contextVersion: this.contextVersion,
|
|
85
|
+
capturedAt: new Date().toISOString()
|
|
86
|
+
}),
|
|
87
|
+
|
|
88
|
+
// Optional host hooks
|
|
89
|
+
onNavigate: (path) => this.router.navigateByUrl(path),
|
|
90
|
+
onOpenTicket: (ticket) => this.openSupportTicket(ticket),
|
|
91
|
+
onOpenSupport: () => this.supportWidget.open(), // widget closes its panel before calling this
|
|
92
|
+
showKnowledgeUpload: this.canManageKnowledgeBase // optional, default false: KB upload button only for KB admins
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// On tenant switch / sign-out:
|
|
96
|
+
ApplicationCopilotWidget.resetSession();
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Public API
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
ApplicationCopilotWidget.init(config); // mount once with a WidgetConfig
|
|
103
|
+
ApplicationCopilotWidget.open();
|
|
104
|
+
ApplicationCopilotWidget.close();
|
|
105
|
+
ApplicationCopilotWidget.show(); // show the launcher (e.g. after login / tenant check)
|
|
106
|
+
ApplicationCopilotWidget.hide(); // hide launcher and panel
|
|
107
|
+
ApplicationCopilotWidget.ask('Why are the dates disabled?');
|
|
108
|
+
ApplicationCopilotWidget.setContext(context);
|
|
109
|
+
ApplicationCopilotWidget.captureError(errorContext);
|
|
110
|
+
ApplicationCopilotWidget.notify(text, suggestion?); // show a proactive message, optional suggested question
|
|
111
|
+
ApplicationCopilotWidget.promptUpload(); // open the KB upload picker (only with showKnowledgeUpload; server enforces admin rights)
|
|
112
|
+
ApplicationCopilotWidget.resetSession(); // drop the session + conversation; next question opens a new session
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Backend endpoints used
|
|
116
|
+
|
|
117
|
+
`POST /api/sessions`, `POST /api/sessions/{id}/messages` (optional `notHelpful: true`), `POST /api/sessions/{id}/intake/ask`,
|
|
118
|
+
`GET /api/sessions/{id}/support-ticket/draft?requestId=`, `POST /api/sessions/{id}/support-ticket`,
|
|
119
|
+
`POST /api/knowledge/upload`, and the optional SignalR hub.
|
|
120
|
+
|
|
121
|
+
## Why Shadow DOM
|
|
122
|
+
|
|
123
|
+
The widget mounts a single host element and attaches `attachShadow({ mode: 'open' })`.
|
|
124
|
+
All markup and CSS live inside that shadow root, and `:host { all: initial }` neutralises
|
|
125
|
+
inherited styles. The result: pixel-identical rendering regardless of the host's CSS
|
|
126
|
+
framework, with zero risk of class-name collisions in either direction.
|