@qoretechnologies/reqraft 0.10.8 → 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 (65) hide show
  1. package/dist/components/form/engine/CompactRow.d.ts.map +1 -1
  2. package/dist/components/form/engine/CompactRow.js +1 -22
  3. package/dist/components/form/engine/CompactRow.js.map +1 -1
  4. package/dist/components/form/engine/compactRowStyles.d.ts +0 -1
  5. package/dist/components/form/engine/compactRowStyles.d.ts.map +1 -1
  6. package/dist/components/form/engine/compactRowStyles.js +4 -19
  7. package/dist/components/form/engine/compactRowStyles.js.map +1 -1
  8. package/dist/components/supportTicket/AttachmentChips.d.ts +7 -0
  9. package/dist/components/supportTicket/AttachmentChips.d.ts.map +1 -0
  10. package/dist/components/supportTicket/AttachmentChips.js +26 -0
  11. package/dist/components/supportTicket/AttachmentChips.js.map +1 -0
  12. package/dist/components/supportTicket/InterfaceReferenceTags.d.ts +25 -0
  13. package/dist/components/supportTicket/InterfaceReferenceTags.d.ts.map +1 -0
  14. package/dist/components/supportTicket/InterfaceReferenceTags.js +28 -0
  15. package/dist/components/supportTicket/InterfaceReferenceTags.js.map +1 -0
  16. package/dist/components/supportTicket/TicketMetaTags.d.ts +24 -0
  17. package/dist/components/supportTicket/TicketMetaTags.d.ts.map +1 -0
  18. package/dist/components/supportTicket/TicketMetaTags.js +21 -0
  19. package/dist/components/supportTicket/TicketMetaTags.js.map +1 -0
  20. package/dist/components/supportTicket/TicketReplyBox.d.ts +59 -0
  21. package/dist/components/supportTicket/TicketReplyBox.d.ts.map +1 -0
  22. package/dist/components/supportTicket/TicketReplyBox.js +169 -0
  23. package/dist/components/supportTicket/TicketReplyBox.js.map +1 -0
  24. package/dist/components/supportTicket/fileToAttachment.d.ts +9 -0
  25. package/dist/components/supportTicket/fileToAttachment.d.ts.map +1 -0
  26. package/dist/components/supportTicket/fileToAttachment.js +28 -0
  27. package/dist/components/supportTicket/fileToAttachment.js.map +1 -0
  28. package/dist/components/supportTicket/index.d.ts +7 -0
  29. package/dist/components/supportTicket/index.d.ts.map +1 -0
  30. package/dist/components/supportTicket/index.js +23 -0
  31. package/dist/components/supportTicket/index.js.map +1 -0
  32. package/dist/components/supportTicket/meta.d.ts +55 -0
  33. package/dist/components/supportTicket/meta.d.ts.map +1 -0
  34. package/dist/components/supportTicket/meta.js +77 -0
  35. package/dist/components/supportTicket/meta.js.map +1 -0
  36. package/dist/components/ticketThread/TicketThread.d.ts +36 -0
  37. package/dist/components/ticketThread/TicketThread.d.ts.map +1 -0
  38. package/dist/components/ticketThread/TicketThread.js +137 -0
  39. package/dist/components/ticketThread/TicketThread.js.map +1 -0
  40. package/dist/components/ticketThread/index.d.ts +3 -0
  41. package/dist/components/ticketThread/index.d.ts.map +1 -0
  42. package/dist/components/ticketThread/index.js +6 -0
  43. package/dist/components/ticketThread/index.js.map +1 -0
  44. package/dist/index.d.ts +2 -0
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +2 -0
  47. package/dist/index.js.map +1 -1
  48. package/package.json +1 -1
  49. package/src/components/form/engine/CompactRow.tsx +1 -57
  50. package/src/components/form/engine/FormEngine.stories.tsx +0 -67
  51. package/src/components/form/engine/compactRowStyles.ts +0 -21
  52. package/src/components/supportTicket/AttachmentChips.tsx +50 -0
  53. package/src/components/supportTicket/InterfaceReferenceTags.stories.tsx +102 -0
  54. package/src/components/supportTicket/InterfaceReferenceTags.tsx +62 -0
  55. package/src/components/supportTicket/TicketMetaTags.stories.tsx +71 -0
  56. package/src/components/supportTicket/TicketMetaTags.tsx +58 -0
  57. package/src/components/supportTicket/TicketReplyBox.stories.tsx +111 -0
  58. package/src/components/supportTicket/TicketReplyBox.tsx +251 -0
  59. package/src/components/supportTicket/fileToAttachment.ts +24 -0
  60. package/src/components/supportTicket/index.ts +6 -0
  61. package/src/components/supportTicket/meta.ts +135 -0
  62. package/src/components/ticketThread/TicketThread.stories.tsx +192 -0
  63. package/src/components/ticketThread/TicketThread.tsx +331 -0
  64. package/src/components/ticketThread/index.ts +6 -0
  65. package/src/index.tsx +2 -0
