@lightworkai.official/debug-capture 0.6.0 → 0.7.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 +44 -80
- package/dist/index.d.ts +1 -10
- package/dist/index.mjs +9 -14
- package/dist/portal.d.ts +24 -0
- package/package.json +1 -1
- package/src/index.ts +10 -54
- package/src/portal.ts +65 -0
- package/dist/mytickets/api.d.ts +0 -115
- package/dist/mytickets/format.d.ts +0 -84
- package/dist/mytickets/sanitize.d.ts +0 -66
- package/dist/mytickets/strings.d.ts +0 -74
- package/dist/mytickets/toolbar.d.ts +0 -17
- package/src/mytickets/api.ts +0 -226
- package/src/mytickets/format.ts +0 -191
- package/src/mytickets/sanitize.ts +0 -221
- package/src/mytickets/strings.ts +0 -217
- package/src/mytickets/toolbar.ts +0 -48
package/src/index.ts
CHANGED
|
@@ -51,59 +51,15 @@ export { createAnnotator } from "./ui/annotator";
|
|
|
51
51
|
export type { Annotator, AnnotatorTool } from "./ui/annotator";
|
|
52
52
|
export { strings as reporterStrings } from "./ui/strings";
|
|
53
53
|
export type { Strings as ReporterStrings } from "./ui/strings";
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
fetchRealmConfig,
|
|
65
|
-
TicketApiError,
|
|
66
|
-
NoIdentityError,
|
|
67
|
-
} from "./mytickets/api";
|
|
68
|
-
export type {
|
|
69
|
-
MyTicket,
|
|
70
|
-
MyTicketListItem,
|
|
71
|
-
MyTicketDetail,
|
|
72
|
-
TicketMessage,
|
|
73
|
-
TicketAttachment,
|
|
74
|
-
StatusEvent,
|
|
75
|
-
StatusColumn,
|
|
76
|
-
RealmConfig,
|
|
77
|
-
} from "./mytickets/api";
|
|
78
|
-
export {
|
|
79
|
-
ticketKey,
|
|
80
|
-
formatDateTime,
|
|
81
|
-
statusMaps,
|
|
82
|
-
hasSolution,
|
|
83
|
-
hasTeamReply,
|
|
84
|
-
responseRank,
|
|
85
|
-
compareBy,
|
|
86
|
-
matchesKeyword,
|
|
87
|
-
pageOf,
|
|
88
|
-
pageCount,
|
|
89
|
-
PAGE_SIZE,
|
|
90
|
-
} from "./mytickets/format";
|
|
91
|
-
export type { StatusMaps, Sort, SortKey } from "./mytickets/format";
|
|
92
|
-
export {
|
|
93
|
-
toPlainText,
|
|
94
|
-
looksLikeHtml,
|
|
95
|
-
renderBody,
|
|
96
|
-
cleanHtml,
|
|
97
|
-
htmlIsEmpty,
|
|
98
|
-
ALLOWED_TAGS,
|
|
99
|
-
ALLOWED_ATTR,
|
|
100
|
-
isAllowedHref,
|
|
101
|
-
isAllowedImageSrc,
|
|
102
|
-
} from "./mytickets/sanitize";
|
|
103
|
-
export { NOTE_TOOLBAR, FULL_TOOLBAR } from "./mytickets/toolbar";
|
|
104
|
-
export type { EditorTool } from "./mytickets/toolbar";
|
|
105
|
-
export { ticketStrings } from "./mytickets/strings";
|
|
106
|
-
export type { TicketStrings } from "./mytickets/strings";
|
|
107
|
-
export { statusTone, STATUS_TONES } from "./mytickets/format";
|
|
54
|
+
/*
|
|
55
|
+
* The reporter's own tickets are no longer a component this library ships.
|
|
56
|
+
*
|
|
57
|
+
* They were: a read API, a ticket list, a thread, a reply editor, ported to
|
|
58
|
+
* React, Vue and Angular. It worked, and it meant every change to the way a
|
|
59
|
+
* ticket looks had to land in four places. The support host renders that screen
|
|
60
|
+
* already, so the library now hands someone to it instead — one button, one
|
|
61
|
+
* link, and the ticket UI maintained where it lives.
|
|
62
|
+
*/
|
|
63
|
+
export { openSupportPortal, supportPortalUrl, NoIdentityError } from "./portal";
|
|
108
64
|
|
|
109
65
|
export type * from "./types";
|
package/src/portal.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sending someone to their tickets on the support host.
|
|
3
|
+
*
|
|
4
|
+
* This replaces an embedded panel, and the trade is worth stating. The panel
|
|
5
|
+
* meant a read API, a ticket screen ported to three frameworks, and every
|
|
6
|
+
* change to the way a ticket looks landing in four repositories. A link means
|
|
7
|
+
* the host renders a button and nothing else; the portal is maintained in one
|
|
8
|
+
* place, by the people who own it. It is the shape Jira and Zendesk use, for
|
|
9
|
+
* the same reason.
|
|
10
|
+
*
|
|
11
|
+
* The cost is honest too: it is a context switch. Someone checking a report
|
|
12
|
+
* leaves the app they were in.
|
|
13
|
+
*/
|
|
14
|
+
import { getConfig } from "./config";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Where a signed-in hand-off lands. Stable on purpose — it goes in other
|
|
18
|
+
* teams' configuration, and moving it means asking them all to redeploy.
|
|
19
|
+
*/
|
|
20
|
+
const PORTAL_PATH = "/sso";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Build the hand-off URL. Separate from opening it so the assembly can be
|
|
24
|
+
* tested without a browser, and so a host that wants its own link element
|
|
25
|
+
* rather than our button has something to point it at.
|
|
26
|
+
*/
|
|
27
|
+
export function supportPortalUrl(host: string, realmKey: string, token: string): string {
|
|
28
|
+
const url = new URL(PORTAL_PATH, host.endsWith("/") ? host : `${host}/`);
|
|
29
|
+
url.searchParams.set("realm", realmKey);
|
|
30
|
+
url.searchParams.set("token", token);
|
|
31
|
+
return url.toString();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class NoIdentityError extends Error {
|
|
35
|
+
constructor(message = "No identity provider is configured, or nobody is signed in") {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = "NoIdentityError";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Open the portal, signed in as the current user.
|
|
43
|
+
*
|
|
44
|
+
* The token is fetched at click time and not before. It is minted to live about
|
|
45
|
+
* two minutes and is spent on arrival, so one obtained at page load would
|
|
46
|
+
* usually be dead by the time anybody pressed anything.
|
|
47
|
+
*
|
|
48
|
+
* Same origin by default. A new tab is available but is not the default: the
|
|
49
|
+
* point of this is that the support system owns the whole ticket experience,
|
|
50
|
+
* and leaving the host app open behind it invites the two to disagree about
|
|
51
|
+
* what a ticket says.
|
|
52
|
+
*/
|
|
53
|
+
export async function openSupportPortal(options: { target?: "_self" | "_blank" } = {}): Promise<void> {
|
|
54
|
+
const config = getConfig();
|
|
55
|
+
if (!config.identity) throw new NoIdentityError();
|
|
56
|
+
|
|
57
|
+
const token = await config.identity();
|
|
58
|
+
// Null is "nobody is signed in", which the host answers, not us — it has a
|
|
59
|
+
// login screen and we do not know where it is.
|
|
60
|
+
if (!token) throw new NoIdentityError();
|
|
61
|
+
|
|
62
|
+
const url = supportPortalUrl(config.host, config.realmKey, token);
|
|
63
|
+
if (options.target === "_blank") window.open(url, "_blank", "noopener,noreferrer");
|
|
64
|
+
else window.location.assign(url);
|
|
65
|
+
}
|
package/dist/mytickets/api.d.ts
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
/** A board column as the realm configured it. Only public lanes are returned. */
|
|
2
|
-
export interface StatusColumn {
|
|
3
|
-
key: string;
|
|
4
|
-
label: string;
|
|
5
|
-
description: string;
|
|
6
|
-
color: string;
|
|
7
|
-
bucket: "active" | "closed";
|
|
8
|
-
awaitingReply: boolean;
|
|
9
|
-
}
|
|
10
|
-
export interface RealmConfig {
|
|
11
|
-
realm: {
|
|
12
|
-
id: string;
|
|
13
|
-
slug: string;
|
|
14
|
-
name: string;
|
|
15
|
-
};
|
|
16
|
-
timezone: string;
|
|
17
|
-
statusColumns: StatusColumn[];
|
|
18
|
-
featureFlags: {
|
|
19
|
-
selfServiceReopen?: boolean;
|
|
20
|
-
attachments?: boolean;
|
|
21
|
-
conversation?: boolean;
|
|
22
|
-
};
|
|
23
|
-
locale: {
|
|
24
|
-
default: string;
|
|
25
|
-
labels: Record<string, string>;
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
export interface TicketMessage {
|
|
29
|
-
id: string;
|
|
30
|
-
authorId: string | null;
|
|
31
|
-
authorName: string | null;
|
|
32
|
-
authorRole: "REPORTER" | "AGENT";
|
|
33
|
-
body: string;
|
|
34
|
-
createdAt: string;
|
|
35
|
-
editedAt: string | null;
|
|
36
|
-
}
|
|
37
|
-
export interface TicketAttachment {
|
|
38
|
-
id: string;
|
|
39
|
-
objectKey: string;
|
|
40
|
-
filename: string | null;
|
|
41
|
-
contentType: string | null;
|
|
42
|
-
sizeBytes: number | null;
|
|
43
|
-
}
|
|
44
|
-
export interface MyTicket {
|
|
45
|
-
id: string;
|
|
46
|
-
number: number;
|
|
47
|
-
title: string;
|
|
48
|
-
description: string | null;
|
|
49
|
-
category: string | null;
|
|
50
|
-
routeUrl: string | null;
|
|
51
|
-
status: string;
|
|
52
|
-
priority: string;
|
|
53
|
-
resolutionNote: string | null;
|
|
54
|
-
reopened: boolean;
|
|
55
|
-
createdAt: string;
|
|
56
|
-
updatedAt: string;
|
|
57
|
-
}
|
|
58
|
-
export interface MyTicketListItem extends MyTicket {
|
|
59
|
-
messageCount: number;
|
|
60
|
-
/** How many replies came from the team — "has anyone answered me yet". */
|
|
61
|
-
agentReplyCount: number;
|
|
62
|
-
lastMessage: {
|
|
63
|
-
at: string;
|
|
64
|
-
authorRole: "REPORTER" | "AGENT";
|
|
65
|
-
preview: string;
|
|
66
|
-
} | null;
|
|
67
|
-
}
|
|
68
|
-
export interface MyTicketDetail extends MyTicket {
|
|
69
|
-
messages: TicketMessage[];
|
|
70
|
-
attachments: TicketAttachment[];
|
|
71
|
-
}
|
|
72
|
-
/** One recorded status change. Internal lanes are already resolved server-side. */
|
|
73
|
-
export interface StatusEvent {
|
|
74
|
-
id: string;
|
|
75
|
-
fromStatus: string | null;
|
|
76
|
-
toStatus: string;
|
|
77
|
-
via: string;
|
|
78
|
-
createdAt: string;
|
|
79
|
-
}
|
|
80
|
-
/** Thrown with the server's own words, so a panel can say what went wrong. */
|
|
81
|
-
export declare class TicketApiError extends Error {
|
|
82
|
-
readonly status: number;
|
|
83
|
-
constructor(message: string, status: number);
|
|
84
|
-
}
|
|
85
|
-
/** Raised when there is no signed-in reporter to ask about. */
|
|
86
|
-
export declare class NoIdentityError extends Error {
|
|
87
|
-
constructor();
|
|
88
|
-
}
|
|
89
|
-
export declare function listMyTickets(): Promise<MyTicketListItem[]>;
|
|
90
|
-
export declare function getMyTicket(id: string): Promise<MyTicketDetail>;
|
|
91
|
-
export declare function getMyTicketByNumber(num: number): Promise<MyTicketDetail>;
|
|
92
|
-
/**
|
|
93
|
-
* A short-lived URL for a file on one's own ticket.
|
|
94
|
-
*
|
|
95
|
-
* Fetched rather than pointed at: the endpoint needs the realm key and the
|
|
96
|
-
* identity token, and an `<img>` or an `<a download>` cannot send a header.
|
|
97
|
-
*/
|
|
98
|
-
export declare function getAttachmentUrl(attachmentId: string): Promise<{
|
|
99
|
-
url: string;
|
|
100
|
-
filename: string | null;
|
|
101
|
-
}>;
|
|
102
|
-
export declare function getMyTicketHistory(id: string): Promise<StatusEvent[]>;
|
|
103
|
-
export declare function replyToTicket(id: string, body: string): Promise<TicketMessage>;
|
|
104
|
-
/**
|
|
105
|
-
* Rewrite one's own reply.
|
|
106
|
-
*
|
|
107
|
-
* The server refuses any message the caller did not write — authorship, not
|
|
108
|
-
* role — so this cannot touch the team's side of the thread.
|
|
109
|
-
*/
|
|
110
|
-
export declare function editMyMessage(ticketId: string, messageId: string, body: string): Promise<TicketMessage>;
|
|
111
|
-
export declare function reopenMyTicket(id: string, note?: string): Promise<MyTicket>;
|
|
112
|
-
export declare function uploadInlineImage(id: string, dataUri: string, filename?: string): Promise<{
|
|
113
|
-
url: string;
|
|
114
|
-
}>;
|
|
115
|
-
export declare function fetchRealmConfig(): Promise<RealmConfig>;
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The panel's decisions that are not DOM: how a ticket is named, dated, sorted,
|
|
3
|
-
* searched and described. Pure, so they can be tested without a browser — which
|
|
4
|
-
* matters here, because the DOM around them cannot be.
|
|
5
|
-
*/
|
|
6
|
-
import type { MyTicketListItem, StatusColumn } from "./api";
|
|
7
|
-
/**
|
|
8
|
-
* `ROOT-1099`, from the realm's slug — the same key the board and the admin app
|
|
9
|
-
* print, so a reporter quoting a number is quoting the one support will search
|
|
10
|
-
* for. A realm with no usable slug falls back to `#1099` rather than inventing
|
|
11
|
-
* a prefix.
|
|
12
|
-
*/
|
|
13
|
-
export declare function ticketKey(slug: string | undefined, number: number): string;
|
|
14
|
-
/**
|
|
15
|
-
* `24 พ.ค. 2568 13:00` — the original's `DD MMM BBBB HH:mm`, from the platform's
|
|
16
|
-
* own Intl rather than a date library this package will not depend on.
|
|
17
|
-
*
|
|
18
|
-
* Formatted in the REALM's timezone, not the reader's. A support desk in
|
|
19
|
-
* Bangkok and a reporter travelling in Berlin must not disagree about which day
|
|
20
|
-
* a ticket was filed, and the realm is the side that also runs the "today"
|
|
21
|
-
* filters.
|
|
22
|
-
*/
|
|
23
|
-
export declare function formatDateTime(iso: string | null | undefined, timezone: string, locale: "th" | "en" | undefined): string;
|
|
24
|
-
/** Lookups over the realm's configured lanes, with sane answers for a key that isn't there. */
|
|
25
|
-
export interface StatusMaps {
|
|
26
|
-
labelOf: (key: string) => string;
|
|
27
|
-
columnOf: (key: string) => StatusColumn | undefined;
|
|
28
|
-
isAwaitingReply: (key: string) => boolean;
|
|
29
|
-
isClosed: (key: string) => boolean;
|
|
30
|
-
/** Board order, for sorting a column of statuses the way the board reads. */
|
|
31
|
-
rankOf: (key: string) => number;
|
|
32
|
-
options: {
|
|
33
|
-
value: string;
|
|
34
|
-
label: string;
|
|
35
|
-
}[];
|
|
36
|
-
}
|
|
37
|
-
export declare function statusMaps(columns: StatusColumn[], allLabel: string): StatusMaps;
|
|
38
|
-
/** Has the team written a solution note? */
|
|
39
|
-
export declare function hasSolution(t: MyTicketListItem): boolean;
|
|
40
|
-
/** Has anyone from the team replied at all? */
|
|
41
|
-
export declare function hasTeamReply(t: MyTicketListItem): boolean;
|
|
42
|
-
/** Solution beats a reply beats silence — the order the column sorts in. */
|
|
43
|
-
export declare function responseRank(t: MyTicketListItem): number;
|
|
44
|
-
export type SortKey = "number" | "title" | "module" | "status" | "response" | "createdAt" | "updatedAt";
|
|
45
|
-
export interface Sort {
|
|
46
|
-
key: SortKey;
|
|
47
|
-
direction: "asc" | "desc";
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Filter by what the reporter SEES.
|
|
51
|
-
*
|
|
52
|
-
* The haystack is the rendered row — key, title, module, status label — because
|
|
53
|
-
* that is what someone searching has in front of them. Searching the raw status
|
|
54
|
-
* key would match `IN_PROGRESS` for a lane the reader only ever saw called
|
|
55
|
-
* กำลังดำเนินการ.
|
|
56
|
-
*/
|
|
57
|
-
export declare function matchesKeyword(t: MyTicketListItem, keyword: string, slug: string | undefined, labelOf: (key: string) => string): boolean;
|
|
58
|
-
/**
|
|
59
|
-
* Comparators for the orders a raw value compare gets wrong: status follows the
|
|
60
|
-
* board rather than the alphabet, dates are chronological rather than
|
|
61
|
-
* lexicographic, and the response column ranks by a signal that is not one field.
|
|
62
|
-
*/
|
|
63
|
-
export declare function compareBy(sort: Sort, maps: StatusMaps, slug: string | undefined): (a: MyTicketListItem, b: MyTicketListItem) => number;
|
|
64
|
-
/** Rows per page — the original's `defaultPageSize`. */
|
|
65
|
-
export declare const PAGE_SIZE = 10;
|
|
66
|
-
export declare function pageOf<T>(rows: T[], page: number, size?: number): T[];
|
|
67
|
-
export declare function pageCount(total: number, size?: number): number;
|
|
68
|
-
/**
|
|
69
|
-
* The same ten colour tokens the board uses, as concrete pairs.
|
|
70
|
-
*
|
|
71
|
-
* A status arrives as DATA — a realm adds lanes whenever it likes — so a pill is
|
|
72
|
-
* coloured with an inline style from this map rather than a class a stylesheet
|
|
73
|
-
* could never know the name of. Keeping the values identical
|
|
74
|
-
* to the app's own STATUS_TONES is the point: a reporter and an agent looking at
|
|
75
|
-
* the same ticket should see the same colour for it.
|
|
76
|
-
*/
|
|
77
|
-
export declare const STATUS_TONES: Record<string, {
|
|
78
|
-
fg: string;
|
|
79
|
-
bg: string;
|
|
80
|
-
}>;
|
|
81
|
-
export declare function statusTone(token: string | undefined): {
|
|
82
|
-
fg: string;
|
|
83
|
-
bg: string;
|
|
84
|
-
};
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rendering a ticket body inside somebody else's app.
|
|
3
|
-
*
|
|
4
|
-
* Bodies are HTML — the composer's formatting and its inline screenshots are the
|
|
5
|
-
* point of the thread, so stripping to text would lose what a reporter actually
|
|
6
|
-
* came to read. But that HTML was written by other people, and this package
|
|
7
|
-
* renders it inside a HOST application's page. Markup that ran there would run
|
|
8
|
-
* with the host's origin, against the host's session. A support widget must not
|
|
9
|
-
* be the way an app gets XSS.
|
|
10
|
-
*
|
|
11
|
-
* The support app solves this with DOMPurify. A package that every consumer
|
|
12
|
-
* installs cannot take that dependency for one screen, so this is the same
|
|
13
|
-
* POLICY over the platform's own parser: parse the string with DOMParser (never
|
|
14
|
-
* a regex), walk the result, and delete every node and attribute not on the
|
|
15
|
-
* list. Anything unrecognised is removed rather than escaped, and the walk is
|
|
16
|
-
* over an inert document, so nothing loads or executes while it happens.
|
|
17
|
-
*/
|
|
18
|
-
/** Tags an ordinary note actually uses. Everything else goes. */
|
|
19
|
-
export declare const ALLOWED_TAGS: Set<string>;
|
|
20
|
-
export declare const ALLOWED_ATTR: Set<string>;
|
|
21
|
-
/** Links: ordinary web destinations only. No javascript:, no data:. */
|
|
22
|
-
export declare function isAllowedHref(url: string): boolean;
|
|
23
|
-
/**
|
|
24
|
-
* Image sources: OUR inline images and nothing else.
|
|
25
|
-
*
|
|
26
|
-
* Not a tightening for its own sake. Any other src turns every ticket into a
|
|
27
|
-
* tracking pixel aimed at whoever opens it — a body can be written by a stranger
|
|
28
|
-
* who filed a report, and the reader here is the reporter, on the host's page.
|
|
29
|
-
* Accepts the server-relative form and the same path already made absolute
|
|
30
|
-
* against the configured host.
|
|
31
|
-
*/
|
|
32
|
-
export declare function isAllowedImageSrc(url: string, host: string): boolean;
|
|
33
|
-
export declare function looksLikeHtml(body: string): boolean;
|
|
34
|
-
/** Tags out, line structure kept — for previews and anywhere text is all that fits. */
|
|
35
|
-
export declare function toPlainText(body: string): string;
|
|
36
|
-
/**
|
|
37
|
-
* Fill `target` with a safe rendering of `body`.
|
|
38
|
-
*
|
|
39
|
-
* A node rather than a string, deliberately: handing back HTML invites a caller
|
|
40
|
-
* to concatenate it with something else and re-parse the result, which is where
|
|
41
|
-
* sanitisers stop holding.
|
|
42
|
-
*/
|
|
43
|
-
export declare function renderBody(target: HTMLElement, body: string, host: string): void;
|
|
44
|
-
/**
|
|
45
|
-
* The same walk, but returning a string — for content going OUT.
|
|
46
|
-
*
|
|
47
|
-
* `renderBody` deliberately hands back a node, because handing back HTML invites
|
|
48
|
-
* a caller to concatenate and re-parse it. This one exists for the single case
|
|
49
|
-
* where a string is the only possible answer: the composer has to put what
|
|
50
|
-
* somebody typed into a JSON body.
|
|
51
|
-
*
|
|
52
|
-
* It matters for the same reason the display side does, from the other
|
|
53
|
-
* direction. A contenteditable takes whatever the clipboard had in it — a
|
|
54
|
-
* pasted block of a web page arrives with its scripts, its styles and its
|
|
55
|
-
* tracking pixels intact — and posting that unfiltered would store it for
|
|
56
|
-
* every future reader of the thread.
|
|
57
|
-
*/
|
|
58
|
-
export declare function cleanHtml(html: string, host: string): string;
|
|
59
|
-
/**
|
|
60
|
-
* True when there is nothing worth sending.
|
|
61
|
-
*
|
|
62
|
-
* An image alone counts as content — a screenshot with no words is the most
|
|
63
|
-
* common reply a reporter makes — but a contenteditable that has been typed in
|
|
64
|
-
* and cleared is full of empty tags and ` `, and those are not.
|
|
65
|
-
*/
|
|
66
|
-
export declare function htmlIsEmpty(html: string): boolean;
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The tickets panel's own words, kept apart from the reporter dialog's so
|
|
3
|
-
* neither grows the other's vocabulary. Thai wording is the original's, verbatim
|
|
4
|
-
* where the original had one.
|
|
5
|
-
*/
|
|
6
|
-
export interface TicketStrings {
|
|
7
|
-
title: string;
|
|
8
|
-
intro: string;
|
|
9
|
-
searchPlaceholder: string;
|
|
10
|
-
searchLabel: string;
|
|
11
|
-
allStatuses: string;
|
|
12
|
-
count: (n: number) => string;
|
|
13
|
-
colNumber: string;
|
|
14
|
-
colTitle: string;
|
|
15
|
-
colModule: string;
|
|
16
|
-
colStatus: string;
|
|
17
|
-
colResponse: string;
|
|
18
|
-
colCreated: string;
|
|
19
|
-
colUpdated: string;
|
|
20
|
-
awaitingReply: string;
|
|
21
|
-
hasSolution: string;
|
|
22
|
-
hasReply: string;
|
|
23
|
-
noReply: string;
|
|
24
|
-
empty: string;
|
|
25
|
-
emptyFiltered: string;
|
|
26
|
-
loading: string;
|
|
27
|
-
listFailed: string;
|
|
28
|
-
detailFailed: string;
|
|
29
|
-
signedOut: string;
|
|
30
|
-
back: string;
|
|
31
|
-
reportedBy: string;
|
|
32
|
-
conversation: string;
|
|
33
|
-
resolution: string;
|
|
34
|
-
noMessages: string;
|
|
35
|
-
you: string;
|
|
36
|
-
team: string;
|
|
37
|
-
/** The role chip beside a reporter's name, as the original prints it. */
|
|
38
|
-
reporterRole: string;
|
|
39
|
-
edited: string;
|
|
40
|
-
edit: string;
|
|
41
|
-
saveEdit: string;
|
|
42
|
-
cancel: string;
|
|
43
|
-
replyPlaceholder: string;
|
|
44
|
-
bold: string;
|
|
45
|
-
italic: string;
|
|
46
|
-
underline: string;
|
|
47
|
-
strike: string;
|
|
48
|
-
code: string;
|
|
49
|
-
blockquote: string;
|
|
50
|
-
bulletList: string;
|
|
51
|
-
orderedList: string;
|
|
52
|
-
link: string;
|
|
53
|
-
linkPrompt: string;
|
|
54
|
-
linkNeedsSelection: string;
|
|
55
|
-
linkInvalid: string;
|
|
56
|
-
attachImage: string;
|
|
57
|
-
uploading: string;
|
|
58
|
-
send: string;
|
|
59
|
-
sending: string;
|
|
60
|
-
sent: string;
|
|
61
|
-
sendFailed: string;
|
|
62
|
-
reopen: string;
|
|
63
|
-
reopenHint: string;
|
|
64
|
-
reopening: string;
|
|
65
|
-
reopened: string;
|
|
66
|
-
reopenFailed: string;
|
|
67
|
-
close: string;
|
|
68
|
-
retry: string;
|
|
69
|
-
page: string;
|
|
70
|
-
of: (page: number, pages: number) => string;
|
|
71
|
-
prev: string;
|
|
72
|
-
next: string;
|
|
73
|
-
}
|
|
74
|
-
export declare function ticketStrings(locale: "th" | "en" | undefined): TicketStrings;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Which controls a rich composer offers.
|
|
3
|
-
*
|
|
4
|
-
* A list rather than a fixed set, because the original itself has two —
|
|
5
|
-
* `NOTE_TOOLBAR` for replies and a longer one for articles — and the support app's
|
|
6
|
-
* admin composer wants a few more than a reporter's does. The alternative was a
|
|
7
|
-
* second editor component, which is the thing this package exists to stop.
|
|
8
|
-
*/
|
|
9
|
-
export type EditorTool = "bold" | "italic" | "underline" | "strike" | "code" | "bulletList" | "orderedList" | "blockquote" | "link" | "image";
|
|
10
|
-
/** The original's own NOTE_TOOLBAR — what a reporter replying to a ticket gets. */
|
|
11
|
-
export declare const NOTE_TOOLBAR: EditorTool[];
|
|
12
|
-
/**
|
|
13
|
-
* Everything, for a staff composer. Adds the three the admin side had grown on
|
|
14
|
-
* its own — strike, code and blockquote — so adopting this component costs the
|
|
15
|
-
* app nothing it already had.
|
|
16
|
-
*/
|
|
17
|
-
export declare const FULL_TOOLBAR: EditorTool[];
|