@flamingo-stack/openframe-frontend-core 0.0.217 → 0.0.218
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/{chunk-L6IBKPVM.js → chunk-EKBM4FHK.js} +2 -2
- package/dist/{chunk-SWZUZYWR.js → chunk-EWA2NFUR.js} +2 -2
- package/dist/{chunk-TYIBMDUZ.cjs → chunk-FZZBCRID.cjs} +7 -7
- package/dist/{chunk-TYIBMDUZ.cjs.map → chunk-FZZBCRID.cjs.map} +1 -1
- package/dist/{chunk-G2HHSZ3S.cjs → chunk-GE64T3JT.cjs} +9 -9
- package/dist/{chunk-G2HHSZ3S.cjs.map → chunk-GE64T3JT.cjs.map} +1 -1
- package/dist/{chunk-YWDC5BXM.cjs → chunk-L5RSJE2I.cjs} +1940 -915
- package/dist/chunk-L5RSJE2I.cjs.map +1 -0
- package/dist/{chunk-BVFRD34B.js → chunk-OHOUSDAY.js} +2 -2
- package/dist/{chunk-MVQ3OODK.cjs → chunk-S4SVD5JI.cjs} +9 -9
- package/dist/{chunk-MVQ3OODK.cjs.map → chunk-S4SVD5JI.cjs.map} +1 -1
- package/dist/{chunk-N5IKPYRL.js → chunk-SWIR5EB2.js} +2 -2
- package/dist/{chunk-6DCKL73F.cjs → chunk-TCJ5B2ZD.cjs} +24 -24
- package/dist/{chunk-6DCKL73F.cjs.map → chunk-TCJ5B2ZD.cjs.map} +1 -1
- package/dist/{chunk-ENBGG2K2.js → chunk-V5JY5RSY.js} +2954 -1929
- package/dist/chunk-V5JY5RSY.js.map +1 -0
- package/dist/components/chat/embeddable-chat.d.ts +13 -0
- package/dist/components/chat/embeddable-chat.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +104 -10
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-slash-commands.d.ts +6 -0
- package/dist/components/chat/hooks/use-slash-commands.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-unified-chat.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +2 -2
- package/dist/components/chat/index.js +1 -1
- package/dist/components/chat/types/unified-chat-state.types.d.ts +81 -0
- package/dist/components/chat/types/unified-chat-state.types.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +3 -3
- package/dist/components/contact/index.js +2 -2
- package/dist/components/features/index.cjs +2 -2
- package/dist/components/features/index.js +1 -1
- package/dist/components/index.cjs +73 -51
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +26 -4
- package/dist/components/index.js.map +1 -1
- package/dist/components/navigation/app-header.d.ts +7 -0
- package/dist/components/navigation/app-header.d.ts.map +1 -1
- package/dist/components/navigation/app-layout-drawer.d.ts +65 -0
- package/dist/components/navigation/app-layout-drawer.d.ts.map +1 -0
- package/dist/components/navigation/app-layout.d.ts +9 -1
- package/dist/components/navigation/app-layout.d.ts.map +1 -1
- package/dist/components/navigation/header-mingo-button.d.ts +21 -0
- package/dist/components/navigation/header-mingo-button.d.ts.map +1 -0
- package/dist/components/navigation/index.cjs +24 -2
- package/dist/components/navigation/index.cjs.map +1 -1
- package/dist/components/navigation/index.d.ts +5 -1
- package/dist/components/navigation/index.d.ts.map +1 -1
- package/dist/components/navigation/index.js +23 -1
- package/dist/components/onboarding-guides/index.cjs +18 -18
- package/dist/components/onboarding-guides/index.js +3 -3
- package/dist/components/tickets/hooks/use-ticket-engagements.d.ts.map +1 -1
- package/dist/components/tickets/index.cjs +80 -66
- package/dist/components/tickets/index.cjs.map +1 -1
- package/dist/components/tickets/index.js +20 -6
- package/dist/components/tickets/index.js.map +1 -1
- package/dist/components/ui/index.cjs +2 -2
- package/dist/components/ui/index.js +1 -1
- package/dist/index.cjs +26 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +25 -1
- package/dist/utils/embed-authed-fetch.d.ts +80 -0
- package/dist/utils/embed-authed-fetch.d.ts.map +1 -1
- package/dist/utils/index.cjs +70 -5
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +70 -6
- package/dist/utils/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/chat/embeddable-chat.tsx +154 -37
- package/src/components/chat/hooks/use-nats-chat-adapter.ts +601 -23
- package/src/components/chat/hooks/use-slash-commands.ts +10 -1
- package/src/components/chat/hooks/use-sse-chat-adapter.ts +45 -0
- package/src/components/chat/hooks/use-unified-chat.ts +59 -0
- package/src/components/chat/types/unified-chat-state.types.ts +116 -0
- package/src/components/navigation/app-header.tsx +23 -0
- package/src/components/navigation/app-layout-drawer.tsx +620 -0
- package/src/components/navigation/app-layout.tsx +65 -26
- package/src/components/navigation/header-mingo-button.tsx +58 -0
- package/src/components/navigation/index.ts +17 -1
- package/src/components/tickets/hooks/use-ticket-engagements.ts +24 -4
- package/src/stories/AppLayoutDrawer.stories.tsx +228 -0
- package/src/utils/.embed-authed-fetch.md +7 -0
- package/src/utils/__tests__/embed-authed-fetch.test.ts +103 -1
- package/src/utils/embed-authed-fetch.ts +247 -7
- package/src/utils/index.ts +5 -1
- package/dist/chunk-ENBGG2K2.js.map +0 -1
- package/dist/chunk-YWDC5BXM.cjs.map +0 -1
- /package/dist/{chunk-L6IBKPVM.js.map → chunk-EKBM4FHK.js.map} +0 -0
- /package/dist/{chunk-SWZUZYWR.js.map → chunk-EWA2NFUR.js.map} +0 -0
- /package/dist/{chunk-BVFRD34B.js.map → chunk-OHOUSDAY.js.map} +0 -0
- /package/dist/{chunk-N5IKPYRL.js.map → chunk-SWIR5EB2.js.map} +0 -0
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
var
|
|
7
|
+
var _chunkGE64T3JTcjs = require('../../chunk-GE64T3JT.cjs');
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
var
|
|
12
|
+
var _chunkFZZBCRIDcjs = require('../../chunk-FZZBCRID.cjs');
|
|
13
13
|
require('../../chunk-OB45JHDY.cjs');
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
var
|
|
16
|
+
var _chunkTCJ5B2ZDcjs = require('../../chunk-TCJ5B2ZD.cjs');
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
|
|
@@ -41,7 +41,7 @@ var _chunk6DCKL73Fcjs = require('../../chunk-6DCKL73F.cjs');
|
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
var
|
|
44
|
+
var _chunkL5RSJE2Icjs = require('../../chunk-L5RSJE2I.cjs');
|
|
45
45
|
require('../../chunk-XL4V2PYG.cjs');
|
|
46
46
|
require('../../chunk-BZFW3FOF.cjs');
|
|
47
47
|
|
|
@@ -105,7 +105,7 @@ function TicketOpenForm({
|
|
|
105
105
|
}) {
|
|
106
106
|
const [subject, setSubject] = _react.useState.call(void 0, "");
|
|
107
107
|
const [content, setContent] = _react.useState.call(void 0, "");
|
|
108
|
-
const { attachments, readyAttachments, hasInflightUploads, addFiles, removeAttachment, clear } =
|
|
108
|
+
const { attachments, readyAttachments, hasInflightUploads, addFiles, removeAttachment, clear } = _chunkL5RSJE2Icjs.useChatAttachments.call(void 0, );
|
|
109
109
|
const trimmedSubject = subject.trim();
|
|
110
110
|
const trimmedContent = content.trim();
|
|
111
111
|
const overCap = content.length > TICKET_TEXT_MAX_CHARS;
|
|
@@ -125,7 +125,7 @@ function TicketOpenForm({
|
|
|
125
125
|
clear();
|
|
126
126
|
}
|
|
127
127
|
};
|
|
128
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
128
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkL5RSJE2Icjs.Card, { className: "p-6", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { onSubmit: handleSubmit, className: "flex flex-col md:flex-row gap-6", children: [
|
|
129
129
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex-1 min-w-0 md:max-w-md", children: [
|
|
130
130
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "text-2xl font-semibold text-ods-text-primary mb-2", children: "Need Support?" }),
|
|
131
131
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-sm", children: "Can't find what you're looking for? Submit a support ticket below \u2014 we'll follow up shortly." }),
|
|
@@ -164,7 +164,7 @@ function TicketOpenForm({
|
|
|
164
164
|
}
|
|
165
165
|
),
|
|
166
166
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
167
|
-
|
|
167
|
+
_chunkL5RSJE2Icjs.Textarea,
|
|
168
168
|
{
|
|
169
169
|
id: "ticket-content",
|
|
170
170
|
placeholder: "Describe your issue or question in detail...",
|
|
@@ -188,7 +188,7 @@ function TicketOpenForm({
|
|
|
188
188
|
)
|
|
189
189
|
] }),
|
|
190
190
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
191
|
-
|
|
191
|
+
_chunkL5RSJE2Icjs.ChatAttachmentChipStrip,
|
|
192
192
|
{
|
|
193
193
|
attachments,
|
|
194
194
|
onRemove: removeAttachment,
|
|
@@ -197,7 +197,7 @@ function TicketOpenForm({
|
|
|
197
197
|
),
|
|
198
198
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center justify-between gap-3", children: [
|
|
199
199
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
200
|
-
|
|
200
|
+
_chunkL5RSJE2Icjs.ChatAttachmentAddButton,
|
|
201
201
|
{
|
|
202
202
|
attachmentsEnabled: !supportSystemDown,
|
|
203
203
|
attachmentsCount: attachments.length,
|
|
@@ -235,9 +235,10 @@ var _usesticktobottom = require('use-stick-to-bottom');
|
|
|
235
235
|
|
|
236
236
|
var LIST_ENGAGEMENTS_ENDPOINT = "/api/chat/agent/list-engagements";
|
|
237
237
|
function useTicketEngagements(externalTicketId, enabled = true, refetchInterval = false) {
|
|
238
|
-
const identity =
|
|
238
|
+
const identity = _chunkL5RSJE2Icjs.useChatIdentity.call(void 0, );
|
|
239
239
|
const identityKey = _nullishCoalesce(_optionalChain([identity, 'access', _2 => _2.user, 'optionalAccess', _3 => _3.email]), () => ( "anon"));
|
|
240
|
-
const
|
|
240
|
+
const fetchable = enabled && !!externalTicketId && !externalTicketId.startsWith("temp-");
|
|
241
|
+
const queryEnabled = fetchable && identity.authTier !== "anon" && !!_optionalChain([identity, 'access', _4 => _4.user, 'optionalAccess', _5 => _5.email]);
|
|
241
242
|
const query = _reactquery.useQuery.call(void 0, {
|
|
242
243
|
queryKey: ["ticket-engagements", externalTicketId, identityKey],
|
|
243
244
|
enabled: queryEnabled,
|
|
@@ -254,7 +255,7 @@ function useTicketEngagements(externalTicketId, enabled = true, refetchInterval
|
|
|
254
255
|
// so polling pauses on a hidden tab.
|
|
255
256
|
refetchInterval,
|
|
256
257
|
queryFn: async () => {
|
|
257
|
-
const response = await
|
|
258
|
+
const response = await _chunkL5RSJE2Icjs.embedAuthedFetch.call(void 0, LIST_ENGAGEMENTS_ENDPOINT, {
|
|
258
259
|
method: "POST",
|
|
259
260
|
body: JSON.stringify({ ticket_id: externalTicketId })
|
|
260
261
|
});
|
|
@@ -268,7 +269,20 @@ function useTicketEngagements(externalTicketId, enabled = true, refetchInterval
|
|
|
268
269
|
});
|
|
269
270
|
return {
|
|
270
271
|
engagements: _nullishCoalesce(query.data, () => ( [])),
|
|
271
|
-
|
|
272
|
+
// Loading-state truth that prevents the "body → blink → skeleton → data"
|
|
273
|
+
// double-flash. The bug: `useChatIdentity` starts at anon defaults and
|
|
274
|
+
// resolves async, so on the first render `queryEnabled` is false and the
|
|
275
|
+
// OLD `queryEnabled && query.isLoading` returned FALSE — the panel rendered
|
|
276
|
+
// the ticket body, THEN identity resolved, the query enabled, isLoading
|
|
277
|
+
// flipped true → skeleton appeared (the blink), then data landed.
|
|
278
|
+
//
|
|
279
|
+
// Fix: for a fetchable ticket we are "loading" whenever we don't yet have
|
|
280
|
+
// the timeline to show — that includes the window while identity is still
|
|
281
|
+
// resolving (so we skeleton from the FIRST render, never the body) AND the
|
|
282
|
+
// cold query fetch (`data === undefined`). A background poll keeps
|
|
283
|
+
// `query.data` defined, so it never re-flashes the skeleton. Non-fetchable
|
|
284
|
+
// (optimistic/disabled) or a resolved-anon viewer → not loading.
|
|
285
|
+
isLoading: fetchable && (identity.isLoading || queryEnabled && query.data === void 0),
|
|
272
286
|
isFetching: query.isFetching,
|
|
273
287
|
error: _nullishCoalesce(query.error, () => ( null)),
|
|
274
288
|
refetch: () => {
|
|
@@ -302,7 +316,7 @@ function TicketLinkedDeliveryCard({
|
|
|
302
316
|
{
|
|
303
317
|
className: `rounded-md border border-ods-border bg-ods-bg overflow-hidden ${_nullishCoalesce(className, () => ( ""))}`,
|
|
304
318
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
305
|
-
|
|
319
|
+
_chunkGE64T3JTcjs.DeliveryRow,
|
|
306
320
|
{
|
|
307
321
|
item,
|
|
308
322
|
href: clickup.delivery_href,
|
|
@@ -326,7 +340,7 @@ function TicketReplyComposer({
|
|
|
326
340
|
}) {
|
|
327
341
|
const [resolution, setResolution] = _react.useState.call(void 0, "");
|
|
328
342
|
const [closeDialogOpen, setCloseDialogOpen] = _react.useState.call(void 0, false);
|
|
329
|
-
const attachments =
|
|
343
|
+
const attachments = _chunkL5RSJE2Icjs.useChatAttachments.call(void 0, );
|
|
330
344
|
const ticketRef = { id: ticket.id, external_id: ticket.external_id };
|
|
331
345
|
const hasReadyFiles = attachments.readyAttachments.length > 0;
|
|
332
346
|
const handleSend = _react.useCallback.call(void 0,
|
|
@@ -354,7 +368,7 @@ function TicketReplyComposer({
|
|
|
354
368
|
const disabled = busy || supportSystemDown;
|
|
355
369
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-2", children: [
|
|
356
370
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
357
|
-
|
|
371
|
+
_chunkL5RSJE2Icjs.ChatAttachmentChipStrip,
|
|
358
372
|
{
|
|
359
373
|
attachments: attachments.attachments,
|
|
360
374
|
onRemove: attachments.removeAttachment,
|
|
@@ -363,7 +377,7 @@ function TicketReplyComposer({
|
|
|
363
377
|
}
|
|
364
378
|
),
|
|
365
379
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
366
|
-
|
|
380
|
+
_chunkL5RSJE2Icjs.ChatInput,
|
|
367
381
|
{
|
|
368
382
|
fullWidth: true,
|
|
369
383
|
autoFocus: true,
|
|
@@ -377,7 +391,7 @@ function TicketReplyComposer({
|
|
|
377
391
|
),
|
|
378
392
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2 w-full", children: [
|
|
379
393
|
!supportSystemDown && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
380
|
-
|
|
394
|
+
_chunkL5RSJE2Icjs.ChatAttachmentAddButton,
|
|
381
395
|
{
|
|
382
396
|
attachmentsEnabled: true,
|
|
383
397
|
attachmentsCount: attachments.attachments.length,
|
|
@@ -400,13 +414,13 @@ function TicketReplyComposer({
|
|
|
400
414
|
}
|
|
401
415
|
)
|
|
402
416
|
] }),
|
|
403
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
404
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
405
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
406
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
417
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkL5RSJE2Icjs.AlertDialog, { open: closeDialogOpen, onOpenChange: setCloseDialogOpen, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkL5RSJE2Icjs.AlertDialogContent, { className: "bg-ods-card border-ods-border", children: [
|
|
418
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkL5RSJE2Icjs.AlertDialogHeader, { children: [
|
|
419
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkL5RSJE2Icjs.AlertDialogTitle, { className: "text-ods-text-primary", children: "Close this ticket?" }),
|
|
420
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkL5RSJE2Icjs.AlertDialogDescription, { className: "text-ods-text-secondary", children: "Add an optional resolution note below. You can reopen the ticket later if needed." })
|
|
407
421
|
] }),
|
|
408
422
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
409
|
-
|
|
423
|
+
_chunkL5RSJE2Icjs.Textarea,
|
|
410
424
|
{
|
|
411
425
|
value: resolution,
|
|
412
426
|
onChange: (e) => setResolution(e.target.value),
|
|
@@ -416,9 +430,9 @@ function TicketReplyComposer({
|
|
|
416
430
|
className: "mt-2"
|
|
417
431
|
}
|
|
418
432
|
),
|
|
419
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
433
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkL5RSJE2Icjs.AlertDialogFooter, { children: [
|
|
420
434
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
421
|
-
|
|
435
|
+
_chunkL5RSJE2Icjs.AlertDialogCancel,
|
|
422
436
|
{
|
|
423
437
|
disabled: busy,
|
|
424
438
|
className: "bg-transparent border-ods-border text-ods-text-primary hover:bg-ods-border",
|
|
@@ -426,7 +440,7 @@ function TicketReplyComposer({
|
|
|
426
440
|
}
|
|
427
441
|
),
|
|
428
442
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
429
|
-
|
|
443
|
+
_chunkL5RSJE2Icjs.AlertDialogAction,
|
|
430
444
|
{
|
|
431
445
|
onClick: () => void confirmClose(),
|
|
432
446
|
disabled: busy,
|
|
@@ -496,7 +510,7 @@ var TICKET_FEED_HEIGHT = "h-[60vh] md:h-[420px]";
|
|
|
496
510
|
var TICKET_FEED_INNER = "flex flex-col gap-4 md:gap-6 px-4 md:px-6 py-4 md:py-6";
|
|
497
511
|
var TICKET_FEED_SKELETON_ROWS = 6;
|
|
498
512
|
function TicketTimelinePanel({ ticket }) {
|
|
499
|
-
const identity =
|
|
513
|
+
const identity = _chunkL5RSJE2Icjs.useChatIdentity.call(void 0, );
|
|
500
514
|
const externalId = isOptimistic(ticket) ? null : ticket.external_id;
|
|
501
515
|
const { engagements, isLoading } = useTicketEngagements(
|
|
502
516
|
externalId,
|
|
@@ -516,11 +530,11 @@ function TicketTimelinePanel({ ticket }) {
|
|
|
516
530
|
const customerName = (isViewerTheCustomer ? viewerName : null) || ticketCustomerName || viewerName || _optionalChain([identity, 'access', _19 => _19.user, 'optionalAccess', _20 => _20.email]) || "You";
|
|
517
531
|
const customerAvatar = isViewerTheCustomer ? _nullishCoalesce(_optionalChain([identity, 'access', _21 => _21.user, 'optionalAccess', _22 => _22.avatarUrl]), () => ( void 0)) : void 0;
|
|
518
532
|
if (isLoading) {
|
|
519
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: `${TICKET_FEED_FRAME} ${TICKET_FEED_HEIGHT}`, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: TICKET_FEED_INNER, children: Array.from({ length: TICKET_FEED_SKELETON_ROWS }, (_, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
533
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: `${TICKET_FEED_FRAME} ${TICKET_FEED_HEIGHT}`, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: TICKET_FEED_INNER, children: Array.from({ length: TICKET_FEED_SKELETON_ROWS }, (_, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkL5RSJE2Icjs.ChatMessageRowSkeleton, {}, i)) }) });
|
|
520
534
|
}
|
|
521
535
|
if (bodyTurns.length === 0 && engagements.length === 0) {
|
|
522
536
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
523
|
-
|
|
537
|
+
_chunkGE64T3JTcjs.EmptyState,
|
|
524
538
|
{
|
|
525
539
|
type: "generic",
|
|
526
540
|
title: "No conversation yet",
|
|
@@ -535,7 +549,7 @@ function TicketTimelinePanel({ ticket }) {
|
|
|
535
549
|
const isResolution = turn.startsWith("[Resolution]");
|
|
536
550
|
const text = isResolution ? turn.replace(/^\[Resolution\]\s*/, "") : turn;
|
|
537
551
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
538
|
-
|
|
552
|
+
_chunkL5RSJE2Icjs.ChatMessageRow,
|
|
539
553
|
{
|
|
540
554
|
displayName: customerName,
|
|
541
555
|
avatarUrl: customerAvatar,
|
|
@@ -564,13 +578,13 @@ function TicketTimelinePanel({ ticket }) {
|
|
|
564
578
|
}
|
|
565
579
|
const engAttachments = mapEngagementAttachments(eng.attachments);
|
|
566
580
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
567
|
-
|
|
581
|
+
_chunkL5RSJE2Icjs.ChatMessageRow,
|
|
568
582
|
{
|
|
569
583
|
displayName: author,
|
|
570
584
|
avatarUrl: avatarSrc,
|
|
571
|
-
timeLabel: eng.createdAt ?
|
|
585
|
+
timeLabel: eng.createdAt ? _chunkL5RSJE2Icjs.formatRelativeTime.call(void 0, eng.createdAt) : null,
|
|
572
586
|
body: stripAttachmentsPreamble(_nullishCoalesce(eng.body, () => ( ""))),
|
|
573
|
-
footer: engAttachments.length > 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mt-2", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
587
|
+
footer: engAttachments.length > 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mt-2", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkL5RSJE2Icjs.TicketAttachmentsList, { attachments: engAttachments, size: "compact" }) }) : null
|
|
574
588
|
},
|
|
575
589
|
eng.id
|
|
576
590
|
);
|
|
@@ -658,7 +672,7 @@ function AssignedAgentRow({
|
|
|
658
672
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-ods-text-secondary uppercase tracking-wider font-medium", children: "Assigned to" }),
|
|
659
673
|
displayLabel ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex items-center gap-1.5 text-ods-text-primary font-medium", children: [
|
|
660
674
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
661
|
-
|
|
675
|
+
_chunkL5RSJE2Icjs.SquareAvatar,
|
|
662
676
|
{
|
|
663
677
|
size: "sm",
|
|
664
678
|
variant: "round",
|
|
@@ -689,7 +703,7 @@ function TicketRow({
|
|
|
689
703
|
const rowRef = _react.useRef.call(void 0, null);
|
|
690
704
|
const handleClick = _react.useCallback.call(void 0, () => {
|
|
691
705
|
onToggle(ticket.id);
|
|
692
|
-
|
|
706
|
+
_chunkL5RSJE2Icjs.scrollElementIntoView.call(void 0, rowRef.current, {
|
|
693
707
|
adjustTargetY: (raw) => {
|
|
694
708
|
if (!rowRef.current) return raw;
|
|
695
709
|
const expandedDrawer = document.querySelector(
|
|
@@ -715,7 +729,7 @@ function TicketRow({
|
|
|
715
729
|
// so the badge accurately reflects "Closed" with a checkmark.
|
|
716
730
|
statusLabel: _nullishCoalesce(ticket.pipeline_stage_label, () => ( void 0)),
|
|
717
731
|
category: _nullishCoalesce(ticket.customer_company, () => ( void 0)),
|
|
718
|
-
timeAgo: ticket.hubspot_updated_at ?
|
|
732
|
+
timeAgo: ticket.hubspot_updated_at ? _chunkL5RSJE2Icjs.formatRelativeTime.call(void 0, ticket.hubspot_updated_at) : void 0,
|
|
719
733
|
// Linked-work chip: surfaced whenever the ticket has a linked
|
|
720
734
|
// ClickUp task. Uses the linked task's own status so the chip text
|
|
721
735
|
// reads "Working" / "Waiting on version release" / etc. — useful
|
|
@@ -730,7 +744,7 @@ function TicketRow({
|
|
|
730
744
|
className: "border-b border-ods-border last:border-b-0",
|
|
731
745
|
children: [
|
|
732
746
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
733
|
-
|
|
747
|
+
_chunkL5RSJE2Icjs.ChatTicketItem,
|
|
734
748
|
{
|
|
735
749
|
ticket: tileData,
|
|
736
750
|
onClick: optimistic ? void 0 : handleClick,
|
|
@@ -799,7 +813,7 @@ function useTicketsList(filters) {
|
|
|
799
813
|
pageSize
|
|
800
814
|
};
|
|
801
815
|
if (statusFilter) body.status = statusFilter;
|
|
802
|
-
const response = await
|
|
816
|
+
const response = await _chunkL5RSJE2Icjs.embedAuthedFetch.call(void 0, FIND_TICKET_ENDPOINT, {
|
|
803
817
|
method: "POST",
|
|
804
818
|
body: JSON.stringify(body)
|
|
805
819
|
});
|
|
@@ -913,7 +927,7 @@ function useTicketActions(options) {
|
|
|
913
927
|
}, []);
|
|
914
928
|
const executeTicketAction = _react.useCallback.call(void 0,
|
|
915
929
|
async (toolName, args) => {
|
|
916
|
-
const res = await
|
|
930
|
+
const res = await _chunkL5RSJE2Icjs.embedAuthedFetch.call(void 0, TICKET_ACTION_ENDPOINT, {
|
|
917
931
|
method: "POST",
|
|
918
932
|
body: JSON.stringify({ tool_name: toolName, args })
|
|
919
933
|
});
|
|
@@ -1298,13 +1312,13 @@ function resolveErrorCode(bodyCode, status) {
|
|
|
1298
1312
|
// src/components/tickets/ticket-center.tsx
|
|
1299
1313
|
|
|
1300
1314
|
function TicketCenter({ toast: toast2 = _chunk5V6MSE3Bcjs.toast } = {}) {
|
|
1301
|
-
const identity =
|
|
1315
|
+
const identity = _chunkL5RSJE2Icjs.useChatIdentity.call(void 0, );
|
|
1302
1316
|
if (identity.isLoading) {
|
|
1303
1317
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TicketCenterSkeleton, {});
|
|
1304
1318
|
}
|
|
1305
1319
|
if (identity.authTier === "anon" || !_optionalChain([identity, 'access', _58 => _58.user, 'optionalAccess', _59 => _59.email])) {
|
|
1306
1320
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1307
|
-
|
|
1321
|
+
_chunkGE64T3JTcjs.EmptyState,
|
|
1308
1322
|
{
|
|
1309
1323
|
type: "generic",
|
|
1310
1324
|
title: "Sign in to manage tickets",
|
|
@@ -1375,7 +1389,7 @@ function TicketCenterAuthed({
|
|
|
1375
1389
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-3 text-xs text-ods-text-secondary", children: [
|
|
1376
1390
|
lastUpdatedAt && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { children: [
|
|
1377
1391
|
"Updated ",
|
|
1378
|
-
|
|
1392
|
+
_chunkL5RSJE2Icjs.formatRelativeTime.call(void 0, new Date(lastUpdatedAt))
|
|
1379
1393
|
] }),
|
|
1380
1394
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1381
1395
|
_chunkXDPSSE4Ocjs.Button,
|
|
@@ -1391,15 +1405,15 @@ function TicketCenterAuthed({
|
|
|
1391
1405
|
)
|
|
1392
1406
|
] })
|
|
1393
1407
|
] }),
|
|
1394
|
-
isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TicketListSkeleton, {}) : merged.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1395
|
-
|
|
1408
|
+
isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TicketListSkeleton, {}) : merged.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkL5RSJE2Icjs.Card, { className: "p-6", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1409
|
+
_chunkGE64T3JTcjs.EmptyState,
|
|
1396
1410
|
{
|
|
1397
1411
|
type: "generic",
|
|
1398
1412
|
title: "No tickets yet",
|
|
1399
1413
|
description: "Open one above to start the conversation.",
|
|
1400
1414
|
showCTA: false
|
|
1401
1415
|
}
|
|
1402
|
-
) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1416
|
+
) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkL5RSJE2Icjs.Card, { className: "overflow-hidden", children: merged.map((ticket) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1403
1417
|
TicketRow,
|
|
1404
1418
|
{
|
|
1405
1419
|
ticket,
|
|
@@ -1419,7 +1433,7 @@ function TicketCenterAuthed({
|
|
|
1419
1433
|
}
|
|
1420
1434
|
function TicketCenterSkeleton() {
|
|
1421
1435
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-6", children: [
|
|
1422
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1436
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkL5RSJE2Icjs.Card, { className: "p-6", children: [
|
|
1423
1437
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXDPSSE4Ocjs.Skeleton, { className: "h-7 w-48 mb-4" }),
|
|
1424
1438
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXDPSSE4Ocjs.Skeleton, { className: "h-10 w-full mb-3" }),
|
|
1425
1439
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXDPSSE4Ocjs.Skeleton, { className: "h-24 w-full" })
|
|
@@ -1428,7 +1442,7 @@ function TicketCenterSkeleton() {
|
|
|
1428
1442
|
] });
|
|
1429
1443
|
}
|
|
1430
1444
|
function TicketListSkeleton() {
|
|
1431
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1445
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkL5RSJE2Icjs.Card, { className: "overflow-hidden", children: [0, 1, 2].map((i) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "h-20 px-4 flex items-center gap-4 border-b border-ods-border last:border-b-0", children: [
|
|
1432
1446
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex-1 flex flex-col gap-2", children: [
|
|
1433
1447
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXDPSSE4Ocjs.Skeleton, { className: "h-4 w-2/3" }),
|
|
1434
1448
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXDPSSE4Ocjs.Skeleton, { className: "h-3 w-full" })
|
|
@@ -1441,7 +1455,7 @@ function TicketListSkeleton() {
|
|
|
1441
1455
|
// src/components/tickets/help-center-list.tsx
|
|
1442
1456
|
|
|
1443
1457
|
|
|
1444
|
-
|
|
1458
|
+
_chunkGE64T3JTcjs.init_unified_pagination.call(void 0, );
|
|
1445
1459
|
|
|
1446
1460
|
// src/components/tickets/help-center-card.tsx
|
|
1447
1461
|
|
|
@@ -1463,7 +1477,7 @@ function HelpCenterCard({
|
|
|
1463
1477
|
const optimistic = isOptimistic(ticket);
|
|
1464
1478
|
const rawStatus = (_nullishCoalesce(ticket.status, () => ( "OPEN"))).toUpperCase();
|
|
1465
1479
|
const priority = (_nullishCoalesce(ticket.priority, () => ( ""))).toUpperCase();
|
|
1466
|
-
const relativeUpdated = ticket.hubspot_updated_at ?
|
|
1480
|
+
const relativeUpdated = ticket.hubspot_updated_at ? _chunkL5RSJE2Icjs.formatRelativeTime.call(void 0, ticket.hubspot_updated_at) : "recently";
|
|
1467
1481
|
const title = (ticket.subject || "").trim() || "(untitled)";
|
|
1468
1482
|
const subtitle = `UPDATED ${relativeUpdated}, #${ticket.external_id || "\u2014"}${ticket.pipeline_stage_label ? `, ${ticket.pipeline_stage_label}` : ""}`;
|
|
1469
1483
|
const description = _nullishCoalesce(_nullishCoalesce(ticket.preview, () => ( ticket.body)), () => ( ""));
|
|
@@ -1476,7 +1490,7 @@ function HelpCenterCard({
|
|
|
1476
1490
|
_react.useEffect.call(void 0, () => {
|
|
1477
1491
|
if (!isExpanded) return;
|
|
1478
1492
|
const raf = requestAnimationFrame(() => {
|
|
1479
|
-
|
|
1493
|
+
_chunkL5RSJE2Icjs.scrollElementIntoView.call(void 0, rowRef.current, {
|
|
1480
1494
|
headerOffset: STICKY_HEADER_OFFSET_PX
|
|
1481
1495
|
});
|
|
1482
1496
|
});
|
|
@@ -1484,16 +1498,16 @@ function HelpCenterCard({
|
|
|
1484
1498
|
}, [isExpanded]);
|
|
1485
1499
|
const rightBadges = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
1486
1500
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1487
|
-
|
|
1501
|
+
_chunkL5RSJE2Icjs.StatusBadge,
|
|
1488
1502
|
{
|
|
1489
1503
|
text: rawStatus,
|
|
1490
|
-
colorScheme:
|
|
1504
|
+
colorScheme: _chunkL5RSJE2Icjs.getStatusColorScheme.call(void 0, rawStatus),
|
|
1491
1505
|
variant: "card",
|
|
1492
1506
|
className: "border border-ods-border"
|
|
1493
1507
|
}
|
|
1494
1508
|
),
|
|
1495
1509
|
priority && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1496
|
-
|
|
1510
|
+
_chunkL5RSJE2Icjs.StatusBadge,
|
|
1497
1511
|
{
|
|
1498
1512
|
text: priority,
|
|
1499
1513
|
colorScheme: mapPriorityScheme(priority),
|
|
@@ -1520,7 +1534,7 @@ function HelpCenterCard({
|
|
|
1520
1534
|
"aria-controls": isExpanded ? `help-center-drawer-${ticket.id}` : void 0,
|
|
1521
1535
|
className: "w-full text-left p-[12px] md:p-[16px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ods-accent focus-visible:ring-inset disabled:cursor-default",
|
|
1522
1536
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1523
|
-
|
|
1537
|
+
_chunkFZZBCRIDcjs.DevCardRowContent,
|
|
1524
1538
|
{
|
|
1525
1539
|
title,
|
|
1526
1540
|
subtitle,
|
|
@@ -1595,7 +1609,7 @@ function HelpCenterCreateForm({
|
|
|
1595
1609
|
const [subject, setSubject] = _react.useState.call(void 0, "");
|
|
1596
1610
|
const [subjectError, setSubjectError] = _react.useState.call(void 0, null);
|
|
1597
1611
|
const subjectField = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col", children: [
|
|
1598
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1612
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkL5RSJE2Icjs.Label, { htmlFor: "help-center-subject", children: [
|
|
1599
1613
|
"Subject",
|
|
1600
1614
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-ods-accent", children: "*" })
|
|
1601
1615
|
] }),
|
|
@@ -1627,7 +1641,7 @@ function HelpCenterCreateForm({
|
|
|
1627
1641
|
)
|
|
1628
1642
|
] });
|
|
1629
1643
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1630
|
-
|
|
1644
|
+
_chunkTCJ5B2ZDcjs.ContactForm,
|
|
1631
1645
|
{
|
|
1632
1646
|
title: "Open a new ticket",
|
|
1633
1647
|
footerText: "The support team typically responds within one business day.",
|
|
@@ -1665,7 +1679,7 @@ function HelpCenterCreateForm({
|
|
|
1665
1679
|
// src/components/tickets/help-center-list.tsx
|
|
1666
1680
|
|
|
1667
1681
|
function HelpCenterList({ toast: toast2 = _chunk5V6MSE3Bcjs.toast } = {}) {
|
|
1668
|
-
const identity =
|
|
1682
|
+
const identity = _chunkL5RSJE2Icjs.useChatIdentity.call(void 0, );
|
|
1669
1683
|
const searchParams = _chunkG7UE6RKVcjs.useSearchParams.call(void 0, );
|
|
1670
1684
|
const router = _chunkG7UE6RKVcjs.useRouter.call(void 0, );
|
|
1671
1685
|
const pathname = _chunkG7UE6RKVcjs.usePathname.call(void 0, );
|
|
@@ -1675,11 +1689,11 @@ function HelpCenterList({ toast: toast2 = _chunk5V6MSE3Bcjs.toast } = {}) {
|
|
|
1675
1689
|
const rawPage = Number(searchParams.get("page"));
|
|
1676
1690
|
const page = Number.isFinite(rawPage) && rawPage > 0 ? Math.floor(rawPage) : 1;
|
|
1677
1691
|
if (identity.isLoading) {
|
|
1678
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1692
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkFZZBCRIDcjs.DevSectionPage, { sectionKey: "tickets", preControls: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, HelpCenterCreateFormSkeleton, {}), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkFZZBCRIDcjs.DevCardRowSkeletonList, {}) });
|
|
1679
1693
|
}
|
|
1680
1694
|
if (identity.authTier === "anon" || !_optionalChain([identity, 'access', _60 => _60.user, 'optionalAccess', _61 => _61.email])) {
|
|
1681
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1682
|
-
|
|
1695
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkFZZBCRIDcjs.DevSectionPage, { sectionKey: "tickets", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1696
|
+
_chunkGE64T3JTcjs.EmptyState,
|
|
1683
1697
|
{
|
|
1684
1698
|
type: "generic",
|
|
1685
1699
|
title: "Sign in to manage tickets",
|
|
@@ -1804,15 +1818,15 @@ function HelpCenterListAuthed({
|
|
|
1804
1818
|
] }),
|
|
1805
1819
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXDPSSE4Ocjs.Button, { type: "button", variant: "accent", onClick: () => refetch(), children: "Retry" })
|
|
1806
1820
|
] }),
|
|
1807
|
-
!error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-full", children: isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1821
|
+
!error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-full", children: isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkFZZBCRIDcjs.DevCardRowSkeletonList, {}) : !hasResults && isFetching ? (
|
|
1808
1822
|
// Bridge state — background refetch in flight and the
|
|
1809
1823
|
// optimistic placeholder was just removed by the mutation
|
|
1810
1824
|
// callback. Without this branch "No tickets yet" would flash
|
|
1811
1825
|
// for ~50ms between `removeOptimistic` and the server
|
|
1812
1826
|
// response landing.
|
|
1813
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1827
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkFZZBCRIDcjs.DevCardRowSkeletonList, { rows: 1 })
|
|
1814
1828
|
) : !hasResults ? hasActiveFilters ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1815
|
-
|
|
1829
|
+
_chunkGE64T3JTcjs.EmptyState,
|
|
1816
1830
|
{
|
|
1817
1831
|
type: "search",
|
|
1818
1832
|
title: "No tickets found",
|
|
@@ -1827,7 +1841,7 @@ function HelpCenterListAuthed({
|
|
|
1827
1841
|
}
|
|
1828
1842
|
}
|
|
1829
1843
|
) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1830
|
-
|
|
1844
|
+
_chunkGE64T3JTcjs.EmptyState,
|
|
1831
1845
|
{
|
|
1832
1846
|
type: "generic",
|
|
1833
1847
|
title: "No tickets yet",
|
|
@@ -1861,9 +1875,9 @@ function HelpCenterListAuthed({
|
|
|
1861
1875
|
ticket.id
|
|
1862
1876
|
)) })
|
|
1863
1877
|
) }),
|
|
1864
|
-
!error && totalPages > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1878
|
+
!error && totalPages > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGE64T3JTcjs.UnifiedPagination, { currentPage: page, totalPages })
|
|
1865
1879
|
] });
|
|
1866
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1880
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkFZZBCRIDcjs.DevSectionPage, { sectionKey: "tickets", preControls: form, children: body });
|
|
1867
1881
|
}
|
|
1868
1882
|
|
|
1869
1883
|
|