spaps-issue-reporting-react 0.4.1 → 0.5.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/CHANGELOG.md +6 -0
- package/README.md +59 -2
- package/dist/index.d.mts +71 -3
- package/dist/index.d.ts +71 -3
- package/dist/index.js +360 -15
- package/dist/index.mjs +355 -15
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.4.2] - 2026-06-04
|
|
6
|
+
|
|
7
|
+
- Added the reporter-visible operator-to-reporter conversation thread (`IssueReportMessageThread`), rendered inside the issue detail modal when the client implements `issueReporting.listMessages`/`submitMessage`. It shows only `active`, reporter-visible projection rows (retracted/superseded/non-visible excluded), distinguishes operator vs reporter authorship and message kind, exposes a `needs_response` affordance plus a floating-entrypoint badge, and includes a clarification-response composer that submits with a client-generated `idempotency_key` and handles `409 ISSUE_REPORT_MESSAGE_CONFLICT`.
|
|
8
|
+
|
|
9
|
+
## [0.4.1] - 2026-05-16
|
|
10
|
+
|
|
5
11
|
- Added optional screenshot attachment UI that uploads private PNG/JPEG/WebP evidence through `issueReporting.uploadAttachment`, validates size/count locally, and submits only backend attachment IDs.
|
|
6
12
|
|
|
7
13
|
## [0.4.0] - 2026-05-11
|
package/README.md
CHANGED
|
@@ -73,6 +73,11 @@ export function AppShell() {
|
|
|
73
73
|
- A client with `issueReporting.getStatus`, `list`, `get`, `create`, `update`, and `reply`.
|
|
74
74
|
- A client with `issueReporting.createVoiceToken` when `inputModes` includes `voice`.
|
|
75
75
|
- A client with `issueReporting.uploadAttachment(file, { filename })` when you want screenshot uploads.
|
|
76
|
+
- Optionally, a client with `issueReporting.listMessages(issueReportId)` and
|
|
77
|
+
`issueReporting.submitMessage(issueReportId, { body, idempotency_key })` to wire the
|
|
78
|
+
operator-to-reporter message thread (and its `needs_response` badge). When these are present,
|
|
79
|
+
the bundled `IssueReportMessageThread` renders the conversation inside the issue detail modal
|
|
80
|
+
(see [Conversation Thread](#conversation-thread)).
|
|
76
81
|
- Any auth and token refresh behavior needed by that client.
|
|
77
82
|
- Eligibility rules such as feature flags, account state, or role checks.
|
|
78
83
|
- The current principal ID and optional role hint passed into the provider.
|
|
@@ -148,18 +153,57 @@ The picker accepts PNG, JPEG, and WebP files, enforces the 10 MiB per-file limit
|
|
|
148
153
|
|
|
149
154
|
This package does not store screenshots, generate public URLs, or redact image content. SPAPS stores screenshots through its shared hosted-asset boundary as private objects, and access URLs are minted by the backend after authorization. Host apps should warn users before upload when a screenshot might include PHI, credentials, payment data, or other sensitive content.
|
|
150
155
|
|
|
156
|
+
## Conversation Thread
|
|
157
|
+
|
|
158
|
+
Support operators can ask a reporter for clarification and post a final resolution message. Those messages flow into an allowlisted, reporter-visible projection that the reporter reads back as a conversation. This package renders that surface when the client implements the two optional message methods:
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
const client = {
|
|
162
|
+
issueReporting: {
|
|
163
|
+
...spaps.issueReporting,
|
|
164
|
+
listMessages: (issueReportId: string) =>
|
|
165
|
+
spaps.issueReporting.listMessages(issueReportId),
|
|
166
|
+
submitMessage: (issueReportId, payload) =>
|
|
167
|
+
spaps.issueReporting.submitMessage(issueReportId, payload),
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
When `listMessages` is present, `FloatingIssueReportButton` mounts the exported `IssueReportMessageThread` inside the issue detail modal (the Edit/Reply views). The thread:
|
|
173
|
+
|
|
174
|
+
- Renders only `active`, `reporter_visible` projection rows in chronological order. Retracted and superseded operator messages, non-visible rows, and raw `support_case_events` payloads are never displayed. The backend filters this; `selectReporterVisibleMessages` re-asserts the same rule in the UI.
|
|
175
|
+
- Distinguishes operator (`Support`) vs reporter (`You`) authorship, labels each message kind (`clarification_request`, `reporter_response`, `final_response`), and shows a relative timestamp.
|
|
176
|
+
- Shows a **needs-response** affordance when the API's `needs_response` flag is set (an open clarification request awaiting an answer), and surfaces a matching dot badge on the floating entrypoint while that thread is open.
|
|
177
|
+
- Renders a reporter clarification-response composer (shown only when the client implements `submitMessage`). It calls `submitMessage(issueReportId, { body, idempotency_key })` with a client-generated `idempotency_key`. A key reused with a different body returns `409 ISSUE_REPORT_MESSAGE_CONFLICT`; the composer detects this (`isReporterMessageConflict`), shows the conflict copy, and rotates the key for retry.
|
|
178
|
+
- Exposes loading, empty, and error (with retry) states.
|
|
179
|
+
|
|
180
|
+
The composer does not reopen a closed case; reopen semantics stay with the Reply flow. You can also mount `IssueReportMessageThread` directly (outside the modal) inside your own issue detail view:
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
import { IssueReportMessageThread } from "spaps-issue-reporting-react";
|
|
184
|
+
|
|
185
|
+
<IssueReportMessageThread issueReportId={issue.id} />;
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
All thread strings are overridable through the provider `copy` prop. The thread copy keys are: `threadTitle`, `threadDescription`, `threadLoading`, `threadLoadFailed`, `threadEmpty`, `threadNeedsResponseBadge`, `threadAuthorOperator`, `threadAuthorReporter`, `threadKindClarificationRequest`, `threadKindReporterResponse`, `threadKindFinalResponse`, `threadResponseLabel`, `threadResponsePlaceholder`, `threadResponseSubmitAction`, `threadResponseSubmittingAction`, `threadResponseConflict`, and `threadResponseFailed`.
|
|
189
|
+
|
|
151
190
|
## Exported Surface
|
|
152
191
|
|
|
153
192
|
| Export | Purpose |
|
|
154
193
|
| --- | --- |
|
|
155
194
|
| `IssueReportingProvider` | Owns queries, modal state, copy, scope, and report-mode behavior |
|
|
156
195
|
| `IssueReportingPageConfig` | Per-page override for `general_page`, `surface_required`, or `surface_preferred` create policy |
|
|
157
|
-
| `FloatingIssueReportButton` | Renders the floating entry point, popover, and
|
|
196
|
+
| `FloatingIssueReportButton` | Renders the floating entry point, popover, modal, and (when the client supports messages) the conversation thread |
|
|
197
|
+
| `IssueReportMessageThread` | Renders the reporter-visible operator-to-reporter conversation for one issue report, with a clarification-response composer |
|
|
158
198
|
| `ReportableSection` | Marks a region as selectable when report mode is active |
|
|
159
199
|
| `useIssueReporting` | Full provider state, including `startNewIssue()`, `openPageIssueModal()`, and `enterReportMode()` |
|
|
160
200
|
| `useIssueReportingStatus` | Query helper for summary state |
|
|
161
201
|
| `useIssueReportingHistory` | Query helper for filtered history lists |
|
|
162
202
|
| `useIssueReportingMutations` | Mutation helpers for create, update, and reply flows |
|
|
203
|
+
| `useIssueReportingMessages` | Query helper for one issue report's reporter-visible message thread |
|
|
204
|
+
| `useIssueReportingMessageMutation` | Mutation helper for submitting a reporter clarification response |
|
|
205
|
+
| `selectReporterVisibleMessages` | Filters a message list to `active`, reporter-visible rows in chronological order |
|
|
206
|
+
| `isReporterMessageConflict` | Detects a `409 ISSUE_REPORT_MESSAGE_CONFLICT` from the client transport |
|
|
163
207
|
| `useReportMode` | Low-level selection state for custom wrappers |
|
|
164
208
|
|
|
165
209
|
## Styling Notes
|
|
@@ -217,6 +261,10 @@ Confirm that the SPAPS server has `ELEVENLABS_API_KEY` set and that the current
|
|
|
217
261
|
|
|
218
262
|
Expose `issueReporting.uploadAttachment` on the client passed to `IssueReportingProvider`. The package intentionally hides the picker when the upload helper is absent.
|
|
219
263
|
|
|
264
|
+
### The conversation thread does not appear
|
|
265
|
+
|
|
266
|
+
Expose `issueReporting.listMessages` on the client passed to `IssueReportingProvider`, then open an existing issue's detail (Edit/Reply). The thread is intentionally hidden when the client cannot list messages. The response composer additionally requires `issueReporting.submitMessage`; without it the thread renders read-only.
|
|
267
|
+
|
|
220
268
|
## Limitations
|
|
221
269
|
|
|
222
270
|
- This package assumes React Query is already part of the host app.
|
|
@@ -253,10 +301,19 @@ No. It only renders scope choices that your app explicitly allows.
|
|
|
253
301
|
|
|
254
302
|
No. This package is UI only. If your browser app calls SPAPS directly with a publishable key, the relevant SPAPS application row must include that browser origin in `allowed_origins`.
|
|
255
303
|
|
|
304
|
+
## Design system
|
|
305
|
+
|
|
306
|
+
This package is intentionally theme-neutral and uses accessible Radix behavior
|
|
307
|
+
primitives plus a restrained slate palette so it blends into the host app. The
|
|
308
|
+
Design System Registry (DSR) adoption decision for this surface is an **explicit
|
|
309
|
+
deferral** because no suitable theme-neutral registry item exists yet. The
|
|
310
|
+
repository-level `docs/DSR-DECISION.md` captures the reasoning, file-level audit,
|
|
311
|
+
and revisit trigger.
|
|
312
|
+
|
|
256
313
|
## Metadata
|
|
257
314
|
|
|
258
315
|
- `package_name`: `spaps-issue-reporting-react`
|
|
259
|
-
- `latest_version`: `0.4.
|
|
316
|
+
- `latest_version`: `0.4.2`
|
|
260
317
|
- `minimum_runtime`: `Node.js >=18.0.0`
|
|
261
318
|
- `api_base_url`: `https://api.sweetpotato.dev`
|
|
262
319
|
|
package/dist/index.d.mts
CHANGED
|
@@ -2,8 +2,8 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import React__default, { ReactNode } from 'react';
|
|
4
4
|
import * as spaps_types from 'spaps-types';
|
|
5
|
-
import { IssueReportScope, IssueReportStatusResult, IssueReportStatus, IssueReportListResult, IssueReport, CreateIssueReportRequest, UpdateIssueReportRequest, ReplyIssueReportRequest, IssueReportingVoiceTokenResult, IssueReportAttachmentOut, IssueReportingInputMode, IssueReportingVoiceProvider } from 'spaps-types';
|
|
6
|
-
export { CreateIssueReportRequest, IssueReport, IssueReportAttachmentOut, IssueReportListResult, IssueReportScope, IssueReportStatus, IssueReportStatusResult, ReplyIssueReportRequest, UpdateIssueReportRequest } from 'spaps-types';
|
|
5
|
+
import { IssueReportScope, IssueReportStatusResult, IssueReportStatus, IssueReportListResult, IssueReport, CreateIssueReportRequest, UpdateIssueReportRequest, ReplyIssueReportRequest, IssueReportingVoiceTokenResult, IssueReportAttachmentOut, ListIssueReportMessagesResponse, CreateReporterMessageRequest, IssueReportMessage, IssueReportingInputMode, IssueReportingVoiceProvider } from 'spaps-types';
|
|
6
|
+
export { CreateIssueReportRequest, CreateReporterMessageRequest, IssueReport, IssueReportAttachmentOut, IssueReportListResult, IssueReportMessage, IssueReportScope, IssueReportStatus, IssueReportStatusResult, ListIssueReportMessagesResponse, ReplyIssueReportRequest, UpdateIssueReportRequest } from 'spaps-types';
|
|
7
7
|
import * as _tanstack_query_core from '@tanstack/query-core';
|
|
8
8
|
import * as _tanstack_react_query from '@tanstack/react-query';
|
|
9
9
|
|
|
@@ -39,6 +39,8 @@ interface IssueReportingClient {
|
|
|
39
39
|
uploadAttachment?: (file: Blob, options?: {
|
|
40
40
|
filename?: string;
|
|
41
41
|
}) => Promise<IssueReportAttachmentOut>;
|
|
42
|
+
listMessages?: (issueReportId: string) => Promise<ListIssueReportMessagesResponse>;
|
|
43
|
+
submitMessage?: (issueReportId: string, payload: CreateReporterMessageRequest) => Promise<IssueReportMessage>;
|
|
42
44
|
};
|
|
43
45
|
}
|
|
44
46
|
interface ReportableTargetDescriptor {
|
|
@@ -96,6 +98,23 @@ interface IssueReportingCopy {
|
|
|
96
98
|
originHumanLabel: string;
|
|
97
99
|
originMachineLabel: string;
|
|
98
100
|
machineOriginFallback: string;
|
|
101
|
+
threadTitle: string;
|
|
102
|
+
threadDescription: string;
|
|
103
|
+
threadLoading: string;
|
|
104
|
+
threadLoadFailed: string;
|
|
105
|
+
threadEmpty: string;
|
|
106
|
+
threadNeedsResponseBadge: string;
|
|
107
|
+
threadAuthorOperator: string;
|
|
108
|
+
threadAuthorReporter: string;
|
|
109
|
+
threadKindClarificationRequest: string;
|
|
110
|
+
threadKindReporterResponse: string;
|
|
111
|
+
threadKindFinalResponse: string;
|
|
112
|
+
threadResponsePlaceholder: string;
|
|
113
|
+
threadResponseLabel: string;
|
|
114
|
+
threadResponseSubmitAction: string;
|
|
115
|
+
threadResponseSubmittingAction: string;
|
|
116
|
+
threadResponseConflict: string;
|
|
117
|
+
threadResponseFailed: string;
|
|
99
118
|
}
|
|
100
119
|
interface IssueReportingProviderProps {
|
|
101
120
|
client: IssueReportingClient;
|
|
@@ -120,6 +139,9 @@ interface IssueReportingPageConfigProps {
|
|
|
120
139
|
createMode: IssueReportingCreateMode;
|
|
121
140
|
}
|
|
122
141
|
|
|
142
|
+
declare function IssueReportMessageThread({ issueReportId, }: {
|
|
143
|
+
issueReportId: string;
|
|
144
|
+
}): react_jsx_runtime.JSX.Element | null;
|
|
123
145
|
declare function FloatingIssueReportButton({ className, positionClassName, }: FloatingIssueReportButtonProps): react_jsx_runtime.JSX.Element | null;
|
|
124
146
|
declare function ReportableSection({ reportableName, children, className, as: Component, }: {
|
|
125
147
|
reportableName: ReportableInput;
|
|
@@ -174,6 +196,8 @@ type IssueReportingContextValue = {
|
|
|
174
196
|
voice: Required<Pick<IssueReportingVoiceConfig, "provider" | "modelId" | "requireMicrophonePermission">> & {
|
|
175
197
|
microphone?: IssueReportingVoiceConfig["microphone"];
|
|
176
198
|
};
|
|
199
|
+
needsResponseIssueIds: string[];
|
|
200
|
+
setNeedsResponse: (issueReportId: string, needsResponse: boolean) => void;
|
|
177
201
|
};
|
|
178
202
|
declare const defaultIssueReportingCopy: IssueReportingCopy;
|
|
179
203
|
declare const issueReportingKeys: {
|
|
@@ -181,6 +205,7 @@ declare const issueReportingKeys: {
|
|
|
181
205
|
status: (scope: IssueReportScope) => readonly ["spaps-issue-reporting", "status", IssueReportScope];
|
|
182
206
|
history: (scope: IssueReportScope) => readonly ["spaps-issue-reporting", "history", IssueReportScope];
|
|
183
207
|
detail: (issueReportId: string) => readonly ["spaps-issue-reporting", "detail", string];
|
|
208
|
+
messages: (issueReportId: string) => readonly ["spaps-issue-reporting", "messages", string];
|
|
184
209
|
};
|
|
185
210
|
declare function isOpenIssueStatus(status: IssueReportStatus): boolean;
|
|
186
211
|
declare function isClosedIssueStatus(status: IssueReportStatus): boolean;
|
|
@@ -192,6 +217,25 @@ declare function getEntryPointState(status?: {
|
|
|
192
217
|
has_recent_resolved: boolean;
|
|
193
218
|
} | null): "open" | "recent_resolved" | "neutral";
|
|
194
219
|
declare function getEntryPointClassName(state: "open" | "recent_resolved" | "neutral"): string;
|
|
220
|
+
/**
|
|
221
|
+
* Defensive reporter-visibility filter for the conversation surface.
|
|
222
|
+
*
|
|
223
|
+
* The reporter `GET /messages` endpoint already returns only `active`,
|
|
224
|
+
* reporter-visible projection rows (retracted/superseded operator messages and
|
|
225
|
+
* raw `support_case_events` payloads are excluded server-side). This filter
|
|
226
|
+
* re-asserts that contract in the UI so a non-allowlisted row can never be
|
|
227
|
+
* rendered to a reporter even if a client or fixture passes one through. Rows
|
|
228
|
+
* are returned in chronological (`created_at`) order.
|
|
229
|
+
*/
|
|
230
|
+
declare function selectReporterVisibleMessages(messages: IssueReportMessage[]): IssueReportMessage[];
|
|
231
|
+
/**
|
|
232
|
+
* Detect the idempotency-key conflict surfaced by the reporter message API as
|
|
233
|
+
* `409 ISSUE_REPORT_MESSAGE_CONFLICT`. The provider only depends on the
|
|
234
|
+
* abstract `IssueReportingClient` contract, so this inspects whatever shape the
|
|
235
|
+
* host client throws (Error message, `code`, or HTTP `status`) without binding
|
|
236
|
+
* to a specific transport.
|
|
237
|
+
*/
|
|
238
|
+
declare function isReporterMessageConflict(error: unknown): boolean;
|
|
195
239
|
declare function getIssueNoteLengthMessage(note: string, copy: IssueReportingCopy): string;
|
|
196
240
|
declare function useIssueReporting(): IssueReportingContextValue;
|
|
197
241
|
declare function IssueReportingPageConfig({ createMode, }: IssueReportingPageConfigProps): react_jsx_runtime.JSX.Element;
|
|
@@ -391,6 +435,30 @@ declare function useIssueReportingMutations(): {
|
|
|
391
435
|
attachment_ids?: string[];
|
|
392
436
|
}, unknown>;
|
|
393
437
|
};
|
|
438
|
+
/**
|
|
439
|
+
* Query helper for the reporter-visible message thread of one issue report.
|
|
440
|
+
*
|
|
441
|
+
* Keyed by `issue_report_id`. Enabled only when the caller is eligible, an
|
|
442
|
+
* issue id is provided, and the host client implements the optional
|
|
443
|
+
* `listMessages` contract method. The query returns the raw server response so
|
|
444
|
+
* consumers can read `needs_response` for the badge; rendering code should pass
|
|
445
|
+
* `data.items` through {@link selectReporterVisibleMessages} before display.
|
|
446
|
+
*/
|
|
447
|
+
declare function useIssueReportingMessages(issueReportId: string | null): _tanstack_react_query.UseQueryResult<ListIssueReportMessagesResponse, Error>;
|
|
448
|
+
/**
|
|
449
|
+
* Mutation helper for submitting a reporter clarification response.
|
|
450
|
+
*
|
|
451
|
+
* Calls the host client's `submitMessage(issueReportId, { body, idempotency_key })`
|
|
452
|
+
* and, on success, invalidates the thread query so the new `reporter_response`
|
|
453
|
+
* row and refreshed `needs_response` flag are re-fetched. The caller supplies a
|
|
454
|
+
* client-generated `idempotency_key` for safe retries; a key reused with a
|
|
455
|
+
* different body surfaces as a `409` conflict the UI can detect with
|
|
456
|
+
* {@link isReporterMessageConflict}.
|
|
457
|
+
*/
|
|
458
|
+
declare function useIssueReportingMessageMutation(issueReportId: string | null): _tanstack_react_query.UseMutationResult<IssueReportMessage, unknown, {
|
|
459
|
+
body: string;
|
|
460
|
+
idempotency_key?: string;
|
|
461
|
+
}, unknown>;
|
|
394
462
|
declare function IssueReportingProvider({ client, isEligible, reporterRoleHint, principalId, getPageUrl, defaultScope, allowTenantScope, defaultCreateMode, inputModes, defaultInputMode, voice, copy, children, }: IssueReportingProviderProps): react_jsx_runtime.JSX.Element;
|
|
395
463
|
|
|
396
464
|
interface ReportModeContextValue {
|
|
@@ -404,4 +472,4 @@ interface ReportModeContextValue {
|
|
|
404
472
|
declare const ReportModeContext: React.Context<ReportModeContextValue | null>;
|
|
405
473
|
declare function useReportMode(): ReportModeContextValue | null;
|
|
406
474
|
|
|
407
|
-
export { FloatingIssueReportButton, type FloatingIssueReportButtonProps, type IssueHistoryFilter, type IssueReportingClient, type IssueReportingCopy, type IssueReportingCreateMode, IssueReportingPageConfig, type IssueReportingPageConfigProps, IssueReportingProvider, type IssueReportingProviderProps, ReportModeContext, type ReportModeContextValue, type ReportableInput, ReportableSection, type ReportableTargetDescriptor, defaultIssueReportingCopy, filterIssueReports, getEntryPointClassName, getEntryPointState, getIssueNoteLengthMessage, getIssueStatusBadgeLabel, getIssueStatusClassName, isClosedIssueStatus, isOpenIssueStatus, issueReportingKeys, useIssueReporting, useIssueReportingHistory, useIssueReportingMutations, useIssueReportingStatus, useReportMode };
|
|
475
|
+
export { FloatingIssueReportButton, type FloatingIssueReportButtonProps, type IssueHistoryFilter, IssueReportMessageThread, type IssueReportingClient, type IssueReportingCopy, type IssueReportingCreateMode, IssueReportingPageConfig, type IssueReportingPageConfigProps, IssueReportingProvider, type IssueReportingProviderProps, ReportModeContext, type ReportModeContextValue, type ReportableInput, ReportableSection, type ReportableTargetDescriptor, defaultIssueReportingCopy, filterIssueReports, getEntryPointClassName, getEntryPointState, getIssueNoteLengthMessage, getIssueStatusBadgeLabel, getIssueStatusClassName, isClosedIssueStatus, isOpenIssueStatus, isReporterMessageConflict, issueReportingKeys, selectReporterVisibleMessages, useIssueReporting, useIssueReportingHistory, useIssueReportingMessageMutation, useIssueReportingMessages, useIssueReportingMutations, useIssueReportingStatus, useReportMode };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import React__default, { ReactNode } from 'react';
|
|
4
4
|
import * as spaps_types from 'spaps-types';
|
|
5
|
-
import { IssueReportScope, IssueReportStatusResult, IssueReportStatus, IssueReportListResult, IssueReport, CreateIssueReportRequest, UpdateIssueReportRequest, ReplyIssueReportRequest, IssueReportingVoiceTokenResult, IssueReportAttachmentOut, IssueReportingInputMode, IssueReportingVoiceProvider } from 'spaps-types';
|
|
6
|
-
export { CreateIssueReportRequest, IssueReport, IssueReportAttachmentOut, IssueReportListResult, IssueReportScope, IssueReportStatus, IssueReportStatusResult, ReplyIssueReportRequest, UpdateIssueReportRequest } from 'spaps-types';
|
|
5
|
+
import { IssueReportScope, IssueReportStatusResult, IssueReportStatus, IssueReportListResult, IssueReport, CreateIssueReportRequest, UpdateIssueReportRequest, ReplyIssueReportRequest, IssueReportingVoiceTokenResult, IssueReportAttachmentOut, ListIssueReportMessagesResponse, CreateReporterMessageRequest, IssueReportMessage, IssueReportingInputMode, IssueReportingVoiceProvider } from 'spaps-types';
|
|
6
|
+
export { CreateIssueReportRequest, CreateReporterMessageRequest, IssueReport, IssueReportAttachmentOut, IssueReportListResult, IssueReportMessage, IssueReportScope, IssueReportStatus, IssueReportStatusResult, ListIssueReportMessagesResponse, ReplyIssueReportRequest, UpdateIssueReportRequest } from 'spaps-types';
|
|
7
7
|
import * as _tanstack_query_core from '@tanstack/query-core';
|
|
8
8
|
import * as _tanstack_react_query from '@tanstack/react-query';
|
|
9
9
|
|
|
@@ -39,6 +39,8 @@ interface IssueReportingClient {
|
|
|
39
39
|
uploadAttachment?: (file: Blob, options?: {
|
|
40
40
|
filename?: string;
|
|
41
41
|
}) => Promise<IssueReportAttachmentOut>;
|
|
42
|
+
listMessages?: (issueReportId: string) => Promise<ListIssueReportMessagesResponse>;
|
|
43
|
+
submitMessage?: (issueReportId: string, payload: CreateReporterMessageRequest) => Promise<IssueReportMessage>;
|
|
42
44
|
};
|
|
43
45
|
}
|
|
44
46
|
interface ReportableTargetDescriptor {
|
|
@@ -96,6 +98,23 @@ interface IssueReportingCopy {
|
|
|
96
98
|
originHumanLabel: string;
|
|
97
99
|
originMachineLabel: string;
|
|
98
100
|
machineOriginFallback: string;
|
|
101
|
+
threadTitle: string;
|
|
102
|
+
threadDescription: string;
|
|
103
|
+
threadLoading: string;
|
|
104
|
+
threadLoadFailed: string;
|
|
105
|
+
threadEmpty: string;
|
|
106
|
+
threadNeedsResponseBadge: string;
|
|
107
|
+
threadAuthorOperator: string;
|
|
108
|
+
threadAuthorReporter: string;
|
|
109
|
+
threadKindClarificationRequest: string;
|
|
110
|
+
threadKindReporterResponse: string;
|
|
111
|
+
threadKindFinalResponse: string;
|
|
112
|
+
threadResponsePlaceholder: string;
|
|
113
|
+
threadResponseLabel: string;
|
|
114
|
+
threadResponseSubmitAction: string;
|
|
115
|
+
threadResponseSubmittingAction: string;
|
|
116
|
+
threadResponseConflict: string;
|
|
117
|
+
threadResponseFailed: string;
|
|
99
118
|
}
|
|
100
119
|
interface IssueReportingProviderProps {
|
|
101
120
|
client: IssueReportingClient;
|
|
@@ -120,6 +139,9 @@ interface IssueReportingPageConfigProps {
|
|
|
120
139
|
createMode: IssueReportingCreateMode;
|
|
121
140
|
}
|
|
122
141
|
|
|
142
|
+
declare function IssueReportMessageThread({ issueReportId, }: {
|
|
143
|
+
issueReportId: string;
|
|
144
|
+
}): react_jsx_runtime.JSX.Element | null;
|
|
123
145
|
declare function FloatingIssueReportButton({ className, positionClassName, }: FloatingIssueReportButtonProps): react_jsx_runtime.JSX.Element | null;
|
|
124
146
|
declare function ReportableSection({ reportableName, children, className, as: Component, }: {
|
|
125
147
|
reportableName: ReportableInput;
|
|
@@ -174,6 +196,8 @@ type IssueReportingContextValue = {
|
|
|
174
196
|
voice: Required<Pick<IssueReportingVoiceConfig, "provider" | "modelId" | "requireMicrophonePermission">> & {
|
|
175
197
|
microphone?: IssueReportingVoiceConfig["microphone"];
|
|
176
198
|
};
|
|
199
|
+
needsResponseIssueIds: string[];
|
|
200
|
+
setNeedsResponse: (issueReportId: string, needsResponse: boolean) => void;
|
|
177
201
|
};
|
|
178
202
|
declare const defaultIssueReportingCopy: IssueReportingCopy;
|
|
179
203
|
declare const issueReportingKeys: {
|
|
@@ -181,6 +205,7 @@ declare const issueReportingKeys: {
|
|
|
181
205
|
status: (scope: IssueReportScope) => readonly ["spaps-issue-reporting", "status", IssueReportScope];
|
|
182
206
|
history: (scope: IssueReportScope) => readonly ["spaps-issue-reporting", "history", IssueReportScope];
|
|
183
207
|
detail: (issueReportId: string) => readonly ["spaps-issue-reporting", "detail", string];
|
|
208
|
+
messages: (issueReportId: string) => readonly ["spaps-issue-reporting", "messages", string];
|
|
184
209
|
};
|
|
185
210
|
declare function isOpenIssueStatus(status: IssueReportStatus): boolean;
|
|
186
211
|
declare function isClosedIssueStatus(status: IssueReportStatus): boolean;
|
|
@@ -192,6 +217,25 @@ declare function getEntryPointState(status?: {
|
|
|
192
217
|
has_recent_resolved: boolean;
|
|
193
218
|
} | null): "open" | "recent_resolved" | "neutral";
|
|
194
219
|
declare function getEntryPointClassName(state: "open" | "recent_resolved" | "neutral"): string;
|
|
220
|
+
/**
|
|
221
|
+
* Defensive reporter-visibility filter for the conversation surface.
|
|
222
|
+
*
|
|
223
|
+
* The reporter `GET /messages` endpoint already returns only `active`,
|
|
224
|
+
* reporter-visible projection rows (retracted/superseded operator messages and
|
|
225
|
+
* raw `support_case_events` payloads are excluded server-side). This filter
|
|
226
|
+
* re-asserts that contract in the UI so a non-allowlisted row can never be
|
|
227
|
+
* rendered to a reporter even if a client or fixture passes one through. Rows
|
|
228
|
+
* are returned in chronological (`created_at`) order.
|
|
229
|
+
*/
|
|
230
|
+
declare function selectReporterVisibleMessages(messages: IssueReportMessage[]): IssueReportMessage[];
|
|
231
|
+
/**
|
|
232
|
+
* Detect the idempotency-key conflict surfaced by the reporter message API as
|
|
233
|
+
* `409 ISSUE_REPORT_MESSAGE_CONFLICT`. The provider only depends on the
|
|
234
|
+
* abstract `IssueReportingClient` contract, so this inspects whatever shape the
|
|
235
|
+
* host client throws (Error message, `code`, or HTTP `status`) without binding
|
|
236
|
+
* to a specific transport.
|
|
237
|
+
*/
|
|
238
|
+
declare function isReporterMessageConflict(error: unknown): boolean;
|
|
195
239
|
declare function getIssueNoteLengthMessage(note: string, copy: IssueReportingCopy): string;
|
|
196
240
|
declare function useIssueReporting(): IssueReportingContextValue;
|
|
197
241
|
declare function IssueReportingPageConfig({ createMode, }: IssueReportingPageConfigProps): react_jsx_runtime.JSX.Element;
|
|
@@ -391,6 +435,30 @@ declare function useIssueReportingMutations(): {
|
|
|
391
435
|
attachment_ids?: string[];
|
|
392
436
|
}, unknown>;
|
|
393
437
|
};
|
|
438
|
+
/**
|
|
439
|
+
* Query helper for the reporter-visible message thread of one issue report.
|
|
440
|
+
*
|
|
441
|
+
* Keyed by `issue_report_id`. Enabled only when the caller is eligible, an
|
|
442
|
+
* issue id is provided, and the host client implements the optional
|
|
443
|
+
* `listMessages` contract method. The query returns the raw server response so
|
|
444
|
+
* consumers can read `needs_response` for the badge; rendering code should pass
|
|
445
|
+
* `data.items` through {@link selectReporterVisibleMessages} before display.
|
|
446
|
+
*/
|
|
447
|
+
declare function useIssueReportingMessages(issueReportId: string | null): _tanstack_react_query.UseQueryResult<ListIssueReportMessagesResponse, Error>;
|
|
448
|
+
/**
|
|
449
|
+
* Mutation helper for submitting a reporter clarification response.
|
|
450
|
+
*
|
|
451
|
+
* Calls the host client's `submitMessage(issueReportId, { body, idempotency_key })`
|
|
452
|
+
* and, on success, invalidates the thread query so the new `reporter_response`
|
|
453
|
+
* row and refreshed `needs_response` flag are re-fetched. The caller supplies a
|
|
454
|
+
* client-generated `idempotency_key` for safe retries; a key reused with a
|
|
455
|
+
* different body surfaces as a `409` conflict the UI can detect with
|
|
456
|
+
* {@link isReporterMessageConflict}.
|
|
457
|
+
*/
|
|
458
|
+
declare function useIssueReportingMessageMutation(issueReportId: string | null): _tanstack_react_query.UseMutationResult<IssueReportMessage, unknown, {
|
|
459
|
+
body: string;
|
|
460
|
+
idempotency_key?: string;
|
|
461
|
+
}, unknown>;
|
|
394
462
|
declare function IssueReportingProvider({ client, isEligible, reporterRoleHint, principalId, getPageUrl, defaultScope, allowTenantScope, defaultCreateMode, inputModes, defaultInputMode, voice, copy, children, }: IssueReportingProviderProps): react_jsx_runtime.JSX.Element;
|
|
395
463
|
|
|
396
464
|
interface ReportModeContextValue {
|
|
@@ -404,4 +472,4 @@ interface ReportModeContextValue {
|
|
|
404
472
|
declare const ReportModeContext: React.Context<ReportModeContextValue | null>;
|
|
405
473
|
declare function useReportMode(): ReportModeContextValue | null;
|
|
406
474
|
|
|
407
|
-
export { FloatingIssueReportButton, type FloatingIssueReportButtonProps, type IssueHistoryFilter, type IssueReportingClient, type IssueReportingCopy, type IssueReportingCreateMode, IssueReportingPageConfig, type IssueReportingPageConfigProps, IssueReportingProvider, type IssueReportingProviderProps, ReportModeContext, type ReportModeContextValue, type ReportableInput, ReportableSection, type ReportableTargetDescriptor, defaultIssueReportingCopy, filterIssueReports, getEntryPointClassName, getEntryPointState, getIssueNoteLengthMessage, getIssueStatusBadgeLabel, getIssueStatusClassName, isClosedIssueStatus, isOpenIssueStatus, issueReportingKeys, useIssueReporting, useIssueReportingHistory, useIssueReportingMutations, useIssueReportingStatus, useReportMode };
|
|
475
|
+
export { FloatingIssueReportButton, type FloatingIssueReportButtonProps, type IssueHistoryFilter, IssueReportMessageThread, type IssueReportingClient, type IssueReportingCopy, type IssueReportingCreateMode, IssueReportingPageConfig, type IssueReportingPageConfigProps, IssueReportingProvider, type IssueReportingProviderProps, ReportModeContext, type ReportModeContextValue, type ReportableInput, ReportableSection, type ReportableTargetDescriptor, defaultIssueReportingCopy, filterIssueReports, getEntryPointClassName, getEntryPointState, getIssueNoteLengthMessage, getIssueStatusBadgeLabel, getIssueStatusClassName, isClosedIssueStatus, isOpenIssueStatus, isReporterMessageConflict, issueReportingKeys, selectReporterVisibleMessages, useIssueReporting, useIssueReportingHistory, useIssueReportingMessageMutation, useIssueReportingMessages, useIssueReportingMutations, useIssueReportingStatus, useReportMode };
|