@spektra-cloudevents/application-copilot-widget 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -77,7 +77,7 @@ var widgetStyles = `
77
77
  /* Panel */
78
78
  .acw-panel {
79
79
  position: fixed; right: 24px; bottom: 96px; z-index: 2147483000;
80
- width: 410px; max-width: calc(100vw - 48px); height: 580px; max-height: calc(100vh - 130px);
80
+ width: 480px; max-width: calc(100vw - 48px); height: 660px; max-height: calc(100vh - 120px);
81
81
  display: none; flex-direction: column;
82
82
  background: var(--acw-bg); color: var(--acw-fg);
83
83
  border: 1px solid var(--acw-border); border-radius: 16px; overflow: hidden;
@@ -135,6 +135,26 @@ var widgetStyles = `
135
135
  .acw-input:focus { outline: 2px solid var(--acw-accent); outline-offset: 0; }
136
136
  .acw-send { border: none; border-radius: 10px; padding: 0 16px; background: var(--acw-accent); color: #fff; cursor: pointer; font-size: 14px; font-family: inherit; }
137
137
  .acw-send:hover { background: var(--acw-accent-dark); }
138
+
139
+ /* Support-ticket draft card */
140
+ .acw-ticket { background: var(--acw-bg); border: 1px solid var(--acw-border); border-radius: 12px; padding: 14px; margin: 12px 0; border-left: 4px solid var(--acw-accent); }
141
+ .acw-ticket-title { font-size: 15px; font-weight: 600; color: var(--acw-fg); margin: 0 0 4px; }
142
+ .acw-ticket-sub { font-size: 12px; color: var(--acw-muted); margin: 0 0 10px; }
143
+ .acw-ticket-label { display: block; font-size: 12px; font-weight: 600; color: var(--acw-muted); margin: 12px 0 5px; }
144
+ .acw-ticket-input, .acw-ticket-desc {
145
+ width: 100%; box-sizing: border-box; font-family: inherit; font-size: 13px;
146
+ padding: 10px 12px; border: 1px solid var(--acw-border); border-radius: 10px;
147
+ color: var(--acw-fg); background: var(--acw-bg);
148
+ }
149
+ .acw-ticket-desc { resize: vertical; min-height: 170px; line-height: 1.5; }
150
+ .acw-ticket-input:focus, .acw-ticket-desc:focus { outline: 2px solid var(--acw-accent); outline-offset: 0; }
151
+ .acw-ticket-actions { display: flex; gap: 10px; margin-top: 14px; }
152
+ .acw-btn-primary { border: none; border-radius: 10px; padding: 10px 20px; cursor: pointer; background: var(--acw-accent); color: #fff; font-size: 14px; font-weight: 600; font-family: inherit; }
153
+ .acw-btn-primary:hover { background: var(--acw-accent-dark); }
154
+ .acw-btn-ghost { border: 1px solid var(--acw-border); border-radius: 10px; padding: 10px 16px; cursor: pointer; background: var(--acw-bg); color: var(--acw-fg); font-size: 14px; font-family: inherit; }
155
+ .acw-btn-ghost:hover { background: #f0eefe; }
156
+ .acw-link-btn { margin-top: 8px; border: none; background: transparent; color: var(--acw-accent); font-size: 12px; font-family: inherit; cursor: pointer; padding: 0; text-decoration: underline; }
157
+ .acw-link-btn:hover { color: var(--acw-accent-dark); }
138
158
  `;
139
159
 
140
160
  // src/widget.ts
@@ -447,12 +467,15 @@ var CopilotWidget = class {
447
467
  const explicit = ctx.page?.requestId || ctx.page?.RequestId;
448
468
  if (explicit) return String(explicit);
449
469
  const route = ctx.page?.route || (typeof window !== "undefined" ? window.location.pathname : "");
450
- const m = /MS[A-Z0-9]{6,}/i.exec(route || "");
451
- return m ? m[0] : void 0;
470
+ const ms = /MS[A-Z0-9]{6,}/i.exec(route || "");
471
+ if (ms) return ms[0];
472
+ const guid = /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/.exec(route || "");
473
+ return guid ? guid[0] : void 0;
452
474
  }
453
475
  /** Build a pre-filled, editable ticket draft and let the user review + Send (they trigger the API call). */
454
476
  openTicketDraft(answer) {
455
- const requestId = this.currentRequestId();
477
+ const fromAnswer = /MS[A-Z0-9]{6,}/i.exec(answer.primaryReason || "");
478
+ const requestId = fromAnswer ? fromAnswer[0] : this.currentRequestId();
456
479
  const role = answer.verifiedRoleLabel || "";
457
480
  const reason = answer.primaryReason || "I am blocked from completing an action.";
458
481
  const subject = requestId ? `[Cloud Events] Help needed on request ${requestId}` : "[Cloud Events] Help needed with an event request";
@@ -465,10 +488,8 @@ var CopilotWidget = class {
465
488
  What the copilot reported:
466
489
  ${reason}`;
467
490
  const card = document.createElement("div");
468
- card.className = "acw-answer";
469
- const lbl = "display:block;font-size:11px;color:var(--acw-muted);margin:8px 0 2px;";
470
- const fld = "width:100%;box-sizing:border-box;font:inherit;font-size:13px;padding:6px 8px;border:1px solid var(--acw-border);border-radius:8px;background:var(--acw-bg);color:var(--acw-fg);";
471
- card.innerHTML = `<div class="acw-reason"><strong>Review your support ticket</strong></div><label style="${lbl}">Subject</label><input class="acw-ticket-subject" type="text" style="${fld}" /><label style="${lbl}">Description</label><textarea class="acw-ticket-desc" rows="6" style="${fld}resize:vertical;"></textarea><div style="display:flex;gap:8px;margin-top:10px;"><button class="acw-ticket-send" type="button" style="border:none;border-radius:8px;padding:6px 14px;cursor:pointer;background:var(--acw-accent);color:var(--acw-accent-fg);font-size:13px;">Send ticket</button><button class="acw-ticket-cancel" type="button" style="border:1px solid var(--acw-border);border-radius:8px;padding:6px 12px;cursor:pointer;background:var(--acw-bg);color:var(--acw-fg);font-size:13px;">Cancel</button></div>`;
491
+ card.className = "acw-ticket";
492
+ card.innerHTML = `<div class="acw-ticket-title">Raise a support ticket</div><div class="acw-ticket-sub">Review the details below and click Send. It goes to the support team as a Zoho Desk ticket.</div><label class="acw-ticket-label">Subject</label><input class="acw-ticket-subject acw-ticket-input" type="text" /><label class="acw-ticket-label">Description</label><textarea class="acw-ticket-desc" rows="8"></textarea><div class="acw-ticket-actions"><button class="acw-ticket-send acw-btn-primary" type="button">Send ticket</button><button class="acw-ticket-cancel acw-btn-ghost" type="button">Cancel</button></div>`;
472
493
  card.querySelector(".acw-ticket-subject").value = subject;
473
494
  card.querySelector(".acw-ticket-desc").value = description;
474
495
  card.querySelector(".acw-ticket-cancel").addEventListener("click", () => card.remove());
@@ -510,7 +531,22 @@ ${reason}`;
510
531
  const num = data.ticketNumber ? `#${data.ticketNumber}` : "";
511
532
  const el = document.createElement("div");
512
533
  el.className = "acw-answer acw-okstate";
513
- el.innerHTML = `<div class="acw-reason">Support ticket ${escapeHtml(num)} has been created. The support team will follow up.</div>` + (data.webUrl ? `<div class="acw-role"><a href="${escapeHtml(data.webUrl)}" target="_blank" rel="noopener">Open the ticket</a></div>` : "");
534
+ el.innerHTML = `<div class="acw-reason">Support ticket ${escapeHtml(num)} has been created. The support team will follow up.</div>`;
535
+ if (data.webUrl || data.id || this.config.onOpenTicket) {
536
+ const open = document.createElement("button");
537
+ open.type = "button";
538
+ open.className = "acw-link-btn";
539
+ open.textContent = "Open the ticket";
540
+ open.addEventListener("click", () => {
541
+ const ticket = { id: data.id, number: data.ticketNumber, webUrl: data.webUrl };
542
+ if (this.config.onOpenTicket) {
543
+ this.config.onOpenTicket(ticket);
544
+ } else if (data.webUrl) {
545
+ window.open(data.webUrl, "_blank", "noopener");
546
+ }
547
+ });
548
+ el.appendChild(open);
549
+ }
514
550
  this.body.appendChild(el);
515
551
  this.body.scrollTop = this.body.scrollHeight;
516
552
  } else {
package/dist/index.d.cts CHANGED
@@ -46,6 +46,12 @@ interface WidgetConfig {
46
46
  buttonText?: string;
47
47
  /** Host navigation hook (e.g. Angular router). If omitted, the widget falls back to window.location. */
48
48
  onNavigate?: (path: string) => void;
49
+ /** Host hook to open a created support ticket (e.g. the embedded Zoho ASAP widget). If omitted, the widget opens webUrl in a new tab. */
50
+ onOpenTicket?: (ticket: {
51
+ id?: string;
52
+ number?: string;
53
+ webUrl?: string;
54
+ }) => void;
49
55
  }
50
56
  interface CopilotAnswer {
51
57
  status: string;
package/dist/index.d.ts CHANGED
@@ -46,6 +46,12 @@ interface WidgetConfig {
46
46
  buttonText?: string;
47
47
  /** Host navigation hook (e.g. Angular router). If omitted, the widget falls back to window.location. */
48
48
  onNavigate?: (path: string) => void;
49
+ /** Host hook to open a created support ticket (e.g. the embedded Zoho ASAP widget). If omitted, the widget opens webUrl in a new tab. */
50
+ onOpenTicket?: (ticket: {
51
+ id?: string;
52
+ number?: string;
53
+ webUrl?: string;
54
+ }) => void;
49
55
  }
50
56
  interface CopilotAnswer {
51
57
  status: string;
package/dist/index.js CHANGED
@@ -40,7 +40,7 @@ var widgetStyles = `
40
40
  /* Panel */
41
41
  .acw-panel {
42
42
  position: fixed; right: 24px; bottom: 96px; z-index: 2147483000;
43
- width: 410px; max-width: calc(100vw - 48px); height: 580px; max-height: calc(100vh - 130px);
43
+ width: 480px; max-width: calc(100vw - 48px); height: 660px; max-height: calc(100vh - 120px);
44
44
  display: none; flex-direction: column;
45
45
  background: var(--acw-bg); color: var(--acw-fg);
46
46
  border: 1px solid var(--acw-border); border-radius: 16px; overflow: hidden;
@@ -98,6 +98,26 @@ var widgetStyles = `
98
98
  .acw-input:focus { outline: 2px solid var(--acw-accent); outline-offset: 0; }
99
99
  .acw-send { border: none; border-radius: 10px; padding: 0 16px; background: var(--acw-accent); color: #fff; cursor: pointer; font-size: 14px; font-family: inherit; }
100
100
  .acw-send:hover { background: var(--acw-accent-dark); }
101
+
102
+ /* Support-ticket draft card */
103
+ .acw-ticket { background: var(--acw-bg); border: 1px solid var(--acw-border); border-radius: 12px; padding: 14px; margin: 12px 0; border-left: 4px solid var(--acw-accent); }
104
+ .acw-ticket-title { font-size: 15px; font-weight: 600; color: var(--acw-fg); margin: 0 0 4px; }
105
+ .acw-ticket-sub { font-size: 12px; color: var(--acw-muted); margin: 0 0 10px; }
106
+ .acw-ticket-label { display: block; font-size: 12px; font-weight: 600; color: var(--acw-muted); margin: 12px 0 5px; }
107
+ .acw-ticket-input, .acw-ticket-desc {
108
+ width: 100%; box-sizing: border-box; font-family: inherit; font-size: 13px;
109
+ padding: 10px 12px; border: 1px solid var(--acw-border); border-radius: 10px;
110
+ color: var(--acw-fg); background: var(--acw-bg);
111
+ }
112
+ .acw-ticket-desc { resize: vertical; min-height: 170px; line-height: 1.5; }
113
+ .acw-ticket-input:focus, .acw-ticket-desc:focus { outline: 2px solid var(--acw-accent); outline-offset: 0; }
114
+ .acw-ticket-actions { display: flex; gap: 10px; margin-top: 14px; }
115
+ .acw-btn-primary { border: none; border-radius: 10px; padding: 10px 20px; cursor: pointer; background: var(--acw-accent); color: #fff; font-size: 14px; font-weight: 600; font-family: inherit; }
116
+ .acw-btn-primary:hover { background: var(--acw-accent-dark); }
117
+ .acw-btn-ghost { border: 1px solid var(--acw-border); border-radius: 10px; padding: 10px 16px; cursor: pointer; background: var(--acw-bg); color: var(--acw-fg); font-size: 14px; font-family: inherit; }
118
+ .acw-btn-ghost:hover { background: #f0eefe; }
119
+ .acw-link-btn { margin-top: 8px; border: none; background: transparent; color: var(--acw-accent); font-size: 12px; font-family: inherit; cursor: pointer; padding: 0; text-decoration: underline; }
120
+ .acw-link-btn:hover { color: var(--acw-accent-dark); }
101
121
  `;
102
122
 
103
123
  // src/widget.ts
@@ -410,12 +430,15 @@ var CopilotWidget = class {
410
430
  const explicit = ctx.page?.requestId || ctx.page?.RequestId;
411
431
  if (explicit) return String(explicit);
412
432
  const route = ctx.page?.route || (typeof window !== "undefined" ? window.location.pathname : "");
413
- const m = /MS[A-Z0-9]{6,}/i.exec(route || "");
414
- return m ? m[0] : void 0;
433
+ const ms = /MS[A-Z0-9]{6,}/i.exec(route || "");
434
+ if (ms) return ms[0];
435
+ const guid = /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/.exec(route || "");
436
+ return guid ? guid[0] : void 0;
415
437
  }
416
438
  /** Build a pre-filled, editable ticket draft and let the user review + Send (they trigger the API call). */
417
439
  openTicketDraft(answer) {
418
- const requestId = this.currentRequestId();
440
+ const fromAnswer = /MS[A-Z0-9]{6,}/i.exec(answer.primaryReason || "");
441
+ const requestId = fromAnswer ? fromAnswer[0] : this.currentRequestId();
419
442
  const role = answer.verifiedRoleLabel || "";
420
443
  const reason = answer.primaryReason || "I am blocked from completing an action.";
421
444
  const subject = requestId ? `[Cloud Events] Help needed on request ${requestId}` : "[Cloud Events] Help needed with an event request";
@@ -428,10 +451,8 @@ var CopilotWidget = class {
428
451
  What the copilot reported:
429
452
  ${reason}`;
430
453
  const card = document.createElement("div");
431
- card.className = "acw-answer";
432
- const lbl = "display:block;font-size:11px;color:var(--acw-muted);margin:8px 0 2px;";
433
- const fld = "width:100%;box-sizing:border-box;font:inherit;font-size:13px;padding:6px 8px;border:1px solid var(--acw-border);border-radius:8px;background:var(--acw-bg);color:var(--acw-fg);";
434
- card.innerHTML = `<div class="acw-reason"><strong>Review your support ticket</strong></div><label style="${lbl}">Subject</label><input class="acw-ticket-subject" type="text" style="${fld}" /><label style="${lbl}">Description</label><textarea class="acw-ticket-desc" rows="6" style="${fld}resize:vertical;"></textarea><div style="display:flex;gap:8px;margin-top:10px;"><button class="acw-ticket-send" type="button" style="border:none;border-radius:8px;padding:6px 14px;cursor:pointer;background:var(--acw-accent);color:var(--acw-accent-fg);font-size:13px;">Send ticket</button><button class="acw-ticket-cancel" type="button" style="border:1px solid var(--acw-border);border-radius:8px;padding:6px 12px;cursor:pointer;background:var(--acw-bg);color:var(--acw-fg);font-size:13px;">Cancel</button></div>`;
454
+ card.className = "acw-ticket";
455
+ card.innerHTML = `<div class="acw-ticket-title">Raise a support ticket</div><div class="acw-ticket-sub">Review the details below and click Send. It goes to the support team as a Zoho Desk ticket.</div><label class="acw-ticket-label">Subject</label><input class="acw-ticket-subject acw-ticket-input" type="text" /><label class="acw-ticket-label">Description</label><textarea class="acw-ticket-desc" rows="8"></textarea><div class="acw-ticket-actions"><button class="acw-ticket-send acw-btn-primary" type="button">Send ticket</button><button class="acw-ticket-cancel acw-btn-ghost" type="button">Cancel</button></div>`;
435
456
  card.querySelector(".acw-ticket-subject").value = subject;
436
457
  card.querySelector(".acw-ticket-desc").value = description;
437
458
  card.querySelector(".acw-ticket-cancel").addEventListener("click", () => card.remove());
@@ -473,7 +494,22 @@ ${reason}`;
473
494
  const num = data.ticketNumber ? `#${data.ticketNumber}` : "";
474
495
  const el = document.createElement("div");
475
496
  el.className = "acw-answer acw-okstate";
476
- el.innerHTML = `<div class="acw-reason">Support ticket ${escapeHtml(num)} has been created. The support team will follow up.</div>` + (data.webUrl ? `<div class="acw-role"><a href="${escapeHtml(data.webUrl)}" target="_blank" rel="noopener">Open the ticket</a></div>` : "");
497
+ el.innerHTML = `<div class="acw-reason">Support ticket ${escapeHtml(num)} has been created. The support team will follow up.</div>`;
498
+ if (data.webUrl || data.id || this.config.onOpenTicket) {
499
+ const open = document.createElement("button");
500
+ open.type = "button";
501
+ open.className = "acw-link-btn";
502
+ open.textContent = "Open the ticket";
503
+ open.addEventListener("click", () => {
504
+ const ticket = { id: data.id, number: data.ticketNumber, webUrl: data.webUrl };
505
+ if (this.config.onOpenTicket) {
506
+ this.config.onOpenTicket(ticket);
507
+ } else if (data.webUrl) {
508
+ window.open(data.webUrl, "_blank", "noopener");
509
+ }
510
+ });
511
+ el.appendChild(open);
512
+ }
477
513
  this.body.appendChild(el);
478
514
  this.body.scrollTop = this.body.scrollHeight;
479
515
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spektra-cloudevents/application-copilot-widget",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Spektra Application Copilot widget — framework-agnostic and CSS-library agnostic via Shadow DOM isolation.",
5
5
  "type": "module",
6
6
  "publishConfig": {