@qoretechnologies/reqraft 0.10.7 → 0.10.9-pr.74.g452d4d3

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.
Files changed (55) hide show
  1. package/dist/components/supportTicket/AttachmentChips.d.ts +7 -0
  2. package/dist/components/supportTicket/AttachmentChips.d.ts.map +1 -0
  3. package/dist/components/supportTicket/AttachmentChips.js +26 -0
  4. package/dist/components/supportTicket/AttachmentChips.js.map +1 -0
  5. package/dist/components/supportTicket/InterfaceReferenceTags.d.ts +25 -0
  6. package/dist/components/supportTicket/InterfaceReferenceTags.d.ts.map +1 -0
  7. package/dist/components/supportTicket/InterfaceReferenceTags.js +28 -0
  8. package/dist/components/supportTicket/InterfaceReferenceTags.js.map +1 -0
  9. package/dist/components/supportTicket/TicketMetaTags.d.ts +24 -0
  10. package/dist/components/supportTicket/TicketMetaTags.d.ts.map +1 -0
  11. package/dist/components/supportTicket/TicketMetaTags.js +21 -0
  12. package/dist/components/supportTicket/TicketMetaTags.js.map +1 -0
  13. package/dist/components/supportTicket/TicketReplyBox.d.ts +59 -0
  14. package/dist/components/supportTicket/TicketReplyBox.d.ts.map +1 -0
  15. package/dist/components/supportTicket/TicketReplyBox.js +169 -0
  16. package/dist/components/supportTicket/TicketReplyBox.js.map +1 -0
  17. package/dist/components/supportTicket/fileToAttachment.d.ts +9 -0
  18. package/dist/components/supportTicket/fileToAttachment.d.ts.map +1 -0
  19. package/dist/components/supportTicket/fileToAttachment.js +28 -0
  20. package/dist/components/supportTicket/fileToAttachment.js.map +1 -0
  21. package/dist/components/supportTicket/index.d.ts +7 -0
  22. package/dist/components/supportTicket/index.d.ts.map +1 -0
  23. package/dist/components/supportTicket/index.js +23 -0
  24. package/dist/components/supportTicket/index.js.map +1 -0
  25. package/dist/components/supportTicket/meta.d.ts +55 -0
  26. package/dist/components/supportTicket/meta.d.ts.map +1 -0
  27. package/dist/components/supportTicket/meta.js +77 -0
  28. package/dist/components/supportTicket/meta.js.map +1 -0
  29. package/dist/components/ticketThread/TicketThread.d.ts +36 -0
  30. package/dist/components/ticketThread/TicketThread.d.ts.map +1 -0
  31. package/dist/components/ticketThread/TicketThread.js +137 -0
  32. package/dist/components/ticketThread/TicketThread.js.map +1 -0
  33. package/dist/components/ticketThread/index.d.ts +3 -0
  34. package/dist/components/ticketThread/index.d.ts.map +1 -0
  35. package/dist/components/ticketThread/index.js +6 -0
  36. package/dist/components/ticketThread/index.js.map +1 -0
  37. package/dist/index.d.ts +2 -0
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +2 -0
  40. package/dist/index.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/components/supportTicket/AttachmentChips.tsx +50 -0
  43. package/src/components/supportTicket/InterfaceReferenceTags.stories.tsx +102 -0
  44. package/src/components/supportTicket/InterfaceReferenceTags.tsx +62 -0
  45. package/src/components/supportTicket/TicketMetaTags.stories.tsx +71 -0
  46. package/src/components/supportTicket/TicketMetaTags.tsx +58 -0
  47. package/src/components/supportTicket/TicketReplyBox.stories.tsx +111 -0
  48. package/src/components/supportTicket/TicketReplyBox.tsx +251 -0
  49. package/src/components/supportTicket/fileToAttachment.ts +24 -0
  50. package/src/components/supportTicket/index.ts +6 -0
  51. package/src/components/supportTicket/meta.ts +135 -0
  52. package/src/components/ticketThread/TicketThread.stories.tsx +192 -0
  53. package/src/components/ticketThread/TicketThread.tsx +331 -0
  54. package/src/components/ticketThread/index.ts +6 -0
  55. package/src/index.tsx +2 -0
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultInterfaceIcon = exports.isTicketReplyable = exports.REPLYABLE_STATUSES = exports.ticketStatusLabel = exports.TICKET_AUDIT_ACTION_META = exports.TICKET_CATEGORY_META = exports.TICKET_PRIORITY_META = exports.TICKET_STATUS_META = void 0;
4
+ exports.TICKET_STATUS_META = {
5
+ new: { label: 'New', intent: 'info', icon: 'SparklingLine' },
6
+ open: { label: 'Open', intent: 'pending', icon: 'Chat3Line' },
7
+ awaiting_customer: {
8
+ label: 'Awaiting customer',
9
+ customerLabel: 'Awaiting your reply',
10
+ intent: 'warning',
11
+ icon: 'UserReceivedLine',
12
+ },
13
+ resolved: { label: 'Resolved', intent: 'success', icon: 'CheckLine' },
14
+ closed: { label: 'Closed', intent: 'muted', icon: 'CloseCircleLine' },
15
+ };
16
+ exports.TICKET_PRIORITY_META = {
17
+ low: { label: 'Low', intent: 'muted', icon: 'ArrowDownLine' },
18
+ normal: { label: 'Normal', intent: 'info', icon: 'SubtractLine' },
19
+ high: { label: 'High', intent: 'warning', icon: 'ArrowUpLine' },
20
+ urgent: { label: 'Urgent', intent: 'danger', icon: 'AlarmWarningLine' },
21
+ };
22
+ exports.TICKET_CATEGORY_META = {
23
+ bug: { label: 'Bug', intent: 'danger', icon: 'BugLine' },
24
+ question: { label: 'Question', intent: 'info', icon: 'QuestionLine' },
25
+ billing: { label: 'Billing', intent: 'warning', icon: 'BankCardLine' },
26
+ feature: { label: 'Feature request', intent: 'success', icon: 'LightbulbLine' },
27
+ other: { label: 'Other', intent: 'muted', icon: 'MoreLine' },
28
+ };
29
+ /** Staff-only audit trail vocabulary (used by the admin-portal staff surface).
30
+ * These are exactly the actions the backend writes (qorus-api
31
+ * `QorusSaasTicketStore::insertAudit`): a public reply, an internal note, a
32
+ * status change, an assignment, or `updated` (a priority/category change). */
33
+ exports.TICKET_AUDIT_ACTION_META = {
34
+ replied: { label: 'Replied', intent: 'success', icon: 'ReplyLine' },
35
+ noted: { label: 'Internal note', intent: 'info', icon: 'StickyNoteLine' },
36
+ status_changed: { label: 'Status changed', intent: 'warning', icon: 'ExchangeLine' },
37
+ assigned: { label: 'Assigned', intent: 'pending', icon: 'UserFollowLine' },
38
+ updated: { label: 'Updated', intent: 'muted', icon: 'Edit2Line' },
39
+ };
40
+ /** The status label for a given viewer — the customer sees "Awaiting your reply"
41
+ * where staff see "Awaiting customer"; all other values are audience-neutral. */
42
+ var ticketStatusLabel = function (status, viewerRole) {
43
+ var meta = exports.TICKET_STATUS_META[status];
44
+ return viewerRole === 'customer' && meta.customerLabel ? meta.customerLabel : meta.label;
45
+ };
46
+ exports.ticketStatusLabel = ticketStatusLabel;
47
+ /** A reply may be sent while a ticket is in any state except `closed`. */
48
+ exports.REPLYABLE_STATUSES = [
49
+ 'new',
50
+ 'open',
51
+ 'awaiting_customer',
52
+ 'resolved',
53
+ ];
54
+ /** Whether a ticket can still be replied to (closed ⇒ no). */
55
+ var isTicketReplyable = function (status) { return status !== 'closed'; };
56
+ exports.isTicketReplyable = isTicketReplyable;
57
+ // Built-in per-kind icons for referenced interfaces, kept in step with the
58
+ // qorus-ide interface vocabulary. Used when a consumer doesn't pass its own
59
+ // `resolveInterfaceIcon`, so the staff view and the Qonsole renderer show the
60
+ // same chips as the customer view without each re-declaring the mapping.
61
+ var DEFAULT_INTERFACE_ICONS = {
62
+ workflow: 'GitBranchLine',
63
+ service: 'ServerLine',
64
+ job: 'CalendarLine',
65
+ fsm: 'DashboardLine',
66
+ connection: 'Plug2Line',
67
+ mapper: 'MindMap',
68
+ class: 'CodeSLine',
69
+ 'value-map': 'BringToFront',
70
+ 'ai-collection': 'FileMarkedLine',
71
+ 'ai-endpoint': 'RobotLine',
72
+ 'ai-guardrail': 'ShieldLine',
73
+ };
74
+ /** Default per-kind icon for a referenced interface, with a generic fallback. */
75
+ var defaultInterfaceIcon = function (kind) { var _a; return (_a = DEFAULT_INTERFACE_ICONS[kind]) !== null && _a !== void 0 ? _a : 'CodeBoxLine'; };
76
+ exports.defaultInterfaceIcon = defaultInterfaceIcon;
77
+ //# sourceMappingURL=meta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta.js","sourceRoot":"","sources":["../../../src/components/supportTicket/meta.ts"],"names":[],"mappings":";;;AAgCa,QAAA,kBAAkB,GAA2C;IACxE,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE;IAC5D,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE;IAC7D,iBAAiB,EAAE;QACjB,KAAK,EAAE,mBAAmB;QAC1B,aAAa,EAAE,qBAAqB;QACpC,MAAM,EAAE,SAAS;QACjB,IAAI,EAAE,kBAAkB;KACzB;IACD,QAAQ,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE;IACrE,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE;CACtE,CAAC;AAEW,QAAA,oBAAoB,GAA6C;IAC5E,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE;IAC7D,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE;IACjE,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE;IAC/D,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,kBAAkB,EAAE;CACxE,CAAC;AAEW,QAAA,oBAAoB,GAA6C;IAC5E,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE;IACxD,QAAQ,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE;IACrE,OAAO,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE;IACtE,OAAO,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,eAAe,EAAE;IAC/E,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE;CAC7D,CAAC;AAEF;;;+EAG+E;AAClE,QAAA,wBAAwB,GAAgD;IACnF,OAAO,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE;IACnE,KAAK,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,EAAE;IACzE,cAAc,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE;IACpF,QAAQ,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,gBAAgB,EAAE;IAC1E,OAAO,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE;CAClE,CAAC;AAEF;kFACkF;AAC3E,IAAM,iBAAiB,GAAG,UAC/B,MAAqB,EACrB,UAA8B;IAE9B,IAAM,IAAI,GAAG,0BAAkB,CAAC,MAAM,CAAC,CAAC;IACxC,OAAO,UAAU,KAAK,UAAU,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;AAC3F,CAAC,CAAC;AANW,QAAA,iBAAiB,qBAM5B;AAEF,0EAA0E;AAC7D,QAAA,kBAAkB,GAAoB;IACjD,KAAK;IACL,MAAM;IACN,mBAAmB;IACnB,UAAU;CACX,CAAC;AAEF,8DAA8D;AACvD,IAAM,iBAAiB,GAAG,UAAC,MAAqB,IAAc,OAAA,MAAM,KAAK,QAAQ,EAAnB,CAAmB,CAAC;AAA5E,QAAA,iBAAiB,qBAA2D;AAuBzF,2EAA2E;AAC3E,4EAA4E;AAC5E,8EAA8E;AAC9E,yEAAyE;AACzE,IAAM,uBAAuB,GAAoC;IAC/D,QAAQ,EAAE,eAAe;IACzB,OAAO,EAAE,YAAY;IACrB,GAAG,EAAE,cAAc;IACnB,GAAG,EAAE,eAAe;IACpB,UAAU,EAAE,WAAW;IACvB,MAAM,EAAE,SAAS;IACjB,KAAK,EAAE,WAAW;IAClB,WAAW,EAAE,cAAc;IAC3B,eAAe,EAAE,gBAAgB;IACjC,aAAa,EAAE,WAAW;IAC1B,cAAc,EAAE,YAAY;CAC7B,CAAC;AAEF,iFAAiF;AAC1E,IAAM,oBAAoB,GAAG,UAAC,IAAY,YAC/C,OAAA,MAAA,uBAAuB,CAAC,IAAI,CAAC,mCAAI,aAAa,CAAA,EAAA,CAAC;AADpC,QAAA,oBAAoB,wBACgB"}
@@ -0,0 +1,36 @@
1
+ import { IReqoreIconName } from '@qoretechnologies/reqore/dist/types/icons';
2
+ import { IInterfaceReference, TTicketMessageAuthor, TTicketViewerRole } from '../supportTicket';
3
+ export interface ITicketThreadAttachment {
4
+ attachment_id: string;
5
+ filename: string;
6
+ content_type: string;
7
+ size_bytes: number;
8
+ }
9
+ export interface ITicketThreadMessage {
10
+ message_id: string;
11
+ author_type: TTicketMessageAuthor;
12
+ author_id: string;
13
+ body: string;
14
+ internal?: boolean;
15
+ created: string;
16
+ attachments?: ITicketThreadAttachment[];
17
+ /** Qorus interfaces this message references, as `{kind, name}` snapshots. */
18
+ referenced_interfaces?: IInterfaceReference[];
19
+ }
20
+ export interface ITicketThreadProps {
21
+ messages: ITicketThreadMessage[];
22
+ /** which side "you" sit on + how internal notes render. */
23
+ viewerRole?: TTicketViewerRole;
24
+ loading?: boolean;
25
+ /** download an attachment (the consumer wires this to its API). */
26
+ onDownloadAttachment?: (attachmentId: string, filename: string) => void;
27
+ /** resolve a per-kind icon for a referenced interface. Consumers with their own
28
+ * icon vocabulary (e.g. the qorus-ide IDE) pass one; when omitted, a built-in
29
+ * per-kind default is used so every surface shows consistent chips. */
30
+ resolveInterfaceIcon?: (kind: string) => IReqoreIconName;
31
+ /** open a referenced interface; reference chips are static when omitted (e.g. the staff
32
+ * view, which can't reach the customer's instance, leaves this out). */
33
+ onInterfaceClick?: (reference: IInterfaceReference) => void;
34
+ }
35
+ export declare const TicketThread: ({ messages, viewerRole, loading, onDownloadAttachment, resolveInterfaceIcon, onInterfaceClick, }: ITicketThreadProps) => import("react/jsx-runtime").JSX.Element;
36
+ //# sourceMappingURL=TicketThread.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TicketThread.d.ts","sourceRoot":"","sources":["../../../src/components/ticketThread/TicketThread.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAC;AAG5E,OAAO,EACL,mBAAmB,EAEnB,oBAAoB,EACpB,iBAAiB,EAClB,MAAM,kBAAkB,CAAC;AAuB1B,MAAM,WAAW,uBAAuB;IACtC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,oBAAoB,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACxC,6EAA6E;IAC7E,qBAAqB,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC/C;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC,2DAA2D;IAC3D,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,oBAAoB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACxE;;4EAEwE;IACxE,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,eAAe,CAAC;IACzD;6EACyE;IACzE,gBAAgB,CAAC,EAAE,CAAC,SAAS,EAAE,mBAAmB,KAAK,IAAI,CAAC;CAC7D;AA2LD,eAAO,MAAM,YAAY,qGAOtB,kBAAkB,4CA8DpB,CAAC"}
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
3
+ if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
4
+ return cooked;
5
+ };
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.TicketThread = void 0;
11
+ var jsx_runtime_1 = require("react/jsx-runtime");
12
+ var reqore_1 = require("@qoretechnologies/reqore");
13
+ var react_markdown_1 = __importDefault(require("react-markdown"));
14
+ var styled_components_1 = __importDefault(require("styled-components"));
15
+ var supportTicket_1 = require("../supportTicket");
16
+ var AUTHOR_META = {
17
+ customer: { icon: 'User3Line' },
18
+ staff: { icon: 'CustomerService2Line' },
19
+ system: { icon: 'InformationLine' },
20
+ };
21
+ /** Compact relative-time label from an ISO timestamp. */
22
+ var timeAgo = function (iso) {
23
+ if (!iso) {
24
+ return '';
25
+ }
26
+ var then = new Date(iso).getTime();
27
+ if (Number.isNaN(then)) {
28
+ return '';
29
+ }
30
+ var seconds = Math.round((then - Date.now()) / 1000);
31
+ var rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
32
+ var units = [
33
+ ['year', 31536000],
34
+ ['month', 2592000],
35
+ ['week', 604800],
36
+ ['day', 86400],
37
+ ['hour', 3600],
38
+ ['minute', 60],
39
+ ['second', 1],
40
+ ];
41
+ for (var _i = 0, units_1 = units; _i < units_1.length; _i++) {
42
+ var _a = units_1[_i], unit = _a[0], per = _a[1];
43
+ if (Math.abs(seconds) >= per || unit === 'second') {
44
+ return rtf.format(Math.round(seconds / per), unit);
45
+ }
46
+ }
47
+ return '';
48
+ };
49
+ /** Human-readable file size, e.g. "12.3 KB". */
50
+ var formatBytes = function (bytes) {
51
+ if (bytes < 1024) {
52
+ return "".concat(bytes, " B");
53
+ }
54
+ var units = ['KB', 'MB', 'GB'];
55
+ var value = bytes / 1024;
56
+ var unit = 0;
57
+ while (value >= 1024 && unit < units.length - 1) {
58
+ value /= 1024;
59
+ unit += 1;
60
+ }
61
+ return "".concat(value.toFixed(1), " ").concat(units[unit]);
62
+ };
63
+ /** The label shown above a run of messages. Customer view masks staff identity as
64
+ * "Qorus Support"; staff view shows the real author with a role prefix. Internal
65
+ * notes always label as "Internal note" regardless of viewer. */
66
+ var authorLabel = function (message, viewerRole) {
67
+ if (message.internal) {
68
+ return 'Internal note';
69
+ }
70
+ if (viewerRole === 'customer') {
71
+ return message.author_type === 'customer' ? 'You' : 'Qorus Support';
72
+ }
73
+ return "".concat(message.author_type === 'staff' ? 'Support' : 'Customer', " \u00B7 ").concat(message.author_id);
74
+ };
75
+ /** Per-role bubble tint: staff green, customer blue, internal notes amber. */
76
+ var bubbleIntent = function (message) {
77
+ if (message.internal) {
78
+ return 'warning';
79
+ }
80
+ return message.author_type === 'staff' ? 'success' : 'info';
81
+ };
82
+ var StyledThread = styled_components_1.default.div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n display: flex;\n flex-direction: column;\n gap: 14px;\n width: 100%;\n"], ["\n display: flex;\n flex-direction: column;\n gap: 14px;\n width: 100%;\n"])));
83
+ // System messages read as a centered muted note between bubble clusters; the
84
+ // nested rule flattens react-markdown's own <p> margins so it sits on one line.
85
+ var StyledSystemRow = styled_components_1.default.div(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n font-size: 11px;\n opacity: 0.55;\n text-align: center;\n p {\n margin: 0;\n }\n"], ["\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n font-size: 11px;\n opacity: 0.55;\n text-align: center;\n p {\n margin: 0;\n }\n"])));
86
+ /** The inner content of a message bubble: an optional author label (shown once
87
+ * per same-author run), the markdown body, attachment chips, and reference chips. */
88
+ var BubbleContent = function (_a) {
89
+ var _b, _c;
90
+ var message = _a.message, showLabel = _a.showLabel, viewerRole = _a.viewerRole, onDownloadAttachment = _a.onDownloadAttachment, resolveInterfaceIcon = _a.resolveInterfaceIcon, onInterfaceClick = _a.onInterfaceClick;
91
+ var isInternal = !!message.internal;
92
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [showLabel ? ((0, jsx_runtime_1.jsxs)(reqore_1.ReqoreControlGroup, { verticalAlign: 'center', gapSize: 'tiny', style: { marginBottom: 4 }, children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreIcon, { icon: isInternal ? 'EyeOffLine' : AUTHOR_META[message.author_type].icon, size: 'tiny' }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreP, { size: 'small', effect: { weight: 'bold', opacity: 0.7 }, children: authorLabel(message, viewerRole) })] })) : null, (0, jsx_runtime_1.jsx)(react_markdown_1.default, { children: message.body }), ((_b = message.attachments) === null || _b === void 0 ? void 0 : _b.length) ? ((0, jsx_runtime_1.jsx)(reqore_1.ReqoreControlGroup, { wrap: true, gapSize: 'small', style: { marginTop: 8 }, children: message.attachments.map(function (a) { return ((0, jsx_runtime_1.jsx)(reqore_1.ReqoreButton, { icon: 'Download2Line', size: 'small', flat: true, badge: formatBytes(a.size_bytes), tooltip: "".concat(a.content_type, " \u00B7 download"), onClick: function () { return onDownloadAttachment === null || onDownloadAttachment === void 0 ? void 0 : onDownloadAttachment(a.attachment_id, a.filename); }, children: a.filename }, a.attachment_id)); }) })) : null, ((_c = message.referenced_interfaces) === null || _c === void 0 ? void 0 : _c.length) ? ((0, jsx_runtime_1.jsx)("div", { style: { marginTop: 8 }, children: (0, jsx_runtime_1.jsx)(supportTicket_1.InterfaceReferenceTags, { references: message.referenced_interfaces, resolveInterfaceIcon: resolveInterfaceIcon, onInterfaceClick: onInterfaceClick }) })) : null] }));
93
+ };
94
+ /** Split the thread into centered system lines and runs of consecutive
95
+ * non-system messages (each run becomes one auto-clustered bubble group). */
96
+ var toSegments = function (messages) {
97
+ var segments = [];
98
+ for (var _i = 0, messages_1 = messages; _i < messages_1.length; _i++) {
99
+ var message = messages_1[_i];
100
+ if (message.author_type === 'system') {
101
+ segments.push({ kind: 'system', message: message });
102
+ continue;
103
+ }
104
+ var last = segments[segments.length - 1];
105
+ if ((last === null || last === void 0 ? void 0 : last.kind) === 'bubbles') {
106
+ last.messages.push(message);
107
+ }
108
+ else {
109
+ segments.push({ kind: 'bubbles', messages: [message] });
110
+ }
111
+ }
112
+ return segments;
113
+ };
114
+ var TicketThread = function (_a) {
115
+ var messages = _a.messages, _b = _a.viewerRole, viewerRole = _b === void 0 ? 'customer' : _b, loading = _a.loading, onDownloadAttachment = _a.onDownloadAttachment, resolveInterfaceIcon = _a.resolveInterfaceIcon, onInterfaceClick = _a.onInterfaceClick;
116
+ if (loading) {
117
+ return ((0, jsx_runtime_1.jsx)(reqore_1.ReqoreControlGroup, { vertical: true, fluid: true, horizontalAlign: 'center', style: { padding: '24px 0' }, children: (0, jsx_runtime_1.jsx)(reqore_1.ReqoreSpinner, { type: 5, iconColor: 'info', size: 'big', children: "Loading conversation\u2026" }) }));
118
+ }
119
+ if (!messages.length) {
120
+ return (0, jsx_runtime_1.jsx)(reqore_1.ReqoreEmptyState, { icon: 'Chat3Line', title: 'No messages yet' });
121
+ }
122
+ return ((0, jsx_runtime_1.jsxs)(StyledThread, { children: [toSegments(messages).map(function (segment, index) {
123
+ return segment.kind === 'system' ? ((0, jsx_runtime_1.jsxs)(StyledSystemRow, { children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreIcon, { icon: 'InformationLine', size: 'tiny' }), (0, jsx_runtime_1.jsx)(react_markdown_1.default, { children: segment.message.body })] }, segment.message.message_id)) : ((0, jsx_runtime_1.jsx)(reqore_1.ReqoreBubbleGroup, { children: segment.messages.map(function (message, i) {
124
+ var previous = segment.messages[i - 1];
125
+ // Label once per same-author run; an internal note always gets its
126
+ // own label even from the same staff author.
127
+ var showLabel = !previous ||
128
+ previous.author_type !== message.author_type ||
129
+ !!previous.internal !== !!message.internal;
130
+ var isSelf = message.author_type === viewerRole;
131
+ return ((0, jsx_runtime_1.jsx)(reqore_1.ReqoreBubble, { align: isSelf ? 'right' : 'left', intent: bubbleIntent(message), minimal: !message.internal, flat: !message.internal, timestamp: timeAgo(message.created) || undefined, children: (0, jsx_runtime_1.jsx)(BubbleContent, { message: message, showLabel: showLabel, viewerRole: viewerRole, onDownloadAttachment: onDownloadAttachment, resolveInterfaceIcon: resolveInterfaceIcon, onInterfaceClick: onInterfaceClick }) }, message.message_id));
132
+ }) }, "group-".concat(index)));
133
+ }), (0, jsx_runtime_1.jsxs)(reqore_1.ReqoreP, { size: 'tiny', effect: { opacity: 0.5, textAlign: 'center' }, children: [messages.length, " message", messages.length === 1 ? '' : 's'] })] }));
134
+ };
135
+ exports.TicketThread = TicketThread;
136
+ var templateObject_1, templateObject_2;
137
+ //# sourceMappingURL=TicketThread.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TicketThread.js","sourceRoot":"","sources":["../../../src/components/ticketThread/TicketThread.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { TicketThread } from './TicketThread';
2
+ export type { ITicketThreadAttachment, ITicketThreadMessage, ITicketThreadProps, } from './TicketThread';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ticketThread/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EACV,uBAAuB,EACvB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TicketThread = void 0;
4
+ var TicketThread_1 = require("./TicketThread");
5
+ Object.defineProperty(exports, "TicketThread", { enumerable: true, get: function () { return TicketThread_1.TicketThread; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/ticketThread/index.ts"],"names":[],"mappings":";;;AAAA,+CAA8C;AAArC,4GAAA,YAAY,OAAA"}
package/dist/index.d.ts CHANGED
@@ -20,4 +20,6 @@ export type { ILspCompletionItem, ILspDiagnostic, ILspMarkupContent, ILspParamet
20
20
  export * from './components/smartEditor';
21
21
  export * from './components/dpqlEditor';
22
22
  export * from './components/qonsoleSmartInput';
23
+ export * from './components/supportTicket';
24
+ export * from './components/ticketThread';
23
25
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EACL,aAAa,EACb,uBAAuB,EACvB,UAAU,EACV,gBAAgB,EAChB,cAAc,EACd,4BAA4B,EAC5B,gCAAgC,GACjC,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,YAAY,EACV,gBAAgB,EAChB,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,GACjB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,YAAY,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACxE,cAAc,mCAAmC,CAAC;AAClD,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,kBAAkB,GACnB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,gBAAgB,IAAI,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC/F,YAAY,EACV,YAAY,EACZ,iBAAiB,GAClB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,YAAY,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAClE,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,wBAAwB,EACxB,YAAY,EACZ,SAAS,EACT,iBAAiB,EACjB,wBAAwB,EACxB,sBAAsB,EACtB,iBAAiB,EACjB,wBAAwB,EACxB,YAAY,EACZ,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AACjC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EACL,aAAa,EACb,uBAAuB,EACvB,UAAU,EACV,gBAAgB,EAChB,cAAc,EACd,4BAA4B,EAC5B,gCAAgC,GACjC,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,YAAY,EACV,gBAAgB,EAChB,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,GACjB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,YAAY,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACxE,cAAc,mCAAmC,CAAC;AAClD,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,kBAAkB,GACnB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,gBAAgB,IAAI,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC/F,YAAY,EACV,YAAY,EACZ,iBAAiB,GAClB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,YAAY,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAClE,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,wBAAwB,EACxB,YAAY,EACZ,SAAS,EACT,iBAAiB,EACjB,wBAAwB,EACxB,sBAAsB,EACtB,iBAAiB,EACjB,wBAAwB,EACxB,YAAY,EACZ,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AACjC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -46,4 +46,6 @@ Object.defineProperty(exports, "ReqraftLspClient", { enumerable: true, get: func
46
46
  __exportStar(require("./components/smartEditor"), exports);
47
47
  __exportStar(require("./components/dpqlEditor"), exports);
48
48
  __exportStar(require("./components/qonsoleSmartInput"), exports);
49
+ __exportStar(require("./components/supportTicket"), exports);
50
+ __exportStar(require("./components/ticketThread"), exports);
49
51
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,oDAAkC;AAClC,uDAAqC;AACrC,qDAQ+B;AAP7B,4GAAA,aAAa,OAAA;AACb,sHAAA,uBAAuB,OAAA;AACvB,yGAAA,UAAU,OAAA;AACV,+GAAA,gBAAgB,OAAA;AAChB,6GAAA,cAAc,OAAA;AACd,2HAAA,4BAA4B,OAAA;AAC5B,+HAAA,gCAAgC,OAAA;AAGlC,+CAAqD;AAA5C,mGAAA,WAAW,OAAA;AAQpB,sDAAqD;AAA5C,oGAAA,QAAQ,OAAA;AAEjB,4DAAkE;AAAzD,+GAAA,iBAAiB,OAAA;AAE1B,oEAAkD;AAClD,+DAIqC;AAHnC,oHAAA,iBAAiB,OAAA;AACjB,kHAAA,eAAe,OAAA;AACf,qHAAA,kBAAkB,OAAA;AAEpB,gEAA+F;AAAtF,sHAAA,gBAAgB,OAA2B;AAKpD,uCAAsC;AAA7B,8FAAA,KAAK,OAAA;AACd,oDAAkC;AAClC,+CAAqD;AAA5C,6GAAA,gBAAgB,OAAA;AAiBzB,2DAAyC;AACzC,0DAAwC;AACxC,iEAA+C"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,oDAAkC;AAClC,uDAAqC;AACrC,qDAQ+B;AAP7B,4GAAA,aAAa,OAAA;AACb,sHAAA,uBAAuB,OAAA;AACvB,yGAAA,UAAU,OAAA;AACV,+GAAA,gBAAgB,OAAA;AAChB,6GAAA,cAAc,OAAA;AACd,2HAAA,4BAA4B,OAAA;AAC5B,+HAAA,gCAAgC,OAAA;AAGlC,+CAAqD;AAA5C,mGAAA,WAAW,OAAA;AAQpB,sDAAqD;AAA5C,oGAAA,QAAQ,OAAA;AAEjB,4DAAkE;AAAzD,+GAAA,iBAAiB,OAAA;AAE1B,oEAAkD;AAClD,+DAIqC;AAHnC,oHAAA,iBAAiB,OAAA;AACjB,kHAAA,eAAe,OAAA;AACf,qHAAA,kBAAkB,OAAA;AAEpB,gEAA+F;AAAtF,sHAAA,gBAAgB,OAA2B;AAKpD,uCAAsC;AAA7B,8FAAA,KAAK,OAAA;AACd,oDAAkC;AAClC,+CAAqD;AAA5C,6GAAA,gBAAgB,OAAA;AAiBzB,2DAAyC;AACzC,0DAAwC;AACxC,iEAA+C;AAC/C,6DAA2C;AAC3C,4DAA0C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qoretechnologies/reqraft",
3
- "version": "0.10.7",
3
+ "version": "0.10.9-pr.74.g452d4d3",
4
4
  "description": "ReQraft is a collection of React components and hooks that are used across Qore Technologies' products made using the ReQore component library from Qore.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,50 @@
1
+ import { ReqoreControlGroup, ReqoreTag } from '@qoretechnologies/reqore';
2
+ import { useEffect, useState } from 'react';
3
+
4
+ /*
5
+ * Renders the files staged on a ticket composer as removable chips. Image files —
6
+ * whether uploaded, pasted, or captured as a screenshot — show a thumbnail;
7
+ * everything else shows a paperclip + filename. Thumbnail object URLs are created
8
+ * here and revoked when the file set changes or the component unmounts. Renders
9
+ * nothing when there are no staged files.
10
+ */
11
+
12
+ export interface IAttachmentChipsProps {
13
+ files: File[];
14
+ onRemove: (index: number) => void;
15
+ disabled?: boolean;
16
+ }
17
+
18
+ export const AttachmentChips = ({ files, onRemove, disabled }: IAttachmentChipsProps) => {
19
+ const [thumbnails, setThumbnails] = useState<string[]>([]);
20
+
21
+ useEffect(() => {
22
+ const urls = files.map((file) =>
23
+ file.type.startsWith('image/') ? URL.createObjectURL(file) : ''
24
+ );
25
+ setThumbnails(urls);
26
+ return () => urls.forEach((url) => url && URL.revokeObjectURL(url));
27
+ }, [files]);
28
+
29
+ if (!files.length) {
30
+ return null;
31
+ }
32
+
33
+ return (
34
+ <ReqoreControlGroup wrap gapSize='small' verticalAlign='center'>
35
+ {files.map((file, index) => {
36
+ const thumbnail = thumbnails[index];
37
+ return (
38
+ <ReqoreTag
39
+ key={`${file.name}-${index}`}
40
+ icon={thumbnail ? undefined : 'AttachmentLine'}
41
+ leftIconProps={thumbnail ? { image: thumbnail } : undefined}
42
+ label={file.name}
43
+ size='small'
44
+ onRemoveClick={disabled ? undefined : () => onRemove(index)}
45
+ />
46
+ );
47
+ })}
48
+ </ReqoreControlGroup>
49
+ );
50
+ };
@@ -0,0 +1,102 @@
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
3
+ import { StoryMeta } from '../../types';
4
+ import { InterfaceReferenceTags } from './InterfaceReferenceTags';
5
+ import { IInterfaceReference } from './meta';
6
+
7
+ // Several references, including two of the same kind (workflow), as `{kind, name}`
8
+ // snapshots — no `resolveInterfaceIcon` is passed, so the built-in per-kind default
9
+ // icons are exercised.
10
+ const REFERENCES: IInterfaceReference[] = [
11
+ { interface_kind: 'workflow', interface_name: 'order-sync:1.2', reference_id: 'r1' },
12
+ { interface_kind: 'workflow', interface_name: 'invoice-sync:2.3', reference_id: 'r2' },
13
+ { interface_kind: 'service', interface_name: 'notification-svc', reference_id: 'r3' },
14
+ { interface_kind: 'job', interface_name: 'nightly-cleanup', reference_id: 'r4' },
15
+ ];
16
+
17
+ const meta = {
18
+ component: InterfaceReferenceTags,
19
+ title: 'Components/InterfaceReferenceTags',
20
+ args: {
21
+ references: REFERENCES,
22
+ label: 'References',
23
+ },
24
+ } as StoryMeta<typeof InterfaceReferenceTags>;
25
+
26
+ export default meta;
27
+ type Story = StoryObj<typeof meta>;
28
+
29
+ /** The ticket-header use: a "References" label followed by one chip per reference. */
30
+ export const Default: Story = {
31
+ async play({ canvasElement }) {
32
+ const canvas = within(canvasElement);
33
+ await expect(canvas.getByText('References')).toBeInTheDocument();
34
+ await expect(canvas.getByText('order-sync:1.2')).toBeInTheDocument();
35
+ await expect(canvas.getByText('invoice-sync:2.3')).toBeInTheDocument();
36
+ await expect(canvas.getByText('notification-svc')).toBeInTheDocument();
37
+ await expect(canvas.getByText('nightly-cleanup')).toBeInTheDocument();
38
+ },
39
+ };
40
+
41
+ /**
42
+ * When `onInterfaceClick` is passed the chips become interactive; clicking one
43
+ * calls it with that reference (the customer view, which can open the interface on
44
+ * its own instance, wires this).
45
+ */
46
+ export const Clickable: Story = {
47
+ args: { onInterfaceClick: fn() },
48
+ async play({ canvasElement, args }) {
49
+ const canvas = within(canvasElement);
50
+ await userEvent.click(canvas.getByText('invoice-sync:2.3'));
51
+ await waitFor(() =>
52
+ expect(args.onInterfaceClick).toHaveBeenCalledWith(
53
+ expect.objectContaining({
54
+ interface_kind: 'workflow',
55
+ interface_name: 'invoice-sync:2.3',
56
+ })
57
+ )
58
+ );
59
+ },
60
+ };
61
+
62
+ /** The in-thread use: no label — the chips sit under a message. */
63
+ export const NoLabel: Story = {
64
+ args: { label: undefined },
65
+ async play({ canvasElement }) {
66
+ const canvas = within(canvasElement);
67
+ await expect(canvas.queryByText('References')).not.toBeInTheDocument();
68
+ await expect(canvas.getByText('order-sync:1.2')).toBeInTheDocument();
69
+ },
70
+ };
71
+
72
+ /**
73
+ * With no references the component renders nothing — no empty header, no chips —
74
+ * so a ticket without references shows a clean gap rather than a stray "References:"
75
+ * label. The dashed frame below is a story-only caption; the empty space inside it
76
+ * is the component.
77
+ */
78
+ export const Empty: Story = {
79
+ args: { references: [] },
80
+ decorators: [
81
+ (Story) => (
82
+ <div
83
+ style={{
84
+ border: '1px dashed rgba(150, 150, 150, 0.4)',
85
+ borderRadius: 6,
86
+ padding: 12,
87
+ fontSize: 12,
88
+ opacity: 0.6,
89
+ }}
90
+ >
91
+ No references → the row renders nothing (no empty header, no chips):
92
+ <Story />
93
+ </div>
94
+ ),
95
+ ],
96
+ async play({ canvasElement }) {
97
+ // The dashed frame + caption are the decorator; the component itself renders
98
+ // nothing — no header text, no chips.
99
+ await expect(within(canvasElement).queryByText('References')).not.toBeInTheDocument();
100
+ await expect(within(canvasElement).queryByText('order-sync:1.2')).not.toBeInTheDocument();
101
+ },
102
+ };
@@ -0,0 +1,62 @@
1
+ import { ReqoreControlGroup, ReqoreP, ReqoreTag } from '@qoretechnologies/reqore';
2
+ import { TSizes } from '@qoretechnologies/reqore/dist/constants/sizes';
3
+ import { IReqoreIconName } from '@qoretechnologies/reqore/dist/types/icons';
4
+ import { defaultInterfaceIcon, IInterfaceReference } from './meta';
5
+
6
+ export interface IInterfaceReferenceTagsProps {
7
+ references?: IInterfaceReference[];
8
+ /** Optional leading label, e.g. "References" in a ticket header. Omitted (the
9
+ * default) inside the thread, where the chips sit under a message. */
10
+ label?: string;
11
+ /** Resolve a per-kind icon. Consumers with their own icon vocabulary (the IDE)
12
+ * pass one; when omitted the built-in per-kind default is used. */
13
+ resolveInterfaceIcon?: (kind: string) => IReqoreIconName;
14
+ /** Open a referenced interface; chips are static (informational) when omitted —
15
+ * e.g. the staff view, which can't reach the customer's instance. */
16
+ onInterfaceClick?: (reference: IInterfaceReference) => void;
17
+ size?: TSizes;
18
+ }
19
+
20
+ /**
21
+ * The chips for the Qorus interfaces a ticket or message references, as
22
+ * `{kind, name}` snapshots. The single renderer for interface references across
23
+ * every support surface — the ticket header (with a "References" label), the
24
+ * thread (per message, no label), and the Qonsole card — so a reference looks
25
+ * identical everywhere. Renders nothing when there are no references.
26
+ */
27
+ export const InterfaceReferenceTags = ({
28
+ references,
29
+ label,
30
+ resolveInterfaceIcon,
31
+ onInterfaceClick,
32
+ size = 'small',
33
+ }: IInterfaceReferenceTagsProps) => {
34
+ if (!references?.length) {
35
+ return null;
36
+ }
37
+ const resolveIcon = resolveInterfaceIcon ?? defaultInterfaceIcon;
38
+ return (
39
+ <ReqoreControlGroup verticalAlign='center' wrap gapSize='small'>
40
+ {label ? (
41
+ <ReqoreP size='small' effect={{ opacity: 0.6 }}>
42
+ {label}
43
+ </ReqoreP>
44
+ ) : null}
45
+ {references.map((reference) => (
46
+ <ReqoreTag
47
+ key={reference.reference_id ?? `${reference.interface_kind}:${reference.interface_name}`}
48
+ icon={resolveIcon(reference.interface_kind)}
49
+ labelKey={reference.interface_kind}
50
+ label={reference.interface_name}
51
+ size={size}
52
+ tooltip={
53
+ onInterfaceClick
54
+ ? `Open ${reference.interface_kind} ${reference.interface_name}`
55
+ : `${reference.interface_kind}: ${reference.interface_name}`
56
+ }
57
+ onClick={onInterfaceClick ? () => onInterfaceClick(reference) : undefined}
58
+ />
59
+ ))}
60
+ </ReqoreControlGroup>
61
+ );
62
+ };
@@ -0,0 +1,71 @@
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { expect, within } from 'storybook/test';
3
+ import { StoryMeta } from '../../types';
4
+ import { TTicketCategory, TTicketPriority, TTicketStatus } from './meta';
5
+ import { TicketMetaTags } from './TicketMetaTags';
6
+
7
+ const ticket = (
8
+ status: TTicketStatus,
9
+ priority: TTicketPriority,
10
+ category: TTicketCategory
11
+ ): { status: TTicketStatus; priority: TTicketPriority; category: TTicketCategory } => ({
12
+ status,
13
+ priority,
14
+ category,
15
+ });
16
+
17
+ const meta = {
18
+ component: TicketMetaTags,
19
+ title: 'Components/TicketMetaTags',
20
+ args: {
21
+ ticket: ticket('open', 'high', 'bug'),
22
+ },
23
+ } as StoryMeta<typeof TicketMetaTags>;
24
+
25
+ export default meta;
26
+ type Story = StoryObj<typeof meta>;
27
+
28
+ /** The status / priority / category badge row — each value's label, intent and
29
+ * icon come from the shared `supportTicket/meta` vocabularies. */
30
+ export const Default: Story = {
31
+ async play({ canvasElement }) {
32
+ const canvas = within(canvasElement);
33
+ await expect(canvas.getByText('Open')).toBeInTheDocument();
34
+ await expect(canvas.getByText('High')).toBeInTheDocument();
35
+ await expect(canvas.getByText('Bug')).toBeInTheDocument();
36
+ },
37
+ };
38
+
39
+ /**
40
+ * The `awaiting_customer` status is the one value whose label is audience-specific.
41
+ * With no `viewerRole` (the staff / neutral default) it reads "Awaiting customer".
42
+ */
43
+ export const StaffAwaitingLabel: Story = {
44
+ args: { ticket: ticket('awaiting_customer', 'normal', 'question') },
45
+ async play({ canvasElement }) {
46
+ const canvas = within(canvasElement);
47
+ await expect(canvas.getByText('Awaiting customer')).toBeInTheDocument();
48
+ await expect(canvas.queryByText('Awaiting your reply')).not.toBeInTheDocument();
49
+ },
50
+ };
51
+
52
+ /** The customer viewpoint re-labels the same status as "Awaiting your reply". */
53
+ export const CustomerAwaitingLabel: Story = {
54
+ args: { viewerRole: 'customer', ticket: ticket('awaiting_customer', 'normal', 'question') },
55
+ async play({ canvasElement }) {
56
+ const canvas = within(canvasElement);
57
+ await expect(canvas.getByText('Awaiting your reply')).toBeInTheDocument();
58
+ await expect(canvas.queryByText('Awaiting customer')).not.toBeInTheDocument();
59
+ },
60
+ };
61
+
62
+ /** `hideCategory` drops the category tag — for dense list rows. */
63
+ export const HideCategory: Story = {
64
+ args: { hideCategory: true },
65
+ async play({ canvasElement }) {
66
+ const canvas = within(canvasElement);
67
+ await expect(canvas.getByText('Open')).toBeInTheDocument();
68
+ await expect(canvas.getByText('High')).toBeInTheDocument();
69
+ await expect(canvas.queryByText('Bug')).not.toBeInTheDocument();
70
+ },
71
+ };