@@ -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.8",
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",
@@ -35,7 +35,6 @@ import {
35
35
  StyledActionSlot,
36
36
  StyledCardHeading,
37
37
  StyledCardLabel,
38
- StyledCodePreview,
39
38
  StyledColorSwatch,
40
39
  StyledColumn,
41
40
  StyledEditCard,
@@ -257,26 +256,6 @@ export const CompactRow = memo(
257
256
  );
258
257
  }
259
258
 
260
- // Code-editor read summary: replace the truncated string with a chip
261
- // showing line count + character count. The actual code renders below
262
- // the row as a monospace `<pre>` inside a `ReqoreCollapsibleContent` —
263
- // see `showCodePreview` below. Keeps the row height fixed while making
264
- // multi-line source readable without opening the full editor.
265
- if (valueType === 'code-editor' && typeof field?.value === 'string') {
266
- const lines = field.value.split('\n').length;
267
- const chars = field.value.length;
268
- return (
269
- <ReqoreTag
270
- size='small'
271
- minimal
272
- intent='info'
273
- icon='CodeLine'
274
- label={`${lines} ${lines === 1 ? 'line' : 'lines'}`}
275
- labelKey={`${chars} ${chars === 1 ? 'char' : 'chars'}`}
276
- />
277
- );
278
- }
279
-
280
259
  // Selected allowed-value / enum item with a logo (e.g. language images):
281
260
  // render it beside the value, where it belongs — not as the field's icon.
282
261
  const allowedImage = getAllowedValueImage(field?.value, schema);
@@ -934,16 +913,6 @@ export const CompactRow = memo(
934
913
  return inner !== null && typeof inner === 'object';
935
914
  });
936
915
  const showStructuredPreview = hashEntries.length > 0 || isHashList;
937
- // Multi-line code preview: a `code-editor` field with a non-empty string
938
- // value gets a `<pre>`-based code block under the row, capped by a
939
- // `ReqoreCollapsibleContent` so the collapsed height stays row-sized and
940
- // "Show more" reveals the rest. Sits in the same inset the hash/list
941
- // preview uses — mutually exclusive with `showStructuredPreview`.
942
- const showCodePreview =
943
- !hidden &&
944
- valueType === 'code-editor' &&
945
- typeof optionField?.value === 'string' &&
946
- optionField.value.length > 0;
947
916
  const typeLabel =
948
917
  showFieldTypes ?
949
918
  `<${(schema?.ui_type as string) || (schema?.type as string) || 'auto'}${(schema as { ui_element_type?: string } | undefined)?.ui_element_type ? `[${(schema as { ui_element_type?: string }).ui_element_type}]` : ''}>`
@@ -1095,7 +1064,7 @@ export const CompactRow = memo(
1095
1064
  role='button'
1096
1065
  tabIndex={0}
1097
1066
  aria-label={label}
1098
- className={`readfirst-row options-readfirst-value${hidden ? ' readfirst-row-hidden' : ''}${fieldDisabled ? ' readfirst-row-disabled' : ''}${isHighlighted ? ' readfirst-row-group-highlight' : ''}${isFlashed ? ' readfirst-row-flash' : ''}${showLabelDesc ? ' readfirst-row-info-open' : ''}${panelMessages.length || showStructuredPreview || showCodePreview ? ' readfirst-row-tall' : ''}${clusterBlockClass ? ' ' + clusterBlockClass : ''}`}
1067
+ className={`readfirst-row options-readfirst-value${hidden ? ' readfirst-row-hidden' : ''}${fieldDisabled ? ' readfirst-row-disabled' : ''}${isHighlighted ? ' readfirst-row-group-highlight' : ''}${isFlashed ? ' readfirst-row-flash' : ''}${showLabelDesc ? ' readfirst-row-info-open' : ''}${panelMessages.length || showStructuredPreview ? ' readfirst-row-tall' : ''}${clusterBlockClass ? ' ' + clusterBlockClass : ''}`}
1099
1068
  aria-disabled={fieldDisabled || undefined}
1100
1069
  style={stripeStyle}
1101
1070
  onClick={activate}
@@ -1206,31 +1175,6 @@ export const CompactRow = memo(
1206
1175
  </ReqoreCollapsibleContent>
1207
1176
  </StyledRowInset>
1208
1177
  : null}
1209
- {/* Code-editor preview: same inset placement as hash/list — a monospace
1210
- `<pre>` block wrapped in `ReqoreCollapsibleContent` so the collapsed
1211
- row stays row-height while multi-line source reveals via "Show more".
1212
- Stopping propagation here (like the structured inset) — a click on
1213
- the collapse button must not also open the field editor. */}
1214
- {showCodePreview ?
1215
- <StyledRowInset
1216
- className='options-readfirst-inset options-readfirst-code-inset'
1217
- onClick={(e) => e.stopPropagation()}
1218
- >
1219
- <ReqoreCollapsibleContent
1220
- maxCollapsedHeight={96}
1221
- buttonProps={{ className: 'options-readfirst-viewmore' }}
1222
- >
1223
- <StyledCodePreview
1224
- className='options-readfirst-code'
1225
- $bg={cHover}
1226
- $border={`${cDivider}88`}
1227
- $fg={cKey}
1228
- >
1229
- {optionField.value as string}
1230
- </StyledCodePreview>
1231
- </ReqoreCollapsibleContent>
1232
- </StyledRowInset>
1233
- : null}
1234
1178
  </StyledRowValue>
1235
1179
  <StyledRowActions>
1236
1180
  {/* Column discipline (table treatment): variable-width chips lead and
@@ -715,73 +715,6 @@ export const OptionInheritsRenderPropFromSiblingCompact: Story = {
715
715
  },
716
716
  };
717
717
 
718
- // Compact-row code-editor preview: a `code-editor` field with a multi-line
719
- // string value renders (a) a "N lines · N chars" tag in the value cell instead
720
- // of the truncated raw string, and (b) a monospace `<pre>` block under the row
721
- // capped by a `ReqoreCollapsibleContent` — the "Show more" affordance the value
722
- // cell couldn't provide on its own. Locks the compact preview so a future
723
- // CompactRow refactor can't silently reduce a Qorus source-code field to an
724
- // ellipsised one-liner again.
725
- export const CompactRowCodeEditorPreview: Story = {
726
- args: {
727
- compact: true,
728
- minColumnWidth: '360px',
729
- componentOverrides: { 'code-editor': CodeEditorStandin },
730
- value: {
731
- language: { type: 'string', value: 'qore' },
732
- source: {
733
- type: 'string',
734
- value:
735
- '%new-style\n%require-types\n%strict-args\n' +
736
- '%enable-all-warnings\n\n' +
737
- 'class ExampleJob inherits QorusJob {\n' +
738
- ' run() {\n' +
739
- ' logInfo("running");\n' +
740
- ' }\n' +
741
- '}\n',
742
- },
743
- },
744
- options: {
745
- language: {
746
- type: 'string',
747
- ui_type: 'string',
748
- display_name: 'Language',
749
- allowed_values: [
750
- { display_name: 'Qore', value: { type: 'string', value: 'qore' } },
751
- { display_name: 'Python', value: { type: 'string', value: 'python' } },
752
- { display_name: 'Java', value: { type: 'string', value: 'java' } },
753
- ],
754
- },
755
- source: {
756
- type: 'string',
757
- ui_type: 'code-editor',
758
- display_name: 'Source Code',
759
- inherit_props: { language: 'language' },
760
- },
761
- },
762
- },
763
- play: async ({ canvasElement }) => {
764
- // (a) The monospace preview mounted under the row — contains a substring
765
- // only the source has, proving `showCodePreview` kicked in and the
766
- // `StyledCodePreview` block is in the DOM.
767
- await waitFor(
768
- () => {
769
- const preview = canvasElement.querySelector('.options-readfirst-code');
770
- expect(preview).toBeTruthy();
771
- expect(preview?.textContent).toContain('class ExampleJob inherits QorusJob');
772
- },
773
- { timeout: 5000 }
774
- );
775
- // (b) The value cell replaced its truncated raw string with a summary tag —
776
- // query the tag directly (its label + labelKey render on separate spans,
777
- // so text-matching across them is fragile). Look for the CodeLine icon
778
- // that only this tag mounts alongside the source-code row.
779
- const sourceRow = canvasElement.querySelector('[data-field="source"]');
780
- expect(sourceRow).toBeTruthy();
781
- expect(sourceRow?.textContent ?? '').toMatch(/\d+\s*lines?/);
782
- },
783
- };
784
-
785
718
  // qorus#347-followup, scope forwarding: this story exercises the nested
786
719
  // case of the OptionInheritsRenderPropFromSibling contract. The parent
787
720
  // form declares `methods: { ui_type: 'list', element_type: 'hash',
@@ -335,27 +335,6 @@ export const StyledRowInset = styled.div`
335
335
  margin-top: 4px;
336
336
  `;
337
337
 
338
- // A collapsed code-block preview shown under the value summary for a
339
- // `code-editor` field. Multi-line, monospace, subtle background — matches
340
- // the aesthetic of the classic code-view surface but small enough to sit
341
- // inside a read-row. Height is capped by the wrapping `ReqoreCollapsibleContent`
342
- // so the "Show more" affordance stays useful.
343
- export const StyledCodePreview = styled.pre<{ $bg: string; $border: string; $fg: string }>`
344
- margin: 0;
345
- padding: 8px 10px;
346
- border-radius: 4px;
347
- background: ${({ $bg }) => $bg};
348
- border: 1px solid ${({ $border }) => $border};
349
- color: ${({ $fg }) => $fg};
350
- font-family:
351
- ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;
352
- font-size: 11.5px;
353
- line-height: 1.5;
354
- white-space: pre;
355
- overflow: auto;
356
- max-width: 100%;
357
- `;
358
-
359
338
  // A small inline colour swatch shown before an rgbcolor value's hex string.
360
339
  export const StyledColorSwatch = styled.span<{ $color: string; $border: string }>`
361
340
  width: 12px;
@@ -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
+ };