maquito-chat-plugin 1.0.0 → 1.1.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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, Injectable, signal, computed, Input, ViewChild, Component } from '@angular/core';
|
|
2
|
+
import { inject, Injectable, ElementRef, signal, computed, Input, ViewChild, Component } from '@angular/core';
|
|
3
3
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
|
4
4
|
import { Observable } from 'rxjs';
|
|
5
5
|
import * as i1 from '@angular/common';
|
|
@@ -134,6 +134,7 @@ class IntelligentChatPluginComponent {
|
|
|
134
134
|
chatContainer;
|
|
135
135
|
config;
|
|
136
136
|
chatService = inject(IntelligentChatService);
|
|
137
|
+
hostEl = inject(ElementRef);
|
|
137
138
|
// State
|
|
138
139
|
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
|
|
139
140
|
isExpanded = signal(false, ...(ngDevMode ? [{ debugName: "isExpanded" }] : []));
|
|
@@ -141,6 +142,18 @@ class IntelligentChatPluginComponent {
|
|
|
141
142
|
isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
142
143
|
selectedTrace = signal(null, ...(ngDevMode ? [{ debugName: "selectedTrace" }] : []));
|
|
143
144
|
authError = signal(null, ...(ngDevMode ? [{ debugName: "authError" }] : []));
|
|
145
|
+
modalUrl = signal(null, ...(ngDevMode ? [{ debugName: "modalUrl" }] : []));
|
|
146
|
+
isModalImage = computed(() => {
|
|
147
|
+
const url = this.modalUrl();
|
|
148
|
+
if (!url)
|
|
149
|
+
return false;
|
|
150
|
+
return /\.(jpg|jpeg|png|gif|webp|svg|bmp)(\?.*)?$/i.test(url);
|
|
151
|
+
}, ...(ngDevMode ? [{ debugName: "isModalImage" }] : []));
|
|
152
|
+
modalLoading = signal(false, ...(ngDevMode ? [{ debugName: "modalLoading" }] : []));
|
|
153
|
+
showHomeBtn = signal(false, ...(ngDevMode ? [{ debugName: "showHomeBtn" }] : []));
|
|
154
|
+
originalModalUrl = '';
|
|
155
|
+
modalReadyForNav = false;
|
|
156
|
+
navReadyTimer = null;
|
|
144
157
|
inputText = '';
|
|
145
158
|
// Pipeline step (driven by real SSE events from backend)
|
|
146
159
|
pipelineStep = '';
|
|
@@ -200,6 +213,11 @@ class IntelligentChatPluginComponent {
|
|
|
200
213
|
const raw = this.resolvedConfig().bubbleSvg || '';
|
|
201
214
|
return this.sanitizer.bypassSecurityTrustHtml(raw);
|
|
202
215
|
}, ...(ngDevMode ? [{ debugName: "sanitizedBubbleSvg" }] : []));
|
|
216
|
+
/** Sanitised URL for the link modal iframe */
|
|
217
|
+
sanitizedModalUrl = computed(() => {
|
|
218
|
+
const url = this.modalUrl() || '';
|
|
219
|
+
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
|
220
|
+
}, ...(ngDevMode ? [{ debugName: "sanitizedModalUrl" }] : []));
|
|
203
221
|
ngOnInit() {
|
|
204
222
|
window.addEventListener('storage', this.storageListener);
|
|
205
223
|
}
|
|
@@ -253,16 +271,24 @@ class IntelligentChatPluginComponent {
|
|
|
253
271
|
}
|
|
254
272
|
toggleChat() {
|
|
255
273
|
this.isOpen.update(v => !v);
|
|
256
|
-
if (!this.isOpen())
|
|
274
|
+
if (!this.isOpen()) {
|
|
257
275
|
this.isExpanded.set(false);
|
|
276
|
+
this.setHostScrollLock(false);
|
|
277
|
+
}
|
|
258
278
|
if (this.isOpen())
|
|
259
279
|
this.shouldScroll = true;
|
|
260
280
|
}
|
|
261
281
|
toggleExpand() {
|
|
262
282
|
this.isExpanded.update(v => !v);
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
283
|
+
this.setHostScrollLock(this.isExpanded());
|
|
284
|
+
}
|
|
285
|
+
/** Lock/unlock the host page scroll to prevent its scrollbar from overlapping ours */
|
|
286
|
+
setHostScrollLock(lock) {
|
|
287
|
+
document.body.style.overflow = lock ? 'hidden' : '';
|
|
288
|
+
// Also target common host containers
|
|
289
|
+
const mc = document.querySelector('.main-container');
|
|
290
|
+
if (mc)
|
|
291
|
+
mc.style.overflow = lock ? 'hidden' : '';
|
|
266
292
|
}
|
|
267
293
|
sendMessage() {
|
|
268
294
|
const text = this.inputText.trim();
|
|
@@ -421,6 +447,66 @@ class IntelligentChatPluginComponent {
|
|
|
421
447
|
closeTrace() {
|
|
422
448
|
this.selectedTrace.set(null);
|
|
423
449
|
}
|
|
450
|
+
// ─── Link Modal ────────────────────────────────
|
|
451
|
+
openLinkModal(url) {
|
|
452
|
+
this.modalLoading.set(true);
|
|
453
|
+
this.showHomeBtn.set(false);
|
|
454
|
+
this.modalReadyForNav = false;
|
|
455
|
+
clearTimeout(this.navReadyTimer);
|
|
456
|
+
this.originalModalUrl = url;
|
|
457
|
+
this.modalUrl.set(url);
|
|
458
|
+
}
|
|
459
|
+
closeLinkModal() {
|
|
460
|
+
this.modalUrl.set(null);
|
|
461
|
+
this.modalLoading.set(false);
|
|
462
|
+
this.showHomeBtn.set(false);
|
|
463
|
+
this.modalReadyForNav = false;
|
|
464
|
+
clearTimeout(this.navReadyTimer);
|
|
465
|
+
this.originalModalUrl = '';
|
|
466
|
+
}
|
|
467
|
+
onIframeLoaded() {
|
|
468
|
+
this.modalLoading.set(false);
|
|
469
|
+
if (this.modalReadyForNav) {
|
|
470
|
+
// A load AFTER the initial page settled = real navigation
|
|
471
|
+
this.showHomeBtn.set(true);
|
|
472
|
+
}
|
|
473
|
+
else {
|
|
474
|
+
// Initial page load (may fire multiple times for SPAs/redirects)
|
|
475
|
+
// Wait 1s of stability before treating next loads as navigation
|
|
476
|
+
clearTimeout(this.navReadyTimer);
|
|
477
|
+
this.navReadyTimer = setTimeout(() => { this.modalReadyForNav = true; }, 1000);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
iframeGoHome() {
|
|
481
|
+
const iframe = this.hostEl.nativeElement.querySelector('.iq-link-iframe');
|
|
482
|
+
if (iframe && this.originalModalUrl) {
|
|
483
|
+
this.modalLoading.set(true);
|
|
484
|
+
this.showHomeBtn.set(false);
|
|
485
|
+
this.modalReadyForNav = false;
|
|
486
|
+
clearTimeout(this.navReadyTimer);
|
|
487
|
+
iframe.src = this.originalModalUrl;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
/** Intercept clicks on <a> and <img> tags inside rendered markdown */
|
|
491
|
+
onMessageClick(event) {
|
|
492
|
+
const target = event.target;
|
|
493
|
+
// Clicking an image opens it full-size in the modal
|
|
494
|
+
if (target.tagName === 'IMG') {
|
|
495
|
+
const src = target.src;
|
|
496
|
+
if (src) {
|
|
497
|
+
event.preventDefault();
|
|
498
|
+
event.stopPropagation();
|
|
499
|
+
this.openLinkModal(src);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
const anchor = target.closest('a');
|
|
504
|
+
if (anchor && anchor.href) {
|
|
505
|
+
event.preventDefault();
|
|
506
|
+
event.stopPropagation();
|
|
507
|
+
this.openLinkModal(anchor.href);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
424
510
|
formatTime(date) {
|
|
425
511
|
return date.toLocaleTimeString('es-CL', { hour: '2-digit', minute: '2-digit' });
|
|
426
512
|
}
|
|
@@ -428,8 +514,14 @@ class IntelligentChatPluginComponent {
|
|
|
428
514
|
if (!text)
|
|
429
515
|
return '';
|
|
430
516
|
try {
|
|
431
|
-
|
|
432
|
-
|
|
517
|
+
let preprocessed = this.preprocessMarkdownTable(text);
|
|
518
|
+
// Encode spaces in markdown image & link URLs:  and [text](url)
|
|
519
|
+
preprocessed = preprocessed.replace(/(!?\[[^\]]*\])\(([^)]+)\)/g, (_match, bracket, url) => `${bracket}(${url.replace(/ /g, '%20')})`);
|
|
520
|
+
let html = marked.parse(preprocessed, { breaks: true });
|
|
521
|
+
// Inject inline styles + onerror on <img> to force small thumbnails & hide broken ones
|
|
522
|
+
const imgStyle = `style="max-height:48px;max-width:100px;object-fit:contain;border-radius:6px;cursor:pointer;display:inline-block;vertical-align:middle;margin:2px 4px;border:1px solid rgba(255,255,255,0.15);box-shadow:0 1px 3px rgba(0,0,0,0.2);"`;
|
|
523
|
+
html = html.replace(/<img /g, `<img ${imgStyle} onerror="this.style.display='none'" `);
|
|
524
|
+
return this.sanitizer.bypassSecurityTrustHtml(html);
|
|
433
525
|
}
|
|
434
526
|
catch {
|
|
435
527
|
return text;
|
|
@@ -687,7 +779,7 @@ class IntelligentChatPluginComponent {
|
|
|
687
779
|
<div class="iq-msg" [class.iq-msg-user]="msg.sender === 'user'" [class.iq-msg-bot]="msg.sender === 'bot'">
|
|
688
780
|
<div class="iq-msg-content">
|
|
689
781
|
@if (msg.sender === 'bot') {
|
|
690
|
-
<div class="iq-md" [innerHTML]="renderMarkdown(msg.text)"></div>
|
|
782
|
+
<div class="iq-md" [innerHTML]="renderMarkdown(msg.text)" (click)="onMessageClick($event)"></div>
|
|
691
783
|
} @else {
|
|
692
784
|
<p>{{ msg.text }}</p>
|
|
693
785
|
}
|
|
@@ -771,8 +863,41 @@ class IntelligentChatPluginComponent {
|
|
|
771
863
|
</div>
|
|
772
864
|
}
|
|
773
865
|
|
|
866
|
+
<!-- Link Modal Overlay -->
|
|
867
|
+
@if (modalUrl()) {
|
|
868
|
+
<div class="iq-link-overlay" (click)="closeLinkModal()">
|
|
869
|
+
<div class="iq-link-modal" (click)="$event.stopPropagation()">
|
|
870
|
+
<div class="iq-link-header">
|
|
871
|
+
@if (showHomeBtn()) {
|
|
872
|
+
<button class="iq-header-btn iq-back-btn" (click)="iframeGoHome()" title="Volver al inicio">🏠</button>
|
|
873
|
+
}
|
|
874
|
+
<span class="iq-link-title" [title]="modalUrl()!">{{ modalUrl() }}</span>
|
|
875
|
+
<div class="iq-link-actions">
|
|
876
|
+
<a [href]="modalUrl()!" target="_blank" rel="noopener" class="iq-header-btn" title="Abrir en nueva pestaña">↗</a>
|
|
877
|
+
<button class="iq-header-btn" (click)="closeLinkModal()">✕</button>
|
|
878
|
+
</div>
|
|
879
|
+
</div>
|
|
880
|
+
<div class="iq-iframe-wrapper">
|
|
881
|
+
@if (isModalImage()) {
|
|
882
|
+
<img [src]="modalUrl()!" class="iq-modal-img" alt="Imagen" />
|
|
883
|
+
} @else {
|
|
884
|
+
@if (modalLoading()) {
|
|
885
|
+
<div class="iq-iframe-loader">
|
|
886
|
+
<div class="iq-spinner"></div>
|
|
887
|
+
<span class="iq-loader-text">Cargando...</span>
|
|
888
|
+
</div>
|
|
889
|
+
}
|
|
890
|
+
<iframe #linkIframe [src]="sanitizedModalUrl()" class="iq-link-iframe"
|
|
891
|
+
[class.iq-iframe-hidden]="modalLoading()"
|
|
892
|
+
(load)="onIframeLoaded()"></iframe>
|
|
893
|
+
}
|
|
894
|
+
</div>
|
|
895
|
+
</div>
|
|
896
|
+
</div>
|
|
897
|
+
}
|
|
898
|
+
|
|
774
899
|
</div><!-- /iq-theme-host -->
|
|
775
|
-
`, isInline: true, styles: [":host{--iq-primary: #1a3a5c;--iq-primary-light: #2a5a8c;--iq-accent: #00d4aa;--iq-accent-light: #33e0be;--iq-bg: #1e1e2f;--iq-bg-card: #252538;--iq-bg-tertiary: #35354a;--iq-text: #ffffff;--iq-text-secondary: #a0a0b0;--iq-text-muted: #6c6c7c;--iq-border: #3a3a4d;--iq-radius: 12px;--iq-bubble-size: 56px;--iq-panel-width: 400px;--iq-panel-height: 520px;--iq-z: 10000;--iq-font: \"Inter\", \"Roboto\", -apple-system, BlinkMacSystemFont, sans-serif;font-family:var(--iq-font)}.iq-bubble{position:fixed;bottom:24px;right:24px;z-index:var(--iq-z);width:var(--iq-bubble-size);height:var(--iq-bubble-size);border-radius:50%;border:none;background:linear-gradient(135deg,var(--iq-accent),var(--iq-accent-light));color:var(--iq-bg);font-size:1.6rem;cursor:pointer;box-shadow:0 4px 16px #00d4aa66;transition:all .3s cubic-bezier(.4,0,.2,1);display:flex;align-items:center;justify-content:center}.iq-bubble:hover{transform:scale(1.1);box-shadow:0 6px 24px #00d4aa80}.iq-bubble .iq-bubble-icon{font-size:1.5rem;pointer-events:none}.iq-bubble-img{width:60%;height:60%;object-fit:contain;border-radius:50%;pointer-events:none}.iq-bubble-svg{width:60%;height:60%;display:flex;align-items:center;justify-content:center;pointer-events:none}.iq-bubble-svg :deep(svg){width:100%;height:100%}.iq-bubble.iq-open{background:var(--iq-bg-tertiary);color:var(--iq-text);box-shadow:0 4px 12px #0000004d;font-size:1.2rem}.iq-bubble.iq-bottom-left{right:auto;left:24px}.iq-bubble-icon{line-height:1}.iq-panel{position:fixed;bottom:92px;right:24px;z-index:var(--iq-z);width:var(--iq-panel-width);height:var(--iq-panel-height);background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 12px 40px #00000080;animation:iq-slide-up .3s cubic-bezier(.4,0,.2,1)}.iq-panel.iq-bottom-left{right:auto;left:24px}.iq-panel.iq-expanded{width:100vw!important;height:100vh!important;inset:0!important;border-radius:0;z-index:calc(var(--iq-z) + 5);animation:iq-expand .3s cubic-bezier(.4,0,.2,1)}.iq-btn-expand{font-size:1.1rem!important}@keyframes iq-expand{0%{opacity:.8;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes iq-slide-up{0%{opacity:0;transform:translateY(16px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}.iq-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--iq-border);background:var(--iq-bg-card)}.iq-header-title{font-weight:600;font-size:.95rem;color:var(--iq-text)}.iq-header-actions{display:flex;gap:4px}.iq-header-btn{background:none;border:none;color:var(--iq-text-muted);cursor:pointer;font-size:1rem;padding:4px 6px;border-radius:4px;transition:all .15s}.iq-header-btn:hover{color:var(--iq-text);background:#ffffff14}.iq-auth-error{display:flex;align-items:center;gap:8px;padding:10px 16px;background:#dc354526;color:#ff6b7a;font-size:.8rem;border-bottom:1px solid rgba(220,53,69,.25)}.iq-messages{flex:1;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:10px}.iq-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:var(--iq-text-secondary)}.iq-empty-icon{font-size:3rem;margin-bottom:8px;display:flex;align-items:center;justify-content:center}.iq-empty-img{width:48px;height:48px;object-fit:contain;border-radius:8px}.iq-empty-svg{width:48px;height:48px;display:flex;align-items:center;justify-content:center}.iq-empty-svg :deep(svg){width:100%;height:100%}.iq-empty p{font-size:.95rem;margin:2px 0}.iq-text-muted{color:var(--iq-text-muted)!important;font-size:.8rem!important}.iq-msg{display:flex;flex-direction:column;max-width:85%}.iq-msg-user{align-self:flex-end}.iq-msg-bot{align-self:flex-start;max-width:100%}.iq-msg-user .iq-msg-content{background:linear-gradient(135deg,var(--iq-primary),var(--iq-primary-light));border-radius:12px 12px 0}.iq-msg-bot .iq-msg-content{background:var(--iq-bg-tertiary);border-radius:12px 12px 12px 0}.iq-msg-content{padding:10px 14px;color:var(--iq-text);font-size:.85rem;line-height:1.45}.iq-msg-content p{margin:0;white-space:pre-wrap}.iq-msg-time{display:block;margin-top:4px;font-size:.65rem;color:#ffffff80}.iq-md{line-height:1.5;overflow-x:auto;max-width:100%}.iq-md :first-child{margin-top:0}.iq-md :last-child{margin-bottom:0}.iq-md p{margin:0 0 .4em}.iq-md p:last-child{margin-bottom:0}.iq-md strong{color:var(--iq-accent)}.iq-md ul,.iq-md ol{margin:.3em 0;padding-left:1.2em}.iq-md li{margin:.15em 0}.iq-md code{background:#0000004d;padding:.15em .4em;border-radius:3px;font-size:.82em}.iq-md pre{background:#0000004d;padding:.8em;border-radius:6px;overflow-x:auto;font-size:.78em;margin:.4em 0}.iq-md pre code{background:none;padding:0}.iq-md table{width:max-content;min-width:100%;border-collapse:separate;border-spacing:0;margin:.5em 0;font-size:.75rem;border-radius:6px;overflow:hidden}.iq-md thead th{background:#6366f12e;color:#a5b4fc;font-weight:600;text-align:left;padding:.5em .8em;border-bottom:2px solid rgba(99,102,241,.3);white-space:nowrap;font-size:.7rem;text-transform:uppercase;letter-spacing:.05em}.iq-md tbody td{padding:.4em .8em;border-bottom:1px solid rgba(255,255,255,.06);white-space:nowrap;color:var(--iq-text-secondary)}.iq-md tbody tr:hover{background:#6366f114}.iq-btn-trace{align-self:flex-start;margin-top:4px;background:transparent;border:1px solid var(--iq-border);color:var(--iq-text-secondary);font-size:.7rem;padding:3px 8px;border-radius:4px;cursor:pointer;transition:all .15s}.iq-btn-trace:hover{border-color:var(--iq-accent);color:var(--iq-accent)}.iq-pipeline{display:flex;align-items:center;gap:8px;animation:iq-fade-in .3s ease-out}.iq-dot{width:8px;height:8px;border-radius:50%;background:var(--iq-accent);animation:iq-pulse 1s ease-in-out infinite}.iq-pipeline-text{font-size:.8rem;color:var(--iq-text-muted);font-style:italic}@keyframes iq-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(.7)}}@keyframes iq-fade-in{0%{opacity:0;transform:translate(-6px)}to{opacity:1;transform:translate(0)}}.iq-input-bar{display:flex;gap:8px;padding:10px 12px;border-top:1px solid var(--iq-border);background:var(--iq-bg-card)}.iq-input-bar input{flex:1;padding:8px 12px;background:var(--iq-bg-tertiary);border:1px solid var(--iq-border);border-radius:8px;color:var(--iq-text);font-size:.85rem;font-family:var(--iq-font);outline:none;transition:border-color .15s}.iq-input-bar input:focus{border-color:var(--iq-accent)}.iq-input-bar input::placeholder{color:var(--iq-text-muted)}.iq-input-bar input:disabled{opacity:.5}.iq-btn-send{width:36px;height:36px;border-radius:8px;border:none;background:linear-gradient(135deg,var(--iq-accent),var(--iq-accent-light));color:var(--iq-bg);font-size:1rem;cursor:pointer;transition:all .2s;display:flex;align-items:center;justify-content:center}.iq-btn-send:hover:not(:disabled){box-shadow:0 0 12px #00d4aa66;transform:translateY(-1px)}.iq-btn-send:disabled{opacity:.4;cursor:not-allowed}.iq-trace-overlay{position:fixed;inset:0;z-index:calc(var(--iq-z) + 10);background:#0009;display:flex;align-items:center;justify-content:center;animation:iq-fade-in .2s ease-out}.iq-trace-modal{width:90%;max-width:520px;max-height:80vh;background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 20px 50px #0009}.iq-trace-header{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--iq-border)}.iq-trace-header h3{margin:0;font-size:.95rem;color:var(--iq-text)}.iq-trace-body{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px}.iq-trace-item label{display:block;font-size:.7rem;color:var(--iq-text-muted);margin-bottom:4px;text-transform:uppercase;letter-spacing:.05em}.iq-trace-item code{display:block;padding:8px;background:var(--iq-bg-tertiary);border-radius:4px;font-family:monospace;font-size:.8rem;color:var(--iq-accent);word-break:break-all}.iq-trace-item pre{margin:0;padding:8px;background:var(--iq-bg-tertiary);border-radius:4px;font-family:monospace;font-size:.7rem;overflow-x:auto;max-height:180px;color:var(--iq-text-secondary)}.iq-cache-hit{background:#10b98126!important;color:#10b981!important}.iq-query-code{color:var(--iq-accent)!important}.iq-messages::-webkit-scrollbar{width:5px}.iq-messages::-webkit-scrollbar-track{background:transparent}.iq-messages::-webkit-scrollbar-thumb{background:var(--iq-border);border-radius:4px}.iq-trace-body::-webkit-scrollbar{width:5px}.iq-trace-body::-webkit-scrollbar-track{background:transparent}.iq-trace-body::-webkit-scrollbar-thumb{background:var(--iq-border);border-radius:4px}@media(max-width:480px){.iq-bubble{bottom:16px;right:16px;width:48px;height:48px;font-size:1.3rem}.iq-bubble.iq-bottom-left{left:16px}.iq-bubble .iq-bubble-icon{font-size:1.2rem}.iq-panel{right:8px;left:8px;bottom:72px;width:auto!important;max-width:calc(100vw - 16px);height:calc(100dvh - 90px);max-height:calc(100dvh - 90px)}.iq-panel.iq-bottom-left{left:8px;right:8px}.iq-panel.iq-expanded{inset:0!important;width:100vw!important;height:100dvh!important;max-height:100dvh!important;max-width:100vw!important;border-radius:0}.iq-header{padding:10px 12px}.iq-header-title{font-size:.85rem}.iq-header-btn{padding:6px 8px;min-width:32px;min-height:32px}.iq-messages{padding:8px;gap:8px}.iq-msg{max-width:92%}.iq-msg-bot{max-width:100%}.iq-msg-content{padding:8px 10px;font-size:.8rem}.iq-md{overflow-x:auto;-webkit-overflow-scrolling:touch}.iq-md table{font-size:.65rem;min-width:unset}.iq-md thead th{padding:.35em .5em;font-size:.6rem}.iq-md tbody td{padding:.3em .5em;font-size:.65rem}.iq-empty-icon{font-size:2.5rem}.iq-empty p{font-size:.85rem}.iq-input-bar{padding:8px 10px;gap:6px}.iq-input-bar input{font-size:16px;padding:8px 10px}.iq-btn-send{width:38px;height:38px;flex-shrink:0}.iq-trace-modal{width:calc(100vw - 24px);max-height:90dvh}.iq-trace-header{padding:12px}.iq-trace-header h3{font-size:.85rem}.iq-trace-body{padding:12px}.iq-trace-item pre{font-size:.65rem;max-height:140px}}@media(max-height:500px)and (orientation:landscape){.iq-bubble{bottom:8px;right:8px;width:44px;height:44px;font-size:1.1rem}.iq-bubble.iq-bottom-left{left:8px}.iq-panel{inset:8px 60px 8px 8px;width:auto!important;max-width:calc(100vw - 76px);height:auto!important;max-height:calc(100dvh - 16px);border-radius:var(--iq-radius)}.iq-panel.iq-bottom-left{left:60px;right:8px}.iq-header{padding:6px 12px}.iq-header-title{font-size:.8rem}.iq-messages{padding:6px 10px;gap:6px}.iq-empty-icon{font-size:1.8rem;margin-bottom:4px}.iq-empty p{font-size:.78rem;margin:1px 0}.iq-input-bar{padding:6px 10px}.iq-input-bar input{font-size:16px;padding:6px 10px}.iq-btn-send{width:32px;height:32px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "pipe", type: i1.JsonPipe, name: "json" }] });
|
|
900
|
+
`, isInline: true, styles: [":host{--iq-primary: #1a3a5c;--iq-primary-light: #2a5a8c;--iq-accent: #00d4aa;--iq-accent-light: #33e0be;--iq-bg: #1e1e2f;--iq-bg-card: #252538;--iq-bg-tertiary: #35354a;--iq-text: #ffffff;--iq-text-secondary: #a0a0b0;--iq-text-muted: #6c6c7c;--iq-border: #3a3a4d;--iq-radius: 12px;--iq-bubble-size: 56px;--iq-panel-width: 400px;--iq-panel-height: 520px;--iq-z: 10000;--iq-font: \"Inter\", \"Roboto\", -apple-system, BlinkMacSystemFont, sans-serif;font-family:var(--iq-font)}.iq-bubble{position:fixed;bottom:24px;right:24px;z-index:var(--iq-z);width:var(--iq-bubble-size);height:var(--iq-bubble-size);border-radius:50%;border:none;background:linear-gradient(135deg,var(--iq-accent),var(--iq-accent-light));color:var(--iq-bg);font-size:1.6rem;cursor:pointer;box-shadow:0 4px 16px #00d4aa66;transition:all .3s cubic-bezier(.4,0,.2,1);display:flex;align-items:center;justify-content:center}.iq-bubble:hover{transform:scale(1.1);box-shadow:0 6px 24px #00d4aa80}.iq-bubble .iq-bubble-icon{font-size:1.5rem;pointer-events:none}.iq-bubble-img{width:60%;height:60%;object-fit:contain;border-radius:50%;pointer-events:none}.iq-bubble-svg{width:60%;height:60%;display:flex;align-items:center;justify-content:center;pointer-events:none}.iq-bubble-svg :deep(svg){width:100%;height:100%}.iq-bubble.iq-open{background:var(--iq-bg-tertiary);color:var(--iq-text);box-shadow:0 4px 12px #0000004d;font-size:1.2rem}.iq-bubble.iq-bottom-left{right:auto;left:24px}.iq-bubble-icon{line-height:1}.iq-panel{position:fixed;bottom:92px;right:24px;z-index:var(--iq-z);width:var(--iq-panel-width);height:var(--iq-panel-height);background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 12px 40px #00000080;animation:iq-slide-up .3s cubic-bezier(.4,0,.2,1)}.iq-panel.iq-bottom-left{right:auto;left:24px}.iq-panel.iq-expanded{width:100vw!important;height:100vh!important;inset:0!important;border:none;border-radius:0;overflow:clip;z-index:calc(var(--iq-z) + 5);animation:iq-expand .3s cubic-bezier(.4,0,.2,1)}.iq-btn-expand{font-size:1.1rem!important}@keyframes iq-expand{0%{opacity:.8;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes iq-slide-up{0%{opacity:0;transform:translateY(16px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}.iq-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--iq-border);background:var(--iq-bg-card)}.iq-header-title{font-weight:600;font-size:.95rem;color:var(--iq-text)}.iq-header-actions{display:flex;gap:4px}.iq-header-btn{background:none;border:none;color:var(--iq-text-muted);cursor:pointer;font-size:1rem;padding:4px 6px;border-radius:4px;transition:all .15s}.iq-header-btn:hover{color:var(--iq-text);background:#ffffff14}.iq-auth-error{display:flex;align-items:center;gap:8px;padding:10px 16px;background:#dc354526;color:#ff6b7a;font-size:.8rem;border-bottom:1px solid rgba(220,53,69,.25)}.iq-messages{flex:1;min-height:0;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:10px}.iq-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:var(--iq-text-secondary)}.iq-empty-icon{font-size:3rem;margin-bottom:8px;display:flex;align-items:center;justify-content:center}.iq-empty-img{width:48px;height:48px;object-fit:contain;border-radius:8px}.iq-empty-svg{width:48px;height:48px;display:flex;align-items:center;justify-content:center}.iq-empty-svg :deep(svg){width:100%;height:100%}.iq-empty p{font-size:.95rem;margin:2px 0}.iq-text-muted{color:var(--iq-text-muted)!important;font-size:.8rem!important}.iq-msg{display:flex;flex-direction:column;max-width:85%}.iq-msg-user{align-self:flex-end}.iq-msg-bot{align-self:flex-start;max-width:100%}.iq-msg-user .iq-msg-content{background:linear-gradient(135deg,var(--iq-primary),var(--iq-primary-light));border-radius:12px 12px 0}.iq-msg-bot .iq-msg-content{background:var(--iq-bg-tertiary);border-radius:12px 12px 12px 0}.iq-msg-content{padding:10px 14px;color:var(--iq-text);font-size:.85rem;line-height:1.45}.iq-msg-content p{margin:0;white-space:pre-wrap}.iq-msg-time{display:block;margin-top:4px;font-size:.65rem;color:#ffffff80}.iq-md{line-height:1.5;overflow-x:auto;max-width:100%}.iq-md :first-child{margin-top:0}.iq-md :last-child{margin-bottom:0}.iq-md p{margin:0 0 .4em}.iq-md p:last-child{margin-bottom:0}.iq-md strong{color:var(--iq-accent)}.iq-md ul,.iq-md ol{margin:.3em 0;padding-left:1.2em}.iq-md li{margin:.15em 0}.iq-md code{background:#0000004d;padding:.15em .4em;border-radius:3px;font-size:.82em}.iq-md pre{background:#0000004d;padding:.8em;border-radius:6px;overflow-x:auto;font-size:.78em;margin:.4em 0}.iq-md pre code{background:none;padding:0}.iq-md table{width:max-content;min-width:100%;border-collapse:separate;border-spacing:0;margin:.5em 0;font-size:.75rem;border-radius:6px;overflow:hidden}.iq-md thead th{background:#6366f12e;color:#a5b4fc;font-weight:600;text-align:left;padding:.5em .8em;border-bottom:2px solid rgba(99,102,241,.3);white-space:nowrap;font-size:.7rem;text-transform:uppercase;letter-spacing:.05em}.iq-md tbody td{padding:.4em .8em;border-bottom:1px solid rgba(255,255,255,.06);white-space:nowrap;color:var(--iq-text-secondary)}.iq-md tbody tr:hover{background:#6366f114}.iq-md img{max-height:80px;max-width:120px;object-fit:cover;border-radius:8px;margin:6px 4px 6px 0;display:inline-block;vertical-align:middle;border:1px solid rgba(255,255,255,.15);box-shadow:0 1px 4px #00000040;cursor:pointer;transition:transform .15s,box-shadow .15s}.iq-md img:hover{transform:scale(1.05);box-shadow:0 3px 12px #6366f159;border-color:var(--iq-accent)}.iq-md img[alt*=logo],.iq-md img[alt*=marca]{max-height:28px;max-width:90px;object-fit:contain;border:none;box-shadow:none;border-radius:4px;background:#ffffffe6;padding:2px 6px}.iq-btn-trace{align-self:flex-start;margin-top:4px;background:transparent;border:1px solid var(--iq-border);color:var(--iq-text-secondary);font-size:.7rem;padding:3px 8px;border-radius:4px;cursor:pointer;transition:all .15s}.iq-btn-trace:hover{border-color:var(--iq-accent);color:var(--iq-accent)}.iq-pipeline{display:flex;align-items:center;gap:8px;animation:iq-fade-in .3s ease-out}.iq-dot{width:8px;height:8px;border-radius:50%;background:var(--iq-accent);animation:iq-pulse 1s ease-in-out infinite}.iq-pipeline-text{font-size:.8rem;color:var(--iq-text-muted);font-style:italic}@keyframes iq-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(.7)}}@keyframes iq-fade-in{0%{opacity:0;transform:translate(-6px)}to{opacity:1;transform:translate(0)}}.iq-input-bar{display:flex;gap:8px;padding:10px 12px;border-top:1px solid var(--iq-border);background:var(--iq-bg-card)}.iq-input-bar input{flex:1;padding:8px 12px;background:var(--iq-bg-tertiary);border:1px solid var(--iq-border);border-radius:8px;color:var(--iq-text);font-size:.85rem;font-family:var(--iq-font);outline:none;transition:border-color .15s}.iq-input-bar input:focus{border-color:var(--iq-accent)}.iq-input-bar input::placeholder{color:var(--iq-text-muted)}.iq-input-bar input:disabled{opacity:.5}.iq-btn-send{width:36px;height:36px;border-radius:8px;border:none;background:linear-gradient(135deg,var(--iq-accent),var(--iq-accent-light));color:var(--iq-bg);font-size:1rem;cursor:pointer;transition:all .2s;display:flex;align-items:center;justify-content:center}.iq-btn-send:hover:not(:disabled){box-shadow:0 0 12px #00d4aa66;transform:translateY(-1px)}.iq-btn-send:disabled{opacity:.4;cursor:not-allowed}.iq-trace-overlay{position:fixed;inset:0;z-index:calc(var(--iq-z) + 10);background:#0009;display:flex;align-items:center;justify-content:center;animation:iq-fade-in .2s ease-out}.iq-trace-modal{width:90%;max-width:520px;max-height:80vh;background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 20px 50px #0009}.iq-trace-header{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--iq-border)}.iq-trace-header h3{margin:0;font-size:.95rem;color:var(--iq-text)}.iq-trace-body{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px}.iq-trace-item label{display:block;font-size:.7rem;color:var(--iq-text-muted);margin-bottom:4px;text-transform:uppercase;letter-spacing:.05em}.iq-trace-item code{display:block;padding:8px;background:var(--iq-bg-tertiary);border-radius:4px;font-family:monospace;font-size:.8rem;color:var(--iq-accent);word-break:break-all}.iq-trace-item pre{margin:0;padding:8px;background:var(--iq-bg-tertiary);border-radius:4px;font-family:monospace;font-size:.7rem;overflow-x:auto;max-height:180px;color:var(--iq-text-secondary)}.iq-cache-hit{background:#10b98126!important;color:#10b981!important}.iq-query-code{color:var(--iq-accent)!important}.iq-link-overlay{position:fixed;inset:0;z-index:calc(var(--iq-z) + 20);background:#000000b3;display:flex;align-items:center;justify-content:center;animation:iq-fade-in .2s ease-out;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.iq-link-modal{width:94vw;height:92vh;background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 24px 60px #000000b3;animation:iq-expand .25s cubic-bezier(.4,0,.2,1)}.iq-link-header{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;border-bottom:1px solid var(--iq-border);background:var(--iq-bg-card);gap:12px;min-height:44px}.iq-link-title{flex:1;font-size:.78rem;color:var(--iq-text-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:monospace}.iq-link-actions{display:flex;gap:4px;flex-shrink:0}.iq-link-actions a{text-decoration:none}.iq-back-btn{flex-shrink:0;font-size:1.1rem;transition:transform .15s ease}.iq-back-btn:hover{transform:translate(-2px)}.iq-iframe-wrapper{flex:1;position:relative;overflow:hidden}.iq-link-iframe{width:100%;height:100%;border:none;background:#fff;transition:opacity .3s ease}.iq-iframe-hidden{opacity:0}.iq-modal-img{width:100%;height:100%;object-fit:contain;background:#1a1a2e}.iq-iframe-loader{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:var(--iq-bg);gap:16px;z-index:2}.iq-spinner{width:40px;height:40px;border:3px solid var(--iq-border);border-top-color:var(--iq-accent);border-radius:50%;animation:iq-spin .8s linear infinite}.iq-loader-text{font-size:.85rem;color:var(--iq-text-secondary);font-weight:500}@keyframes iq-spin{to{transform:rotate(360deg)}}.iq-md a{color:var(--iq-accent);text-decoration:underline;cursor:pointer;transition:color .15s}.iq-md a:hover{color:var(--iq-accent-light)}@media(max-width:480px){.iq-link-modal{width:100vw;height:100dvh;border-radius:0}.iq-link-header{padding:8px 12px}.iq-link-title{font-size:.7rem}}.iq-messages::-webkit-scrollbar{width:5px}.iq-messages::-webkit-scrollbar-track{background:transparent}.iq-messages::-webkit-scrollbar-thumb{background:var(--iq-border);border-radius:4px}.iq-trace-body::-webkit-scrollbar{width:5px}.iq-trace-body::-webkit-scrollbar-track{background:transparent}.iq-trace-body::-webkit-scrollbar-thumb{background:var(--iq-border);border-radius:4px}.iq-expanded .iq-messages::-webkit-scrollbar{width:8px}.iq-expanded .iq-messages{scrollbar-gutter:stable}@media(max-width:480px){.iq-bubble{bottom:16px;right:16px;width:48px;height:48px;font-size:1.3rem}.iq-bubble.iq-bottom-left{left:16px}.iq-bubble .iq-bubble-icon{font-size:1.2rem}.iq-panel{right:8px;left:8px;bottom:72px;width:auto!important;max-width:calc(100vw - 16px);height:calc(100dvh - 90px);max-height:calc(100dvh - 90px)}.iq-panel.iq-bottom-left{left:8px;right:8px}.iq-panel.iq-expanded{inset:0!important;width:100vw!important;height:100dvh!important;max-height:100dvh!important;max-width:100vw!important;border-radius:0}.iq-header{padding:10px 12px}.iq-header-title{font-size:.85rem}.iq-header-btn{padding:6px 8px;min-width:32px;min-height:32px}.iq-messages{padding:8px;gap:8px}.iq-msg{max-width:92%}.iq-msg-bot{max-width:100%}.iq-msg-content{padding:8px 10px;font-size:.8rem}.iq-md{overflow-x:auto;-webkit-overflow-scrolling:touch}.iq-md table{font-size:.65rem;min-width:unset}.iq-md thead th{padding:.35em .5em;font-size:.6rem}.iq-md tbody td{padding:.3em .5em;font-size:.65rem}.iq-empty-icon{font-size:2.5rem}.iq-empty p{font-size:.85rem}.iq-input-bar{padding:8px 10px;gap:6px}.iq-input-bar input{font-size:16px;padding:8px 10px}.iq-btn-send{width:38px;height:38px;flex-shrink:0}.iq-trace-modal{width:calc(100vw - 24px);max-height:90dvh}.iq-trace-header{padding:12px}.iq-trace-header h3{font-size:.85rem}.iq-trace-body{padding:12px}.iq-trace-item pre{font-size:.65rem;max-height:140px}}@media(max-height:500px)and (orientation:landscape){.iq-bubble{bottom:8px;right:8px;width:44px;height:44px;font-size:1.1rem}.iq-bubble.iq-bottom-left{left:8px}.iq-panel{inset:8px 60px 8px 8px;width:auto!important;max-width:calc(100vw - 76px);height:auto!important;max-height:calc(100dvh - 16px);border-radius:var(--iq-radius)}.iq-panel.iq-bottom-left{left:60px;right:8px}.iq-panel.iq-expanded{inset:0!important;width:100vw!important;height:100dvh!important;max-height:100dvh!important;max-width:100vw!important;border-radius:0}.iq-header{padding:6px 12px}.iq-header-title{font-size:.8rem}.iq-messages{padding:6px 10px;gap:6px}.iq-empty-icon{font-size:1.8rem;margin-bottom:4px}.iq-empty p{font-size:.78rem;margin:1px 0}.iq-input-bar{padding:6px 10px}.iq-input-bar input{font-size:16px;padding:6px 10px}.iq-btn-send{width:32px;height:32px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "pipe", type: i1.JsonPipe, name: "json" }] });
|
|
776
901
|
}
|
|
777
902
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: IntelligentChatPluginComponent, decorators: [{
|
|
778
903
|
type: Component,
|
|
@@ -865,7 +990,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImpor
|
|
|
865
990
|
<div class="iq-msg" [class.iq-msg-user]="msg.sender === 'user'" [class.iq-msg-bot]="msg.sender === 'bot'">
|
|
866
991
|
<div class="iq-msg-content">
|
|
867
992
|
@if (msg.sender === 'bot') {
|
|
868
|
-
<div class="iq-md" [innerHTML]="renderMarkdown(msg.text)"></div>
|
|
993
|
+
<div class="iq-md" [innerHTML]="renderMarkdown(msg.text)" (click)="onMessageClick($event)"></div>
|
|
869
994
|
} @else {
|
|
870
995
|
<p>{{ msg.text }}</p>
|
|
871
996
|
}
|
|
@@ -949,8 +1074,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImpor
|
|
|
949
1074
|
</div>
|
|
950
1075
|
}
|
|
951
1076
|
|
|
1077
|
+
<!-- Link Modal Overlay -->
|
|
1078
|
+
@if (modalUrl()) {
|
|
1079
|
+
<div class="iq-link-overlay" (click)="closeLinkModal()">
|
|
1080
|
+
<div class="iq-link-modal" (click)="$event.stopPropagation()">
|
|
1081
|
+
<div class="iq-link-header">
|
|
1082
|
+
@if (showHomeBtn()) {
|
|
1083
|
+
<button class="iq-header-btn iq-back-btn" (click)="iframeGoHome()" title="Volver al inicio">🏠</button>
|
|
1084
|
+
}
|
|
1085
|
+
<span class="iq-link-title" [title]="modalUrl()!">{{ modalUrl() }}</span>
|
|
1086
|
+
<div class="iq-link-actions">
|
|
1087
|
+
<a [href]="modalUrl()!" target="_blank" rel="noopener" class="iq-header-btn" title="Abrir en nueva pestaña">↗</a>
|
|
1088
|
+
<button class="iq-header-btn" (click)="closeLinkModal()">✕</button>
|
|
1089
|
+
</div>
|
|
1090
|
+
</div>
|
|
1091
|
+
<div class="iq-iframe-wrapper">
|
|
1092
|
+
@if (isModalImage()) {
|
|
1093
|
+
<img [src]="modalUrl()!" class="iq-modal-img" alt="Imagen" />
|
|
1094
|
+
} @else {
|
|
1095
|
+
@if (modalLoading()) {
|
|
1096
|
+
<div class="iq-iframe-loader">
|
|
1097
|
+
<div class="iq-spinner"></div>
|
|
1098
|
+
<span class="iq-loader-text">Cargando...</span>
|
|
1099
|
+
</div>
|
|
1100
|
+
}
|
|
1101
|
+
<iframe #linkIframe [src]="sanitizedModalUrl()" class="iq-link-iframe"
|
|
1102
|
+
[class.iq-iframe-hidden]="modalLoading()"
|
|
1103
|
+
(load)="onIframeLoaded()"></iframe>
|
|
1104
|
+
}
|
|
1105
|
+
</div>
|
|
1106
|
+
</div>
|
|
1107
|
+
</div>
|
|
1108
|
+
}
|
|
1109
|
+
|
|
952
1110
|
</div><!-- /iq-theme-host -->
|
|
953
|
-
`, styles: [":host{--iq-primary: #1a3a5c;--iq-primary-light: #2a5a8c;--iq-accent: #00d4aa;--iq-accent-light: #33e0be;--iq-bg: #1e1e2f;--iq-bg-card: #252538;--iq-bg-tertiary: #35354a;--iq-text: #ffffff;--iq-text-secondary: #a0a0b0;--iq-text-muted: #6c6c7c;--iq-border: #3a3a4d;--iq-radius: 12px;--iq-bubble-size: 56px;--iq-panel-width: 400px;--iq-panel-height: 520px;--iq-z: 10000;--iq-font: \"Inter\", \"Roboto\", -apple-system, BlinkMacSystemFont, sans-serif;font-family:var(--iq-font)}.iq-bubble{position:fixed;bottom:24px;right:24px;z-index:var(--iq-z);width:var(--iq-bubble-size);height:var(--iq-bubble-size);border-radius:50%;border:none;background:linear-gradient(135deg,var(--iq-accent),var(--iq-accent-light));color:var(--iq-bg);font-size:1.6rem;cursor:pointer;box-shadow:0 4px 16px #00d4aa66;transition:all .3s cubic-bezier(.4,0,.2,1);display:flex;align-items:center;justify-content:center}.iq-bubble:hover{transform:scale(1.1);box-shadow:0 6px 24px #00d4aa80}.iq-bubble .iq-bubble-icon{font-size:1.5rem;pointer-events:none}.iq-bubble-img{width:60%;height:60%;object-fit:contain;border-radius:50%;pointer-events:none}.iq-bubble-svg{width:60%;height:60%;display:flex;align-items:center;justify-content:center;pointer-events:none}.iq-bubble-svg :deep(svg){width:100%;height:100%}.iq-bubble.iq-open{background:var(--iq-bg-tertiary);color:var(--iq-text);box-shadow:0 4px 12px #0000004d;font-size:1.2rem}.iq-bubble.iq-bottom-left{right:auto;left:24px}.iq-bubble-icon{line-height:1}.iq-panel{position:fixed;bottom:92px;right:24px;z-index:var(--iq-z);width:var(--iq-panel-width);height:var(--iq-panel-height);background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 12px 40px #00000080;animation:iq-slide-up .3s cubic-bezier(.4,0,.2,1)}.iq-panel.iq-bottom-left{right:auto;left:24px}.iq-panel.iq-expanded{width:100vw!important;height:100vh!important;inset:0!important;border-radius:0;z-index:calc(var(--iq-z) + 5);animation:iq-expand .3s cubic-bezier(.4,0,.2,1)}.iq-btn-expand{font-size:1.1rem!important}@keyframes iq-expand{0%{opacity:.8;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes iq-slide-up{0%{opacity:0;transform:translateY(16px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}.iq-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--iq-border);background:var(--iq-bg-card)}.iq-header-title{font-weight:600;font-size:.95rem;color:var(--iq-text)}.iq-header-actions{display:flex;gap:4px}.iq-header-btn{background:none;border:none;color:var(--iq-text-muted);cursor:pointer;font-size:1rem;padding:4px 6px;border-radius:4px;transition:all .15s}.iq-header-btn:hover{color:var(--iq-text);background:#ffffff14}.iq-auth-error{display:flex;align-items:center;gap:8px;padding:10px 16px;background:#dc354526;color:#ff6b7a;font-size:.8rem;border-bottom:1px solid rgba(220,53,69,.25)}.iq-messages{flex:1;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:10px}.iq-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:var(--iq-text-secondary)}.iq-empty-icon{font-size:3rem;margin-bottom:8px;display:flex;align-items:center;justify-content:center}.iq-empty-img{width:48px;height:48px;object-fit:contain;border-radius:8px}.iq-empty-svg{width:48px;height:48px;display:flex;align-items:center;justify-content:center}.iq-empty-svg :deep(svg){width:100%;height:100%}.iq-empty p{font-size:.95rem;margin:2px 0}.iq-text-muted{color:var(--iq-text-muted)!important;font-size:.8rem!important}.iq-msg{display:flex;flex-direction:column;max-width:85%}.iq-msg-user{align-self:flex-end}.iq-msg-bot{align-self:flex-start;max-width:100%}.iq-msg-user .iq-msg-content{background:linear-gradient(135deg,var(--iq-primary),var(--iq-primary-light));border-radius:12px 12px 0}.iq-msg-bot .iq-msg-content{background:var(--iq-bg-tertiary);border-radius:12px 12px 12px 0}.iq-msg-content{padding:10px 14px;color:var(--iq-text);font-size:.85rem;line-height:1.45}.iq-msg-content p{margin:0;white-space:pre-wrap}.iq-msg-time{display:block;margin-top:4px;font-size:.65rem;color:#ffffff80}.iq-md{line-height:1.5;overflow-x:auto;max-width:100%}.iq-md :first-child{margin-top:0}.iq-md :last-child{margin-bottom:0}.iq-md p{margin:0 0 .4em}.iq-md p:last-child{margin-bottom:0}.iq-md strong{color:var(--iq-accent)}.iq-md ul,.iq-md ol{margin:.3em 0;padding-left:1.2em}.iq-md li{margin:.15em 0}.iq-md code{background:#0000004d;padding:.15em .4em;border-radius:3px;font-size:.82em}.iq-md pre{background:#0000004d;padding:.8em;border-radius:6px;overflow-x:auto;font-size:.78em;margin:.4em 0}.iq-md pre code{background:none;padding:0}.iq-md table{width:max-content;min-width:100%;border-collapse:separate;border-spacing:0;margin:.5em 0;font-size:.75rem;border-radius:6px;overflow:hidden}.iq-md thead th{background:#6366f12e;color:#a5b4fc;font-weight:600;text-align:left;padding:.5em .8em;border-bottom:2px solid rgba(99,102,241,.3);white-space:nowrap;font-size:.7rem;text-transform:uppercase;letter-spacing:.05em}.iq-md tbody td{padding:.4em .8em;border-bottom:1px solid rgba(255,255,255,.06);white-space:nowrap;color:var(--iq-text-secondary)}.iq-md tbody tr:hover{background:#6366f114}.iq-btn-trace{align-self:flex-start;margin-top:4px;background:transparent;border:1px solid var(--iq-border);color:var(--iq-text-secondary);font-size:.7rem;padding:3px 8px;border-radius:4px;cursor:pointer;transition:all .15s}.iq-btn-trace:hover{border-color:var(--iq-accent);color:var(--iq-accent)}.iq-pipeline{display:flex;align-items:center;gap:8px;animation:iq-fade-in .3s ease-out}.iq-dot{width:8px;height:8px;border-radius:50%;background:var(--iq-accent);animation:iq-pulse 1s ease-in-out infinite}.iq-pipeline-text{font-size:.8rem;color:var(--iq-text-muted);font-style:italic}@keyframes iq-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(.7)}}@keyframes iq-fade-in{0%{opacity:0;transform:translate(-6px)}to{opacity:1;transform:translate(0)}}.iq-input-bar{display:flex;gap:8px;padding:10px 12px;border-top:1px solid var(--iq-border);background:var(--iq-bg-card)}.iq-input-bar input{flex:1;padding:8px 12px;background:var(--iq-bg-tertiary);border:1px solid var(--iq-border);border-radius:8px;color:var(--iq-text);font-size:.85rem;font-family:var(--iq-font);outline:none;transition:border-color .15s}.iq-input-bar input:focus{border-color:var(--iq-accent)}.iq-input-bar input::placeholder{color:var(--iq-text-muted)}.iq-input-bar input:disabled{opacity:.5}.iq-btn-send{width:36px;height:36px;border-radius:8px;border:none;background:linear-gradient(135deg,var(--iq-accent),var(--iq-accent-light));color:var(--iq-bg);font-size:1rem;cursor:pointer;transition:all .2s;display:flex;align-items:center;justify-content:center}.iq-btn-send:hover:not(:disabled){box-shadow:0 0 12px #00d4aa66;transform:translateY(-1px)}.iq-btn-send:disabled{opacity:.4;cursor:not-allowed}.iq-trace-overlay{position:fixed;inset:0;z-index:calc(var(--iq-z) + 10);background:#0009;display:flex;align-items:center;justify-content:center;animation:iq-fade-in .2s ease-out}.iq-trace-modal{width:90%;max-width:520px;max-height:80vh;background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 20px 50px #0009}.iq-trace-header{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--iq-border)}.iq-trace-header h3{margin:0;font-size:.95rem;color:var(--iq-text)}.iq-trace-body{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px}.iq-trace-item label{display:block;font-size:.7rem;color:var(--iq-text-muted);margin-bottom:4px;text-transform:uppercase;letter-spacing:.05em}.iq-trace-item code{display:block;padding:8px;background:var(--iq-bg-tertiary);border-radius:4px;font-family:monospace;font-size:.8rem;color:var(--iq-accent);word-break:break-all}.iq-trace-item pre{margin:0;padding:8px;background:var(--iq-bg-tertiary);border-radius:4px;font-family:monospace;font-size:.7rem;overflow-x:auto;max-height:180px;color:var(--iq-text-secondary)}.iq-cache-hit{background:#10b98126!important;color:#10b981!important}.iq-query-code{color:var(--iq-accent)!important}.iq-messages::-webkit-scrollbar{width:5px}.iq-messages::-webkit-scrollbar-track{background:transparent}.iq-messages::-webkit-scrollbar-thumb{background:var(--iq-border);border-radius:4px}.iq-trace-body::-webkit-scrollbar{width:5px}.iq-trace-body::-webkit-scrollbar-track{background:transparent}.iq-trace-body::-webkit-scrollbar-thumb{background:var(--iq-border);border-radius:4px}@media(max-width:480px){.iq-bubble{bottom:16px;right:16px;width:48px;height:48px;font-size:1.3rem}.iq-bubble.iq-bottom-left{left:16px}.iq-bubble .iq-bubble-icon{font-size:1.2rem}.iq-panel{right:8px;left:8px;bottom:72px;width:auto!important;max-width:calc(100vw - 16px);height:calc(100dvh - 90px);max-height:calc(100dvh - 90px)}.iq-panel.iq-bottom-left{left:8px;right:8px}.iq-panel.iq-expanded{inset:0!important;width:100vw!important;height:100dvh!important;max-height:100dvh!important;max-width:100vw!important;border-radius:0}.iq-header{padding:10px 12px}.iq-header-title{font-size:.85rem}.iq-header-btn{padding:6px 8px;min-width:32px;min-height:32px}.iq-messages{padding:8px;gap:8px}.iq-msg{max-width:92%}.iq-msg-bot{max-width:100%}.iq-msg-content{padding:8px 10px;font-size:.8rem}.iq-md{overflow-x:auto;-webkit-overflow-scrolling:touch}.iq-md table{font-size:.65rem;min-width:unset}.iq-md thead th{padding:.35em .5em;font-size:.6rem}.iq-md tbody td{padding:.3em .5em;font-size:.65rem}.iq-empty-icon{font-size:2.5rem}.iq-empty p{font-size:.85rem}.iq-input-bar{padding:8px 10px;gap:6px}.iq-input-bar input{font-size:16px;padding:8px 10px}.iq-btn-send{width:38px;height:38px;flex-shrink:0}.iq-trace-modal{width:calc(100vw - 24px);max-height:90dvh}.iq-trace-header{padding:12px}.iq-trace-header h3{font-size:.85rem}.iq-trace-body{padding:12px}.iq-trace-item pre{font-size:.65rem;max-height:140px}}@media(max-height:500px)and (orientation:landscape){.iq-bubble{bottom:8px;right:8px;width:44px;height:44px;font-size:1.1rem}.iq-bubble.iq-bottom-left{left:8px}.iq-panel{inset:8px 60px 8px 8px;width:auto!important;max-width:calc(100vw - 76px);height:auto!important;max-height:calc(100dvh - 16px);border-radius:var(--iq-radius)}.iq-panel.iq-bottom-left{left:60px;right:8px}.iq-header{padding:6px 12px}.iq-header-title{font-size:.8rem}.iq-messages{padding:6px 10px;gap:6px}.iq-empty-icon{font-size:1.8rem;margin-bottom:4px}.iq-empty p{font-size:.78rem;margin:1px 0}.iq-input-bar{padding:6px 10px}.iq-input-bar input{font-size:16px;padding:6px 10px}.iq-btn-send{width:32px;height:32px}}\n"] }]
|
|
1111
|
+
`, styles: [":host{--iq-primary: #1a3a5c;--iq-primary-light: #2a5a8c;--iq-accent: #00d4aa;--iq-accent-light: #33e0be;--iq-bg: #1e1e2f;--iq-bg-card: #252538;--iq-bg-tertiary: #35354a;--iq-text: #ffffff;--iq-text-secondary: #a0a0b0;--iq-text-muted: #6c6c7c;--iq-border: #3a3a4d;--iq-radius: 12px;--iq-bubble-size: 56px;--iq-panel-width: 400px;--iq-panel-height: 520px;--iq-z: 10000;--iq-font: \"Inter\", \"Roboto\", -apple-system, BlinkMacSystemFont, sans-serif;font-family:var(--iq-font)}.iq-bubble{position:fixed;bottom:24px;right:24px;z-index:var(--iq-z);width:var(--iq-bubble-size);height:var(--iq-bubble-size);border-radius:50%;border:none;background:linear-gradient(135deg,var(--iq-accent),var(--iq-accent-light));color:var(--iq-bg);font-size:1.6rem;cursor:pointer;box-shadow:0 4px 16px #00d4aa66;transition:all .3s cubic-bezier(.4,0,.2,1);display:flex;align-items:center;justify-content:center}.iq-bubble:hover{transform:scale(1.1);box-shadow:0 6px 24px #00d4aa80}.iq-bubble .iq-bubble-icon{font-size:1.5rem;pointer-events:none}.iq-bubble-img{width:60%;height:60%;object-fit:contain;border-radius:50%;pointer-events:none}.iq-bubble-svg{width:60%;height:60%;display:flex;align-items:center;justify-content:center;pointer-events:none}.iq-bubble-svg :deep(svg){width:100%;height:100%}.iq-bubble.iq-open{background:var(--iq-bg-tertiary);color:var(--iq-text);box-shadow:0 4px 12px #0000004d;font-size:1.2rem}.iq-bubble.iq-bottom-left{right:auto;left:24px}.iq-bubble-icon{line-height:1}.iq-panel{position:fixed;bottom:92px;right:24px;z-index:var(--iq-z);width:var(--iq-panel-width);height:var(--iq-panel-height);background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 12px 40px #00000080;animation:iq-slide-up .3s cubic-bezier(.4,0,.2,1)}.iq-panel.iq-bottom-left{right:auto;left:24px}.iq-panel.iq-expanded{width:100vw!important;height:100vh!important;inset:0!important;border:none;border-radius:0;overflow:clip;z-index:calc(var(--iq-z) + 5);animation:iq-expand .3s cubic-bezier(.4,0,.2,1)}.iq-btn-expand{font-size:1.1rem!important}@keyframes iq-expand{0%{opacity:.8;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes iq-slide-up{0%{opacity:0;transform:translateY(16px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}.iq-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--iq-border);background:var(--iq-bg-card)}.iq-header-title{font-weight:600;font-size:.95rem;color:var(--iq-text)}.iq-header-actions{display:flex;gap:4px}.iq-header-btn{background:none;border:none;color:var(--iq-text-muted);cursor:pointer;font-size:1rem;padding:4px 6px;border-radius:4px;transition:all .15s}.iq-header-btn:hover{color:var(--iq-text);background:#ffffff14}.iq-auth-error{display:flex;align-items:center;gap:8px;padding:10px 16px;background:#dc354526;color:#ff6b7a;font-size:.8rem;border-bottom:1px solid rgba(220,53,69,.25)}.iq-messages{flex:1;min-height:0;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:10px}.iq-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:var(--iq-text-secondary)}.iq-empty-icon{font-size:3rem;margin-bottom:8px;display:flex;align-items:center;justify-content:center}.iq-empty-img{width:48px;height:48px;object-fit:contain;border-radius:8px}.iq-empty-svg{width:48px;height:48px;display:flex;align-items:center;justify-content:center}.iq-empty-svg :deep(svg){width:100%;height:100%}.iq-empty p{font-size:.95rem;margin:2px 0}.iq-text-muted{color:var(--iq-text-muted)!important;font-size:.8rem!important}.iq-msg{display:flex;flex-direction:column;max-width:85%}.iq-msg-user{align-self:flex-end}.iq-msg-bot{align-self:flex-start;max-width:100%}.iq-msg-user .iq-msg-content{background:linear-gradient(135deg,var(--iq-primary),var(--iq-primary-light));border-radius:12px 12px 0}.iq-msg-bot .iq-msg-content{background:var(--iq-bg-tertiary);border-radius:12px 12px 12px 0}.iq-msg-content{padding:10px 14px;color:var(--iq-text);font-size:.85rem;line-height:1.45}.iq-msg-content p{margin:0;white-space:pre-wrap}.iq-msg-time{display:block;margin-top:4px;font-size:.65rem;color:#ffffff80}.iq-md{line-height:1.5;overflow-x:auto;max-width:100%}.iq-md :first-child{margin-top:0}.iq-md :last-child{margin-bottom:0}.iq-md p{margin:0 0 .4em}.iq-md p:last-child{margin-bottom:0}.iq-md strong{color:var(--iq-accent)}.iq-md ul,.iq-md ol{margin:.3em 0;padding-left:1.2em}.iq-md li{margin:.15em 0}.iq-md code{background:#0000004d;padding:.15em .4em;border-radius:3px;font-size:.82em}.iq-md pre{background:#0000004d;padding:.8em;border-radius:6px;overflow-x:auto;font-size:.78em;margin:.4em 0}.iq-md pre code{background:none;padding:0}.iq-md table{width:max-content;min-width:100%;border-collapse:separate;border-spacing:0;margin:.5em 0;font-size:.75rem;border-radius:6px;overflow:hidden}.iq-md thead th{background:#6366f12e;color:#a5b4fc;font-weight:600;text-align:left;padding:.5em .8em;border-bottom:2px solid rgba(99,102,241,.3);white-space:nowrap;font-size:.7rem;text-transform:uppercase;letter-spacing:.05em}.iq-md tbody td{padding:.4em .8em;border-bottom:1px solid rgba(255,255,255,.06);white-space:nowrap;color:var(--iq-text-secondary)}.iq-md tbody tr:hover{background:#6366f114}.iq-md img{max-height:80px;max-width:120px;object-fit:cover;border-radius:8px;margin:6px 4px 6px 0;display:inline-block;vertical-align:middle;border:1px solid rgba(255,255,255,.15);box-shadow:0 1px 4px #00000040;cursor:pointer;transition:transform .15s,box-shadow .15s}.iq-md img:hover{transform:scale(1.05);box-shadow:0 3px 12px #6366f159;border-color:var(--iq-accent)}.iq-md img[alt*=logo],.iq-md img[alt*=marca]{max-height:28px;max-width:90px;object-fit:contain;border:none;box-shadow:none;border-radius:4px;background:#ffffffe6;padding:2px 6px}.iq-btn-trace{align-self:flex-start;margin-top:4px;background:transparent;border:1px solid var(--iq-border);color:var(--iq-text-secondary);font-size:.7rem;padding:3px 8px;border-radius:4px;cursor:pointer;transition:all .15s}.iq-btn-trace:hover{border-color:var(--iq-accent);color:var(--iq-accent)}.iq-pipeline{display:flex;align-items:center;gap:8px;animation:iq-fade-in .3s ease-out}.iq-dot{width:8px;height:8px;border-radius:50%;background:var(--iq-accent);animation:iq-pulse 1s ease-in-out infinite}.iq-pipeline-text{font-size:.8rem;color:var(--iq-text-muted);font-style:italic}@keyframes iq-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(.7)}}@keyframes iq-fade-in{0%{opacity:0;transform:translate(-6px)}to{opacity:1;transform:translate(0)}}.iq-input-bar{display:flex;gap:8px;padding:10px 12px;border-top:1px solid var(--iq-border);background:var(--iq-bg-card)}.iq-input-bar input{flex:1;padding:8px 12px;background:var(--iq-bg-tertiary);border:1px solid var(--iq-border);border-radius:8px;color:var(--iq-text);font-size:.85rem;font-family:var(--iq-font);outline:none;transition:border-color .15s}.iq-input-bar input:focus{border-color:var(--iq-accent)}.iq-input-bar input::placeholder{color:var(--iq-text-muted)}.iq-input-bar input:disabled{opacity:.5}.iq-btn-send{width:36px;height:36px;border-radius:8px;border:none;background:linear-gradient(135deg,var(--iq-accent),var(--iq-accent-light));color:var(--iq-bg);font-size:1rem;cursor:pointer;transition:all .2s;display:flex;align-items:center;justify-content:center}.iq-btn-send:hover:not(:disabled){box-shadow:0 0 12px #00d4aa66;transform:translateY(-1px)}.iq-btn-send:disabled{opacity:.4;cursor:not-allowed}.iq-trace-overlay{position:fixed;inset:0;z-index:calc(var(--iq-z) + 10);background:#0009;display:flex;align-items:center;justify-content:center;animation:iq-fade-in .2s ease-out}.iq-trace-modal{width:90%;max-width:520px;max-height:80vh;background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 20px 50px #0009}.iq-trace-header{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--iq-border)}.iq-trace-header h3{margin:0;font-size:.95rem;color:var(--iq-text)}.iq-trace-body{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px}.iq-trace-item label{display:block;font-size:.7rem;color:var(--iq-text-muted);margin-bottom:4px;text-transform:uppercase;letter-spacing:.05em}.iq-trace-item code{display:block;padding:8px;background:var(--iq-bg-tertiary);border-radius:4px;font-family:monospace;font-size:.8rem;color:var(--iq-accent);word-break:break-all}.iq-trace-item pre{margin:0;padding:8px;background:var(--iq-bg-tertiary);border-radius:4px;font-family:monospace;font-size:.7rem;overflow-x:auto;max-height:180px;color:var(--iq-text-secondary)}.iq-cache-hit{background:#10b98126!important;color:#10b981!important}.iq-query-code{color:var(--iq-accent)!important}.iq-link-overlay{position:fixed;inset:0;z-index:calc(var(--iq-z) + 20);background:#000000b3;display:flex;align-items:center;justify-content:center;animation:iq-fade-in .2s ease-out;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.iq-link-modal{width:94vw;height:92vh;background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 24px 60px #000000b3;animation:iq-expand .25s cubic-bezier(.4,0,.2,1)}.iq-link-header{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;border-bottom:1px solid var(--iq-border);background:var(--iq-bg-card);gap:12px;min-height:44px}.iq-link-title{flex:1;font-size:.78rem;color:var(--iq-text-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:monospace}.iq-link-actions{display:flex;gap:4px;flex-shrink:0}.iq-link-actions a{text-decoration:none}.iq-back-btn{flex-shrink:0;font-size:1.1rem;transition:transform .15s ease}.iq-back-btn:hover{transform:translate(-2px)}.iq-iframe-wrapper{flex:1;position:relative;overflow:hidden}.iq-link-iframe{width:100%;height:100%;border:none;background:#fff;transition:opacity .3s ease}.iq-iframe-hidden{opacity:0}.iq-modal-img{width:100%;height:100%;object-fit:contain;background:#1a1a2e}.iq-iframe-loader{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:var(--iq-bg);gap:16px;z-index:2}.iq-spinner{width:40px;height:40px;border:3px solid var(--iq-border);border-top-color:var(--iq-accent);border-radius:50%;animation:iq-spin .8s linear infinite}.iq-loader-text{font-size:.85rem;color:var(--iq-text-secondary);font-weight:500}@keyframes iq-spin{to{transform:rotate(360deg)}}.iq-md a{color:var(--iq-accent);text-decoration:underline;cursor:pointer;transition:color .15s}.iq-md a:hover{color:var(--iq-accent-light)}@media(max-width:480px){.iq-link-modal{width:100vw;height:100dvh;border-radius:0}.iq-link-header{padding:8px 12px}.iq-link-title{font-size:.7rem}}.iq-messages::-webkit-scrollbar{width:5px}.iq-messages::-webkit-scrollbar-track{background:transparent}.iq-messages::-webkit-scrollbar-thumb{background:var(--iq-border);border-radius:4px}.iq-trace-body::-webkit-scrollbar{width:5px}.iq-trace-body::-webkit-scrollbar-track{background:transparent}.iq-trace-body::-webkit-scrollbar-thumb{background:var(--iq-border);border-radius:4px}.iq-expanded .iq-messages::-webkit-scrollbar{width:8px}.iq-expanded .iq-messages{scrollbar-gutter:stable}@media(max-width:480px){.iq-bubble{bottom:16px;right:16px;width:48px;height:48px;font-size:1.3rem}.iq-bubble.iq-bottom-left{left:16px}.iq-bubble .iq-bubble-icon{font-size:1.2rem}.iq-panel{right:8px;left:8px;bottom:72px;width:auto!important;max-width:calc(100vw - 16px);height:calc(100dvh - 90px);max-height:calc(100dvh - 90px)}.iq-panel.iq-bottom-left{left:8px;right:8px}.iq-panel.iq-expanded{inset:0!important;width:100vw!important;height:100dvh!important;max-height:100dvh!important;max-width:100vw!important;border-radius:0}.iq-header{padding:10px 12px}.iq-header-title{font-size:.85rem}.iq-header-btn{padding:6px 8px;min-width:32px;min-height:32px}.iq-messages{padding:8px;gap:8px}.iq-msg{max-width:92%}.iq-msg-bot{max-width:100%}.iq-msg-content{padding:8px 10px;font-size:.8rem}.iq-md{overflow-x:auto;-webkit-overflow-scrolling:touch}.iq-md table{font-size:.65rem;min-width:unset}.iq-md thead th{padding:.35em .5em;font-size:.6rem}.iq-md tbody td{padding:.3em .5em;font-size:.65rem}.iq-empty-icon{font-size:2.5rem}.iq-empty p{font-size:.85rem}.iq-input-bar{padding:8px 10px;gap:6px}.iq-input-bar input{font-size:16px;padding:8px 10px}.iq-btn-send{width:38px;height:38px;flex-shrink:0}.iq-trace-modal{width:calc(100vw - 24px);max-height:90dvh}.iq-trace-header{padding:12px}.iq-trace-header h3{font-size:.85rem}.iq-trace-body{padding:12px}.iq-trace-item pre{font-size:.65rem;max-height:140px}}@media(max-height:500px)and (orientation:landscape){.iq-bubble{bottom:8px;right:8px;width:44px;height:44px;font-size:1.1rem}.iq-bubble.iq-bottom-left{left:8px}.iq-panel{inset:8px 60px 8px 8px;width:auto!important;max-width:calc(100vw - 76px);height:auto!important;max-height:calc(100dvh - 16px);border-radius:var(--iq-radius)}.iq-panel.iq-bottom-left{left:60px;right:8px}.iq-panel.iq-expanded{inset:0!important;width:100vw!important;height:100dvh!important;max-height:100dvh!important;max-width:100vw!important;border-radius:0}.iq-header{padding:6px 12px}.iq-header-title{font-size:.8rem}.iq-messages{padding:6px 10px;gap:6px}.iq-empty-icon{font-size:1.8rem;margin-bottom:4px}.iq-empty p{font-size:.78rem;margin:1px 0}.iq-input-bar{padding:6px 10px}.iq-input-bar input{font-size:16px;padding:6px 10px}.iq-btn-send{width:32px;height:32px}}\n"] }]
|
|
954
1112
|
}], propDecorators: { chatContainer: [{
|
|
955
1113
|
type: ViewChild,
|
|
956
1114
|
args: ['chatContainer']
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"maquito-chat-plugin.mjs","sources":["../../../frontend/maquito-chat-plugin/src/lib/intelligent-chat.service.ts","../../../frontend/maquito-chat-plugin/src/lib/intelligent-chat-plugin.component.ts","../../../frontend/maquito-chat-plugin/src/public-api.ts","../../../frontend/maquito-chat-plugin/src/maquito-chat-plugin.ts"],"sourcesContent":["import { Injectable, inject } from '@angular/core';\r\nimport { HttpClient, HttpHeaders } from '@angular/common/http';\r\nimport { Observable } from 'rxjs';\r\n\r\n/**\r\n * Standalone HTTP service for the Maquito Chat Plugin.\r\n * Decoupled from any host app service — uses apiUrl + token from config.\r\n * Replicates exactly the same endpoints used by the Maquito Core API.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class IntelligentChatService {\r\n\r\n private http = inject(HttpClient);\r\n\r\n /**\r\n * Execute an intelligent query (POST /api/query).\r\n * Auth via X-Api-Key header.\r\n */\r\n executeIntelligentQuery(\r\n apiUrl: string,\r\n token: string,\r\n systemId: string,\r\n question: string,\r\n conversationHistory: { role: string; content: string }[] = [],\r\n baseContext?: string,\r\n skipPatternCache?: boolean,\r\n preferTableFormat?: boolean,\r\n userName?: string,\r\n personality?: string\r\n ): Observable<any> {\r\n const headers = this.buildHeaders(token);\r\n const body: any = { systemId, question, conversationHistory };\r\n if (baseContext) body.baseContext = baseContext;\r\n if (skipPatternCache) body.skipPatternCache = skipPatternCache;\r\n if (preferTableFormat !== undefined) body.preferTableFormat = preferTableFormat;\r\n if (userName) body.userName = userName;\r\n if (personality) body.personality = personality;\r\n return this.http.post<any>(`${apiUrl}/query`, body, { headers });\r\n }\r\n\r\n /**\r\n * Execute an intelligent query with SSE streaming progress.\r\n * Emits: { type: 'progress', step: string, message: string }\r\n * { type: 'result', data: any }\r\n */\r\n executeIntelligentQueryStream(\r\n apiUrl: string,\r\n token: string,\r\n systemId: string,\r\n question: string,\r\n conversationHistory: { role: string; content: string }[] = [],\r\n baseContext?: string,\r\n skipPatternCache?: boolean,\r\n preferTableFormat?: boolean,\r\n userName?: string,\r\n personality?: string\r\n ): Observable<{ type: 'progress' | 'result'; step?: string; message?: string; data?: any }> {\r\n const body: any = { systemId, question, conversationHistory };\r\n if (baseContext) body.baseContext = baseContext;\r\n if (skipPatternCache) body.skipPatternCache = skipPatternCache;\r\n if (preferTableFormat !== undefined) body.preferTableFormat = preferTableFormat;\r\n if (userName) body.userName = userName;\r\n if (personality) body.personality = personality;\r\n\r\n return new Observable(observer => {\r\n const abortController = new AbortController();\r\n\r\n fetch(`${apiUrl}/query/stream`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json', 'X-Api-Key': token },\r\n body: JSON.stringify(body),\r\n signal: abortController.signal\r\n }).then(async response => {\r\n if (!response.ok || !response.body) {\r\n observer.error(new Error(`HTTP ${response.status}`));\r\n return;\r\n }\r\n const reader = response.body.getReader();\r\n const decoder = new TextDecoder();\r\n let buffer = '';\r\n\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n buffer += decoder.decode(value, { stream: true });\r\n\r\n const parts = buffer.split('\\n\\n');\r\n buffer = parts.pop() || '';\r\n for (const part of parts) {\r\n const lines = part.split('\\n');\r\n let eventType = '';\r\n let eventData = '';\r\n for (const line of lines) {\r\n if (line.startsWith('event: ')) eventType = line.slice(7);\r\n else if (line.startsWith('data: ')) eventData = line.slice(6);\r\n }\r\n if (!eventType || !eventData) continue;\r\n try {\r\n const parsed = JSON.parse(eventData);\r\n if (eventType === 'progress') {\r\n observer.next({ type: 'progress', step: parsed.step, message: parsed.message });\r\n } else if (eventType === 'result') {\r\n observer.next({ type: 'result', data: parsed });\r\n observer.complete();\r\n } else if (eventType === 'error') {\r\n observer.error(parsed);\r\n }\r\n } catch { /* skip malformed JSON */ }\r\n }\r\n }\r\n if (!observer.closed) observer.complete();\r\n }).catch(err => {\r\n if (err.name !== 'AbortError') observer.error(err);\r\n });\r\n\r\n return () => abortController.abort();\r\n });\r\n }\r\n\r\n /**\r\n * Standard orchestration ask (POST /api/cortex/ask).\r\n * Used when intelligent query mode is disabled.\r\n */\r\n ask(apiUrl: string, token: string, text: string): Observable<any> {\r\n const headers = this.buildHeaders(token);\r\n return this.http.post<any>(`${apiUrl}/cortex/ask`, { text }, { headers });\r\n }\r\n\r\n private buildHeaders(token: string): HttpHeaders {\r\n return new HttpHeaders({ 'X-Api-Key': token });\r\n }\r\n}\r\n","import {\r\n Component, Input, inject, signal, computed, ViewChild, ElementRef,\r\n AfterViewChecked, OnChanges, OnInit, OnDestroy, SimpleChanges\r\n} from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\nimport { marked } from 'marked';\r\nimport { IntelligentChatConfig, ChatMessage, PluginTheme } from './intelligent-chat.models';\r\nimport { IntelligentChatService } from './intelligent-chat.service';\r\n\r\n@Component({\r\n selector: 'intelligent-chat-plugin',\r\n standalone: true,\r\n imports: [CommonModule, FormsModule],\r\n template: `\r\n <!-- Host theme overrides -->\r\n <div class=\"iq-theme-host\" [ngStyle]=\"themeStyles()\">\r\n\r\n <!-- Floating Bubble Button (hidden when expanded) -->\r\n @if (!isExpanded()) {\r\n <button\r\n class=\"iq-bubble\"\r\n [class.iq-bottom-left]=\"resolvedConfig().position === 'bottom-left'\"\r\n [class.iq-open]=\"isOpen()\"\r\n [style.position]=\"resolvedConfig().stickyBubble ? 'fixed' : 'absolute'\"\r\n (click)=\"toggleChat()\"\r\n [attr.aria-label]=\"isOpen() ? 'Cerrar chat' : 'Abrir chat'\"\r\n >\r\n @if (isOpen()) {\r\n <span class=\"iq-bubble-icon\">✕</span>\r\n } @else {\r\n @switch (resolvedConfig().bubbleIconType) {\r\n @case ('image') {\r\n <img [src]=\"resolvedConfig().bubbleImageUrl\" alt=\"Chat\" class=\"iq-bubble-img\" />\r\n }\r\n @case ('svg') {\r\n <span class=\"iq-bubble-svg\" [innerHTML]=\"sanitizedBubbleSvg()\"></span>\r\n }\r\n @default {\r\n <span class=\"iq-bubble-icon\">{{ resolvedConfig().bubbleIcon }}</span>\r\n }\r\n }\r\n }\r\n </button>\r\n }\r\n\r\n <!-- Chat Panel -->\r\n @if (isOpen()) {\r\n <div\r\n class=\"iq-panel\"\r\n [class.iq-bottom-left]=\"resolvedConfig().position === 'bottom-left'\"\r\n [class.iq-expanded]=\"isExpanded()\"\r\n [class]=\"resolvedConfig().themeClass || ''\"\r\n [style.position]=\"resolvedConfig().stickyBubble ? 'fixed' : 'absolute'\"\r\n >\r\n <!-- Header -->\r\n <div class=\"iq-header\">\r\n <span class=\"iq-header-title\">{{ resolvedConfig().title }}</span>\r\n <div class=\"iq-header-actions\">\r\n <button class=\"iq-header-btn\" (click)=\"clearChat()\" title=\"Limpiar chat\">🗑️</button>\r\n @if (resolvedConfig().allowExpand) {\r\n <button class=\"iq-header-btn iq-btn-expand\" (click)=\"toggleExpand()\" [title]=\"isExpanded() ? 'Contraer' : 'Expandir'\">\r\n {{ isExpanded() ? '⊡' : '⛶' }}\r\n </button>\r\n }\r\n <button class=\"iq-header-btn\" (click)=\"isExpanded() ? toggleExpand() : toggleChat()\">✕</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Auth Error Banner -->\r\n @if (authError()) {\r\n <div class=\"iq-auth-error\">\r\n <span>🔒</span>\r\n <span>{{ authError() }}</span>\r\n </div>\r\n }\r\n\r\n <!-- Messages -->\r\n <div class=\"iq-messages\" #chatContainer>\r\n @if (messages().length === 0 && !authError()) {\r\n <div class=\"iq-empty\">\r\n <div class=\"iq-empty-icon\">\r\n @switch (resolvedConfig().bubbleIconType) {\r\n @case ('image') {\r\n <img [src]=\"resolvedConfig().bubbleImageUrl\" alt=\"\" class=\"iq-empty-img\" />\r\n }\r\n @case ('svg') {\r\n <span class=\"iq-empty-svg\" [innerHTML]=\"sanitizedBubbleSvg()\"></span>\r\n }\r\n @default {\r\n <span>{{ resolvedConfig().bubbleIcon }}</span>\r\n }\r\n }\r\n </div>\r\n <p>{{ resolvedConfig().welcomeTitle }}</p>\r\n <p class=\"iq-text-muted\">{{ resolvedConfig().welcomeSubtitle }}</p>\r\n </div>\r\n }\r\n\r\n @for (msg of messages(); track msg.id) {\r\n <div class=\"iq-msg\" [class.iq-msg-user]=\"msg.sender === 'user'\" [class.iq-msg-bot]=\"msg.sender === 'bot'\">\r\n <div class=\"iq-msg-content\">\r\n @if (msg.sender === 'bot') {\r\n <div class=\"iq-md\" [innerHTML]=\"renderMarkdown(msg.text)\"></div>\r\n } @else {\r\n <p>{{ msg.text }}</p>\r\n }\r\n <span class=\"iq-msg-time\">{{ formatTime(msg.timestamp) }}</span>\r\n </div>\r\n @if (msg.sender === 'bot' && msg.traceData && resolvedConfig().showTrace) {\r\n <button class=\"iq-btn-trace\" (click)=\"showTrace(msg)\">🔍 Ver Traza</button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Pipeline progress -->\r\n @if (isLoading()) {\r\n <div class=\"iq-msg iq-msg-bot\">\r\n <div class=\"iq-msg-content iq-pipeline\">\r\n <span class=\"iq-dot\"></span>\r\n <span class=\"iq-pipeline-text\">{{ pipelineStep }}</span>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Input -->\r\n <form class=\"iq-input-bar\" (ngSubmit)=\"sendMessage()\">\r\n <input\r\n type=\"text\"\r\n [(ngModel)]=\"inputText\"\r\n name=\"message\"\r\n [placeholder]=\"resolvedConfig().placeholder!\"\r\n [disabled]=\"isLoading() || !!authError()\"\r\n autocomplete=\"off\"\r\n />\r\n <button type=\"submit\" class=\"iq-btn-send\" [disabled]=\"isLoading() || !inputText.trim() || !!authError()\">\r\n ➤\r\n </button>\r\n </form>\r\n </div>\r\n }\r\n\r\n <!-- Trace Modal Overlay -->\r\n @if (selectedTrace()) {\r\n <div class=\"iq-trace-overlay\" (click)=\"closeTrace()\">\r\n <div class=\"iq-trace-modal\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"iq-trace-header\">\r\n <h3>🔍 Detalle de Traza</h3>\r\n <button class=\"iq-header-btn\" (click)=\"closeTrace()\">✕</button>\r\n </div>\r\n <div class=\"iq-trace-body\">\r\n @if (selectedTrace()?.fromCache !== undefined) {\r\n <div class=\"iq-trace-item\">\r\n <label>Origen</label>\r\n <code [class.iq-cache-hit]=\"selectedTrace()?.fromCache\">{{ selectedTrace()?.fromCache ? '📚 Desde Caché' : '🤖 Generado por GPT' }}</code>\r\n </div>\r\n }\r\n @if (selectedTrace()?.query) {\r\n <div class=\"iq-trace-item\">\r\n <label>Query Generada</label>\r\n <pre class=\"iq-query-code\">{{ selectedTrace()?.query }}</pre>\r\n </div>\r\n }\r\n @if (selectedTrace()?.explanation) {\r\n <div class=\"iq-trace-item\">\r\n <label>Explicación</label>\r\n <code>{{ selectedTrace()?.explanation }}</code>\r\n </div>\r\n }\r\n @if (selectedTrace()?.traceId) {\r\n <div class=\"iq-trace-item\">\r\n <label>Trace ID</label>\r\n <code>{{ selectedTrace()?.traceId }}</code>\r\n </div>\r\n }\r\n @if (selectedTrace()?.data) {\r\n <div class=\"iq-trace-item\">\r\n <label>Datos Retornados</label>\r\n <pre>{{ selectedTrace()?.data | json }}</pre>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n </div><!-- /iq-theme-host -->\r\n `,\r\n styles: [`\r\n /* ========= CSS Custom Properties (overridable by host) ========= */\r\n :host {\r\n --iq-primary: #1a3a5c;\r\n --iq-primary-light: #2a5a8c;\r\n --iq-accent: #00d4aa;\r\n --iq-accent-light: #33e0be;\r\n --iq-bg: #1e1e2f;\r\n --iq-bg-card: #252538;\r\n --iq-bg-tertiary: #35354a;\r\n --iq-text: #ffffff;\r\n --iq-text-secondary: #a0a0b0;\r\n --iq-text-muted: #6c6c7c;\r\n --iq-border: #3a3a4d;\r\n --iq-radius: 12px;\r\n --iq-bubble-size: 56px;\r\n --iq-panel-width: 400px;\r\n --iq-panel-height: 520px;\r\n --iq-z: 10000;\r\n --iq-font: 'Inter', 'Roboto', -apple-system, BlinkMacSystemFont, sans-serif;\r\n font-family: var(--iq-font);\r\n }\r\n\r\n /* ========= Bubble ========= */\r\n .iq-bubble {\r\n position: fixed;\r\n bottom: 24px;\r\n right: 24px;\r\n z-index: var(--iq-z);\r\n width: var(--iq-bubble-size);\r\n height: var(--iq-bubble-size);\r\n border-radius: 50%;\r\n border: none;\r\n background: linear-gradient(135deg, var(--iq-accent), var(--iq-accent-light));\r\n color: var(--iq-bg);\r\n font-size: 1.6rem;\r\n cursor: pointer;\r\n box-shadow: 0 4px 16px rgba(0, 212, 170, 0.4);\r\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n }\r\n .iq-bubble:hover {\r\n transform: scale(1.1);\r\n box-shadow: 0 6px 24px rgba(0, 212, 170, 0.5);\r\n }\r\n .iq-bubble .iq-bubble-icon {\r\n font-size: 1.5rem;\r\n pointer-events: none;\r\n }\r\n\r\n .iq-bubble-img {\r\n width: 60%; height: 60%;\r\n object-fit: contain; border-radius: 50%;\r\n pointer-events: none;\r\n }\r\n\r\n .iq-bubble-svg {\r\n width: 60%; height: 60%;\r\n display: flex; align-items: center; justify-content: center;\r\n pointer-events: none;\r\n }\r\n .iq-bubble-svg :deep(svg) { width: 100%; height: 100%; }\r\n\r\n .iq-bubble.iq-open {\r\n background: var(--iq-bg-tertiary);\r\n color: var(--iq-text);\r\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\r\n font-size: 1.2rem;\r\n }\r\n .iq-bubble.iq-bottom-left {\r\n right: auto;\r\n left: 24px;\r\n }\r\n .iq-bubble-icon { line-height: 1; }\r\n\r\n /* ========= Panel ========= */\r\n .iq-panel {\r\n position: fixed;\r\n bottom: 92px;\r\n right: 24px;\r\n z-index: var(--iq-z);\r\n width: var(--iq-panel-width);\r\n height: var(--iq-panel-height);\r\n background: var(--iq-bg);\r\n border: 1px solid var(--iq-border);\r\n border-radius: var(--iq-radius);\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n box-shadow: 0 12px 40px rgba(0,0,0,0.5);\r\n animation: iq-slide-up 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n }\r\n .iq-panel.iq-bottom-left {\r\n right: auto;\r\n left: 24px;\r\n }\r\n /* ========= Expanded / Fullscreen ========= */\r\n .iq-panel.iq-expanded {\r\n width: 100vw !important;\r\n height: 100vh !important;\r\n top: 0 !important;\r\n left: 0 !important;\r\n right: 0 !important;\r\n bottom: 0 !important;\r\n border-radius: 0;\r\n z-index: calc(var(--iq-z) + 5);\r\n animation: iq-expand 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n }\r\n .iq-btn-expand {\r\n font-size: 1.1rem !important;\r\n }\r\n @keyframes iq-expand {\r\n from { opacity: 0.8; transform: scale(0.95); }\r\n to { opacity: 1; transform: scale(1); }\r\n }\r\n @keyframes iq-slide-up {\r\n from { opacity: 0; transform: translateY(16px) scale(0.96); }\r\n to { opacity: 1; transform: translateY(0) scale(1); }\r\n }\r\n\r\n /* ========= Header ========= */\r\n .iq-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 12px 16px;\r\n border-bottom: 1px solid var(--iq-border);\r\n background: var(--iq-bg-card);\r\n }\r\n .iq-header-title {\r\n font-weight: 600;\r\n font-size: 0.95rem;\r\n color: var(--iq-text);\r\n }\r\n .iq-header-actions {\r\n display: flex;\r\n gap: 4px;\r\n }\r\n .iq-header-btn {\r\n background: none;\r\n border: none;\r\n color: var(--iq-text-muted);\r\n cursor: pointer;\r\n font-size: 1rem;\r\n padding: 4px 6px;\r\n border-radius: 4px;\r\n transition: all 0.15s;\r\n }\r\n .iq-header-btn:hover {\r\n color: var(--iq-text);\r\n background: rgba(255,255,255,0.08);\r\n }\r\n\r\n /* ========= Auth Error ========= */\r\n .iq-auth-error {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 10px 16px;\r\n background: rgba(220, 53, 69, 0.15);\r\n color: #ff6b7a;\r\n font-size: 0.8rem;\r\n border-bottom: 1px solid rgba(220, 53, 69, 0.25);\r\n }\r\n\r\n /* ========= Messages ========= */\r\n .iq-messages {\r\n flex: 1;\r\n overflow-y: auto;\r\n padding: 12px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 10px;\r\n }\r\n\r\n .iq-empty {\r\n flex: 1;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n text-align: center;\r\n color: var(--iq-text-secondary);\r\n }\r\n .iq-empty-icon { font-size: 3rem; margin-bottom: 8px; display: flex; align-items: center; justify-content: center; }\r\n .iq-empty-img { width: 48px; height: 48px; object-fit: contain; border-radius: 8px; }\r\n .iq-empty-svg { width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; }\r\n .iq-empty-svg :deep(svg) { width: 100%; height: 100%; }\r\n .iq-empty p { font-size: 0.95rem; margin: 2px 0; }\r\n .iq-text-muted { color: var(--iq-text-muted) !important; font-size: 0.8rem !important; }\r\n\r\n .iq-msg { display: flex; flex-direction: column; max-width: 85%; }\r\n .iq-msg-user { align-self: flex-end; }\r\n .iq-msg-bot { align-self: flex-start; max-width: 100%; }\r\n\r\n .iq-msg-user .iq-msg-content {\r\n background: linear-gradient(135deg, var(--iq-primary), var(--iq-primary-light));\r\n border-radius: 12px 12px 0 12px;\r\n }\r\n .iq-msg-bot .iq-msg-content {\r\n background: var(--iq-bg-tertiary);\r\n border-radius: 12px 12px 12px 0;\r\n }\r\n .iq-msg-content {\r\n padding: 10px 14px;\r\n color: var(--iq-text);\r\n font-size: 0.85rem;\r\n line-height: 1.45;\r\n }\r\n .iq-msg-content p { margin: 0; white-space: pre-wrap; }\r\n .iq-msg-time {\r\n display: block;\r\n margin-top: 4px;\r\n font-size: 0.65rem;\r\n color: rgba(255,255,255,0.5);\r\n }\r\n\r\n /* Markdown rendered content */\r\n .iq-md { line-height: 1.5; overflow-x: auto; max-width: 100%; }\r\n .iq-md :first-child { margin-top: 0; }\r\n .iq-md :last-child { margin-bottom: 0; }\r\n .iq-md p { margin: 0 0 0.4em 0; }\r\n .iq-md p:last-child { margin-bottom: 0; }\r\n .iq-md strong { color: var(--iq-accent); }\r\n .iq-md ul, .iq-md ol { margin: 0.3em 0; padding-left: 1.2em; }\r\n .iq-md li { margin: 0.15em 0; }\r\n .iq-md code {\r\n background: rgba(0,0,0,0.3);\r\n padding: 0.15em 0.4em;\r\n border-radius: 3px;\r\n font-size: 0.82em;\r\n }\r\n .iq-md pre {\r\n background: rgba(0,0,0,0.3);\r\n padding: 0.8em;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n font-size: 0.78em;\r\n margin: 0.4em 0;\r\n }\r\n .iq-md pre code { background: none; padding: 0; }\r\n .iq-md table {\r\n width: max-content; min-width: 100%;\r\n border-collapse: separate; border-spacing: 0;\r\n margin: 0.5em 0; font-size: 0.75rem;\r\n border-radius: 6px; overflow: hidden;\r\n }\r\n .iq-md thead th {\r\n background: rgba(99,102,241,0.18); color: #a5b4fc;\r\n font-weight: 600; text-align: left;\r\n padding: 0.5em 0.8em; border-bottom: 2px solid rgba(99,102,241,0.3);\r\n white-space: nowrap; font-size: 0.7rem;\r\n text-transform: uppercase; letter-spacing: 0.05em;\r\n }\r\n .iq-md tbody td {\r\n padding: 0.4em 0.8em; border-bottom: 1px solid rgba(255,255,255,0.06);\r\n white-space: nowrap; color: var(--iq-text-secondary);\r\n }\r\n .iq-md tbody tr:hover { background: rgba(99,102,241,0.08); }\r\n\r\n /* Trace button */\r\n .iq-btn-trace {\r\n align-self: flex-start; margin-top: 4px;\r\n background: transparent; border: 1px solid var(--iq-border);\r\n color: var(--iq-text-secondary); font-size: 0.7rem;\r\n padding: 3px 8px; border-radius: 4px; cursor: pointer;\r\n transition: all 0.15s;\r\n }\r\n .iq-btn-trace:hover { border-color: var(--iq-accent); color: var(--iq-accent); }\r\n\r\n /* Pipeline loading indicator */\r\n .iq-pipeline {\r\n display: flex; align-items: center; gap: 8px;\r\n animation: iq-fade-in 0.3s ease-out;\r\n }\r\n .iq-dot {\r\n width: 8px; height: 8px; border-radius: 50%;\r\n background: var(--iq-accent);\r\n animation: iq-pulse 1s ease-in-out infinite;\r\n }\r\n .iq-pipeline-text {\r\n font-size: 0.8rem; color: var(--iq-text-muted); font-style: italic;\r\n }\r\n @keyframes iq-pulse {\r\n 0%, 100% { opacity: 1; transform: scale(1); }\r\n 50% { opacity: 0.4; transform: scale(0.7); }\r\n }\r\n @keyframes iq-fade-in {\r\n from { opacity: 0; transform: translateX(-6px); }\r\n to { opacity: 1; transform: translateX(0); }\r\n }\r\n\r\n /* ========= Input Bar ========= */\r\n .iq-input-bar {\r\n display: flex; gap: 8px;\r\n padding: 10px 12px;\r\n border-top: 1px solid var(--iq-border);\r\n background: var(--iq-bg-card);\r\n }\r\n .iq-input-bar input {\r\n flex: 1; padding: 8px 12px;\r\n background: var(--iq-bg-tertiary);\r\n border: 1px solid var(--iq-border);\r\n border-radius: 8px;\r\n color: var(--iq-text);\r\n font-size: 0.85rem;\r\n font-family: var(--iq-font);\r\n outline: none;\r\n transition: border-color 0.15s;\r\n }\r\n .iq-input-bar input:focus { border-color: var(--iq-accent); }\r\n .iq-input-bar input::placeholder { color: var(--iq-text-muted); }\r\n .iq-input-bar input:disabled { opacity: 0.5; }\r\n .iq-btn-send {\r\n width: 36px; height: 36px;\r\n border-radius: 8px; border: none;\r\n background: linear-gradient(135deg, var(--iq-accent), var(--iq-accent-light));\r\n color: var(--iq-bg); font-size: 1rem;\r\n cursor: pointer; transition: all 0.2s;\r\n display: flex; align-items: center; justify-content: center;\r\n }\r\n .iq-btn-send:hover:not(:disabled) { box-shadow: 0 0 12px rgba(0,212,170,0.4); transform: translateY(-1px); }\r\n .iq-btn-send:disabled { opacity: 0.4; cursor: not-allowed; }\r\n\r\n /* ========= Trace Modal ========= */\r\n .iq-trace-overlay {\r\n position: fixed; inset: 0;\r\n z-index: calc(var(--iq-z) + 10);\r\n background: rgba(0,0,0,0.6);\r\n display: flex; align-items: center; justify-content: center;\r\n animation: iq-fade-in 0.2s ease-out;\r\n }\r\n .iq-trace-modal {\r\n width: 90%; max-width: 520px; max-height: 80vh;\r\n background: var(--iq-bg); border: 1px solid var(--iq-border);\r\n border-radius: var(--iq-radius);\r\n display: flex; flex-direction: column; overflow: hidden;\r\n box-shadow: 0 20px 50px rgba(0,0,0,0.6);\r\n }\r\n .iq-trace-header {\r\n display: flex; align-items: center; justify-content: space-between;\r\n padding: 14px 16px; border-bottom: 1px solid var(--iq-border);\r\n }\r\n .iq-trace-header h3 { margin: 0; font-size: 0.95rem; color: var(--iq-text); }\r\n .iq-trace-body {\r\n flex: 1; overflow-y: auto; padding: 16px;\r\n display: flex; flex-direction: column; gap: 12px;\r\n }\r\n .iq-trace-item label {\r\n display: block; font-size: 0.7rem; color: var(--iq-text-muted);\r\n margin-bottom: 4px; text-transform: uppercase; letter-spacing: 0.05em;\r\n }\r\n .iq-trace-item code {\r\n display: block; padding: 8px;\r\n background: var(--iq-bg-tertiary); border-radius: 4px;\r\n font-family: monospace; font-size: 0.8rem; color: var(--iq-accent);\r\n word-break: break-all;\r\n }\r\n .iq-trace-item pre {\r\n margin: 0; padding: 8px;\r\n background: var(--iq-bg-tertiary); border-radius: 4px;\r\n font-family: monospace; font-size: 0.7rem;\r\n overflow-x: auto; max-height: 180px; color: var(--iq-text-secondary);\r\n }\r\n .iq-cache-hit { background: rgba(16,185,129,0.15) !important; color: #10b981 !important; }\r\n .iq-query-code { color: var(--iq-accent) !important; }\r\n\r\n /* ========= Scrollbar ========= */\r\n .iq-messages::-webkit-scrollbar { width: 5px; }\r\n .iq-messages::-webkit-scrollbar-track { background: transparent; }\r\n .iq-messages::-webkit-scrollbar-thumb { background: var(--iq-border); border-radius: 4px; }\r\n .iq-trace-body::-webkit-scrollbar { width: 5px; }\r\n .iq-trace-body::-webkit-scrollbar-track { background: transparent; }\r\n .iq-trace-body::-webkit-scrollbar-thumb { background: var(--iq-border); border-radius: 4px; }\r\n\r\n /* ========= Mobile Small Screens ========= */\r\n @media (max-width: 480px) {\r\n .iq-bubble {\r\n bottom: 16px;\r\n right: 16px;\r\n width: 48px;\r\n height: 48px;\r\n font-size: 1.3rem;\r\n }\r\n .iq-bubble.iq-bottom-left {\r\n left: 16px;\r\n }\r\n .iq-bubble .iq-bubble-icon { font-size: 1.2rem; }\r\n\r\n .iq-panel {\r\n right: 8px;\r\n left: 8px;\r\n bottom: 72px;\r\n width: auto !important;\r\n max-width: calc(100vw - 16px);\r\n height: calc(100dvh - 90px);\r\n max-height: calc(100dvh - 90px);\r\n }\r\n .iq-panel.iq-bottom-left {\r\n left: 8px;\r\n right: 8px;\r\n }\r\n .iq-panel.iq-expanded {\r\n top: 0 !important;\r\n left: 0 !important;\r\n right: 0 !important;\r\n bottom: 0 !important;\r\n width: 100vw !important;\r\n height: 100dvh !important;\r\n max-height: 100dvh !important;\r\n max-width: 100vw !important;\r\n border-radius: 0;\r\n }\r\n\r\n .iq-header {\r\n padding: 10px 12px;\r\n }\r\n .iq-header-title { font-size: 0.85rem; }\r\n .iq-header-btn { padding: 6px 8px; min-width: 32px; min-height: 32px; }\r\n\r\n .iq-messages { padding: 8px; gap: 8px; }\r\n\r\n .iq-msg { max-width: 92%; }\r\n .iq-msg-bot { max-width: 100%; }\r\n .iq-msg-content { padding: 8px 10px; font-size: 0.8rem; }\r\n\r\n .iq-md { overflow-x: auto; -webkit-overflow-scrolling: touch; }\r\n .iq-md table { font-size: 0.65rem; min-width: unset; }\r\n .iq-md thead th { padding: 0.35em 0.5em; font-size: 0.6rem; }\r\n .iq-md tbody td { padding: 0.3em 0.5em; font-size: 0.65rem; }\r\n\r\n .iq-empty-icon { font-size: 2.5rem; }\r\n .iq-empty p { font-size: 0.85rem; }\r\n\r\n .iq-input-bar { padding: 8px 10px; gap: 6px; }\r\n .iq-input-bar input { font-size: 16px; padding: 8px 10px; }\r\n .iq-btn-send { width: 38px; height: 38px; flex-shrink: 0; }\r\n\r\n .iq-trace-modal {\r\n width: calc(100vw - 24px);\r\n max-height: 90dvh;\r\n }\r\n .iq-trace-header { padding: 12px; }\r\n .iq-trace-header h3 { font-size: 0.85rem; }\r\n .iq-trace-body { padding: 12px; }\r\n .iq-trace-item pre { font-size: 0.65rem; max-height: 140px; }\r\n }\r\n\r\n /* ========= Landscape Mobile — fit floating panel ========= */\r\n @media (max-height: 500px) and (orientation: landscape) {\r\n .iq-bubble {\r\n bottom: 8px;\r\n right: 8px;\r\n width: 44px;\r\n height: 44px;\r\n font-size: 1.1rem;\r\n }\r\n .iq-bubble.iq-bottom-left { left: 8px; }\r\n\r\n .iq-panel {\r\n right: 60px;\r\n left: 8px;\r\n bottom: 8px;\r\n top: 8px;\r\n width: auto !important;\r\n max-width: calc(100vw - 76px);\r\n height: auto !important;\r\n max-height: calc(100dvh - 16px);\r\n border-radius: var(--iq-radius);\r\n }\r\n .iq-panel.iq-bottom-left {\r\n left: 60px;\r\n right: 8px;\r\n }\r\n\r\n .iq-header { padding: 6px 12px; }\r\n .iq-header-title { font-size: 0.8rem; }\r\n .iq-messages { padding: 6px 10px; gap: 6px; }\r\n .iq-empty-icon { font-size: 1.8rem; margin-bottom: 4px; }\r\n .iq-empty p { font-size: 0.78rem; margin: 1px 0; }\r\n .iq-input-bar { padding: 6px 10px; }\r\n .iq-input-bar input { font-size: 16px; padding: 6px 10px; }\r\n .iq-btn-send { width: 32px; height: 32px; }\r\n }\r\n `]\r\n})\r\nexport class IntelligentChatPluginComponent implements AfterViewChecked, OnChanges, OnInit, OnDestroy {\r\n @ViewChild('chatContainer') private chatContainer!: ElementRef;\r\n\r\n @Input() config!: IntelligentChatConfig;\r\n\r\n private chatService = inject(IntelligentChatService);\r\n\r\n // State\r\n isOpen = signal(false);\r\n isExpanded = signal(false);\r\n messages = signal<ChatMessage[]>([]);\r\n isLoading = signal(false);\r\n selectedTrace = signal<any>(null);\r\n authError = signal<string | null>(null);\r\n inputText = '';\r\n\r\n // Pipeline step (driven by real SSE events from backend)\r\n pipelineStep = '';\r\n\r\n private messageId = 0;\r\n private shouldScroll = false;\r\n\r\n // ─── Session Persistence ──────────────────────────\r\n private readonly STORAGE_PREFIX = 'iq_chat_session_';\r\n private sessionKey = '';\r\n private storageListener = (e: StorageEvent) => this.onStorageChange(e);\r\n\r\n /** Resolved config with defaults applied */\r\n private sanitizer = inject(DomSanitizer);\r\n\r\n resolvedConfig = signal<Required<IntelligentChatConfig>>({\r\n apiUrl: '',\r\n systemId: '',\r\n token: '',\r\n useIntelligentQuery: true,\r\n skipPatterns: true,\r\n baseContext: '',\r\n showTrace: false,\r\n showPipelineSteps: true,\r\n preferTableFormat: true,\r\n title: 'Maquito Chat',\r\n placeholder: 'Escribe tu consulta aquí...',\r\n welcomeTitle: '¡Hola! Soy Maquito.',\r\n welcomeSubtitle: 'Escribe tu consulta para comenzar.',\r\n position: 'bottom-right',\r\n bubbleIcon: '🤖',\r\n bubbleIconType: 'emoji',\r\n bubbleImageUrl: '',\r\n bubbleSvg: '',\r\n themeClass: '',\r\n stickyBubble: true,\r\n allowExpand: false,\r\n theme: {},\r\n userName: '',\r\n personality: ''\r\n });\r\n\r\n /** Map theme object → CSS variable overrides */\r\n themeStyles = computed(() => {\r\n const t = this.resolvedConfig().theme || {};\r\n const map: Record<string, string> = {};\r\n const pairs: [keyof PluginTheme, string][] = [\r\n ['primary', '--iq-primary'], ['primaryLight', '--iq-primary-light'],\r\n ['accent', '--iq-accent'], ['accentLight', '--iq-accent-light'],\r\n ['bg', '--iq-bg'], ['bgCard', '--iq-bg-card'], ['bgTertiary', '--iq-bg-tertiary'],\r\n ['text', '--iq-text'], ['textSecondary', '--iq-text-secondary'],\r\n ['textMuted', '--iq-text-muted'], ['border', '--iq-border']\r\n ];\r\n for (const [key, cssVar] of pairs) {\r\n if (t[key]) map[cssVar] = t[key]!;\r\n }\r\n return map;\r\n });\r\n\r\n /** Sanitised SVG HTML for bubble */\r\n sanitizedBubbleSvg = computed<SafeHtml>(() => {\r\n const raw = this.resolvedConfig().bubbleSvg || '';\r\n return this.sanitizer.bypassSecurityTrustHtml(raw);\r\n });\r\n\r\n ngOnInit(): void {\r\n window.addEventListener('storage', this.storageListener);\r\n }\r\n\r\n ngOnDestroy(): void {\r\n window.removeEventListener('storage', this.storageListener);\r\n this.pipelineStep = '';\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if (changes['config'] && this.config) {\r\n this.resolvedConfig.set({\r\n apiUrl: this.config.apiUrl || '',\r\n systemId: this.config.systemId || '',\r\n token: this.config.token || '',\r\n useIntelligentQuery: this.config.useIntelligentQuery ?? true,\r\n skipPatterns: this.config.skipPatterns ?? true,\r\n baseContext: this.config.baseContext || '',\r\n showTrace: this.config.showTrace ?? false,\r\n showPipelineSteps: this.config.showPipelineSteps ?? true,\r\n preferTableFormat: this.config.preferTableFormat ?? true,\r\n title: this.config.title || 'Maquito Chat',\r\n placeholder: this.config.placeholder || 'Escribe tu consulta aquí...',\r\n welcomeTitle: this.config.welcomeTitle || '¡Hola! Soy Maquito.',\r\n welcomeSubtitle: this.config.welcomeSubtitle || 'Escribe tu consulta para comenzar.',\r\n position: this.config.position || 'bottom-right',\r\n bubbleIcon: this.config.bubbleIcon || '🤖',\r\n bubbleIconType: this.config.bubbleIconType || 'emoji',\r\n bubbleImageUrl: this.config.bubbleImageUrl || '',\r\n bubbleSvg: this.config.bubbleSvg || '',\r\n themeClass: this.config.themeClass || '',\r\n stickyBubble: this.config.stickyBubble ?? true,\r\n allowExpand: this.config.allowExpand ?? false,\r\n theme: this.config.theme || {},\r\n userName: this.config.userName || '',\r\n personality: this.config.personality || ''\r\n });\r\n // Rebuild session key when config changes\r\n const newKey = this.buildSessionKey();\r\n if (newKey !== this.sessionKey) {\r\n this.sessionKey = newKey;\r\n this.loadSession();\r\n }\r\n // Clear auth error when config changes (user may be testing a new token)\r\n this.authError.set(null);\r\n }\r\n }\r\n\r\n ngAfterViewChecked(): void {\r\n if (this.shouldScroll) {\r\n this.scrollToBottom();\r\n this.shouldScroll = false;\r\n }\r\n }\r\n\r\n toggleChat(): void {\r\n this.isOpen.update(v => !v);\r\n if (!this.isOpen()) this.isExpanded.set(false);\r\n if (this.isOpen()) this.shouldScroll = true;\r\n }\r\n\r\n toggleExpand(): void {\r\n this.isExpanded.update(v => !v);\r\n if (!this.isExpanded()) {\r\n // Collapsing from expanded — just return to normal panel\r\n }\r\n }\r\n\r\n sendMessage(): void {\r\n const text = this.inputText.trim();\r\n if (!text) return;\r\n\r\n const cfg = this.resolvedConfig();\r\n\r\n // Validate required config\r\n if (!cfg.token) {\r\n this.authError.set('Token no configurado. El plugin requiere un token técnico válido.');\r\n return;\r\n }\r\n if (!cfg.apiUrl) {\r\n this.authError.set('API URL no configurada.');\r\n return;\r\n }\r\n\r\n this.authError.set(null);\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text,\r\n sender: 'user',\r\n timestamp: new Date()\r\n }]);\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n this.inputText = '';\r\n this.isLoading.set(true);\r\n\r\n if (cfg.showPipelineSteps) {\r\n this.pipelineStep = '⏳ Procesando...';\r\n } else {\r\n this.pipelineStep = '⏳ Procesando...';\r\n }\r\n\r\n if (cfg.useIntelligentQuery && cfg.systemId) {\r\n // Build conversation history from previous messages (last 6 pairs)\r\n const history = this.messages()\r\n .filter(m => m.sender === 'user' || m.sender === 'bot')\r\n .slice(-12)\r\n .map(msg => ({\r\n role: msg.sender === 'user' ? 'user' : 'assistant',\r\n content: msg.text\r\n }));\r\n\r\n const ctx = cfg.baseContext?.trim() || undefined;\r\n\r\n if (cfg.showPipelineSteps) {\r\n // Use SSE streaming for real-time pipeline progress\r\n this.chatService.executeIntelligentQueryStream(\r\n cfg.apiUrl, cfg.token, cfg.systemId, text, history, ctx, cfg.skipPatterns, cfg.preferTableFormat,\r\n cfg.userName || undefined, cfg.personality || undefined\r\n ).subscribe({\r\n next: (event) => {\r\n if (event.type === 'progress') {\r\n this.pipelineStep = event.message || '';\r\n } else if (event.type === 'result') {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n const response = event.data;\r\n const responseText = response.success\r\n ? (response.response || 'Consulta ejecutada correctamente')\r\n : (response.error || 'Error en la consulta');\r\n\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: responseText,\r\n sender: 'bot',\r\n timestamp: new Date(),\r\n traceData: {\r\n traceId: response.traceId,\r\n fromCache: response.fromCache,\r\n fromContext: response.fromContext,\r\n query: response.query,\r\n explanation: response.explanation,\r\n patternId: response.patternId,\r\n data: response.data\r\n }\r\n }]);\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n }\r\n },\r\n error: (error) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n this.handleError(error);\r\n }\r\n });\r\n } else {\r\n // Fallback: use standard non-streaming endpoint\r\n this.chatService.executeIntelligentQuery(\r\n cfg.apiUrl, cfg.token, cfg.systemId, text, history, ctx, cfg.skipPatterns, cfg.preferTableFormat,\r\n cfg.userName || undefined, cfg.personality || undefined\r\n ).subscribe({\r\n next: (response: any) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n const responseText = response.success\r\n ? (response.response || 'Consulta ejecutada correctamente')\r\n : (response.error || 'Error en la consulta');\r\n\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: responseText,\r\n sender: 'bot',\r\n timestamp: new Date(),\r\n traceData: {\r\n traceId: response.traceId,\r\n fromCache: response.fromCache,\r\n fromContext: response.fromContext,\r\n query: response.query,\r\n explanation: response.explanation,\r\n patternId: response.patternId,\r\n data: response.data\r\n }\r\n }]);\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n },\r\n error: (error) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n this.handleError(error);\r\n }\r\n });\r\n }\r\n } else {\r\n // Standard orchestration (non-intelligent)\r\n this.chatService.ask(cfg.apiUrl, cfg.token, text).subscribe({\r\n next: (response) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: response.data?.response || 'Sin respuesta',\r\n sender: 'bot',\r\n timestamp: new Date(),\r\n traceData: {\r\n traceId: response.traceId,\r\n responseTime: response.data?.processingTime,\r\n appliedRules: response.data?.appliedRules,\r\n decisions: response.data?.decisions\r\n }\r\n }]);\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n },\r\n error: (error) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n this.handleError(error);\r\n }\r\n });\r\n }\r\n }\r\n\r\n clearChat(): void {\r\n this.messages.set([]);\r\n this.selectedTrace.set(null);\r\n this.authError.set(null);\r\n this.clearSession();\r\n }\r\n\r\n showTrace(msg: ChatMessage): void {\r\n this.selectedTrace.set(msg.traceData);\r\n }\r\n\r\n closeTrace(): void {\r\n this.selectedTrace.set(null);\r\n }\r\n\r\n formatTime(date: Date): string {\r\n return date.toLocaleTimeString('es-CL', { hour: '2-digit', minute: '2-digit' });\r\n }\r\n\r\n renderMarkdown(text: string): string {\r\n if (!text) return '';\r\n try {\r\n const preprocessed = this.preprocessMarkdownTable(text);\r\n return marked.parse(preprocessed, { breaks: true }) as string;\r\n } catch {\r\n return text;\r\n }\r\n }\r\n\r\n /**\r\n * Pre-process text to ensure pipe-delimited tables render as HTML tables.\r\n *\r\n * The API often returns header + separator + data on ONE line, e.g.:\r\n * \"| Col1 | Col2 | |---|---| | Val1 | Val2 |\"\r\n *\r\n * Step 1: Find the dash-separator pattern (|---|---|) and break the line\r\n * around it so each part (header / separator / data rows) is its\r\n * own line.\r\n * Step 2: Line-by-line cleanup — ensure a blank line exists before the\r\n * first pipe-row and inject a separator if one is still missing.\r\n */\r\n private preprocessMarkdownTable(text: string): string {\r\n // ── Step 1: Break inline separator onto its own line ───────────\r\n // Pattern: the separator row consists only of |, -, :, and spaces.\r\n // We insert \\n before and after it.\r\n text = text.replace(\r\n /\\s*(\\|(?:\\s*:?-{2,}:?\\s*\\|){2,})\\s*/g,\r\n '\\n$1\\n'\r\n );\r\n // Clean up excess blank lines created by step 1\r\n text = text.replace(/\\n{3,}/g, '\\n\\n');\r\n\r\n // ── Step 2: Line-by-line processing ───────────────────────────\r\n const lines = text.split('\\n');\r\n const result: string[] = [];\r\n let inTable = false;\r\n\r\n const isPipeLine = (l: string) => {\r\n const t = l.trim();\r\n return t.startsWith('|') && t.split('|').length > 3;\r\n };\r\n const isSepLine = (l: string) =>\r\n /^\\|(?:\\s*:?-{2,}:?\\s*\\|){2,}\\s*$/.test(l.trim());\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n const line = lines[i];\r\n const trimmed = line.trim();\r\n\r\n if (isPipeLine(trimmed) && !isSepLine(trimmed)) {\r\n if (!inTable) {\r\n inTable = true;\r\n // Insert blank line before table if preceded by non-empty text\r\n if (result.length > 0 && result[result.length - 1].trim() !== '') {\r\n result.push('');\r\n }\r\n result.push(line);\r\n // Inject separator if the next line isn't one\r\n const next = (i + 1 < lines.length) ? lines[i + 1] : '';\r\n if (!isSepLine(next)) {\r\n const cols = trimmed.split('|').filter(c => c.trim() !== '').length;\r\n result.push('| ' + Array(cols).fill('---').join(' | ') + ' |');\r\n }\r\n } else {\r\n result.push(line); // data row\r\n }\r\n } else if (isSepLine(trimmed)) {\r\n if (!inTable) inTable = true; // edge-case: separator before header\r\n result.push(line);\r\n } else {\r\n inTable = false;\r\n result.push(line);\r\n }\r\n }\r\n\r\n return result.join('\\n');\r\n }\r\n\r\n // ─── Private ───────────────────────────────────────────\r\n\r\n private handleError(error: any): void {\r\n const status = error?.status;\r\n if (status === 401 || status === 403) {\r\n const msg = status === 401 ? 'Token inválido o expirado' : 'Sin permisos para este sistema';\r\n this.authError.set(`🔒 ${msg}`);\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: `⚠️ ${msg}. Verifica el token y el systemId configurados.`,\r\n sender: 'bot',\r\n timestamp: new Date()\r\n }]);\r\n } else {\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: `Error: ${error.error?.message || error.error?.error || 'No se pudo procesar la consulta'}`,\r\n sender: 'bot',\r\n timestamp: new Date()\r\n }]);\r\n }\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n }\r\n\r\n private stopPipelineSteps(): void {\r\n this.pipelineStep = '';\r\n }\r\n\r\n private scrollToBottom(): void {\r\n if (this.chatContainer) {\r\n const el = this.chatContainer.nativeElement;\r\n el.scrollTop = el.scrollHeight;\r\n }\r\n }\r\n\r\n // ─── Session Persistence ──────────────────────────\r\n\r\n private buildSessionKey(): string {\r\n const cfg = this.resolvedConfig();\r\n if (!cfg.token || !cfg.systemId) return '';\r\n // Simple hash-like key from systemId + first 8 chars of token\r\n const tokenPrefix = cfg.token.substring(0, 8);\r\n return `${this.STORAGE_PREFIX}${cfg.systemId}_${tokenPrefix}`;\r\n }\r\n\r\n private saveSession(): void {\r\n if (!this.sessionKey) return;\r\n try {\r\n const data = this.messages().map(m => ({\r\n id: m.id,\r\n text: m.text,\r\n sender: m.sender,\r\n timestamp: m.timestamp,\r\n traceData: m.traceData\r\n }));\r\n localStorage.setItem(this.sessionKey, JSON.stringify(data));\r\n } catch { /* ignore quota errors */ }\r\n }\r\n\r\n private loadSession(): void {\r\n if (!this.sessionKey) return;\r\n try {\r\n const raw = localStorage.getItem(this.sessionKey);\r\n if (!raw) { this.messages.set([]); return; }\r\n const data: any[] = JSON.parse(raw);\r\n const msgs: ChatMessage[] = data.map(m => ({\r\n ...m,\r\n timestamp: new Date(m.timestamp)\r\n }));\r\n this.messages.set(msgs);\r\n this.messageId = msgs.length > 0 ? Math.max(...msgs.map(m => m.id)) + 1 : 0;\r\n this.shouldScroll = true;\r\n } catch { this.messages.set([]); }\r\n }\r\n\r\n private clearSession(): void {\r\n if (this.sessionKey) {\r\n try { localStorage.removeItem(this.sessionKey); } catch {}\r\n }\r\n }\r\n\r\n /** Called when another tab modifies localStorage */\r\n private onStorageChange(e: StorageEvent): void {\r\n if (!this.sessionKey || e.key !== this.sessionKey) return;\r\n if (e.newValue === null) {\r\n // Session was cleared in another tab\r\n this.messages.set([]);\r\n } else {\r\n this.loadSession();\r\n }\r\n this.shouldScroll = true;\r\n }\r\n}\r\n","/*\r\n * Public API Surface of maquito-chat-plugin\r\n */\r\n\r\nexport type { IntelligentChatConfig, ChatMessage, PluginTheme } from './lib/intelligent-chat.models';\r\nexport { IntelligentChatService } from './lib/intelligent-chat.service';\r\nexport { IntelligentChatPluginComponent } from './lib/intelligent-chat-plugin.component';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"maquito-chat-plugin.mjs","sources":["../../../frontend/maquito-chat-plugin/src/lib/intelligent-chat.service.ts","../../../frontend/maquito-chat-plugin/src/lib/intelligent-chat-plugin.component.ts","../../../frontend/maquito-chat-plugin/src/public-api.ts","../../../frontend/maquito-chat-plugin/src/maquito-chat-plugin.ts"],"sourcesContent":["import { Injectable, inject } from '@angular/core';\r\nimport { HttpClient, HttpHeaders } from '@angular/common/http';\r\nimport { Observable } from 'rxjs';\r\n\r\n/**\r\n * Standalone HTTP service for the Maquito Chat Plugin.\r\n * Decoupled from any host app service — uses apiUrl + token from config.\r\n * Replicates exactly the same endpoints used by the Maquito Core API.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class IntelligentChatService {\r\n\r\n private http = inject(HttpClient);\r\n\r\n /**\r\n * Execute an intelligent query (POST /api/query).\r\n * Auth via X-Api-Key header.\r\n */\r\n executeIntelligentQuery(\r\n apiUrl: string,\r\n token: string,\r\n systemId: string,\r\n question: string,\r\n conversationHistory: { role: string; content: string }[] = [],\r\n baseContext?: string,\r\n skipPatternCache?: boolean,\r\n preferTableFormat?: boolean,\r\n userName?: string,\r\n personality?: string\r\n ): Observable<any> {\r\n const headers = this.buildHeaders(token);\r\n const body: any = { systemId, question, conversationHistory };\r\n if (baseContext) body.baseContext = baseContext;\r\n if (skipPatternCache) body.skipPatternCache = skipPatternCache;\r\n if (preferTableFormat !== undefined) body.preferTableFormat = preferTableFormat;\r\n if (userName) body.userName = userName;\r\n if (personality) body.personality = personality;\r\n return this.http.post<any>(`${apiUrl}/query`, body, { headers });\r\n }\r\n\r\n /**\r\n * Execute an intelligent query with SSE streaming progress.\r\n * Emits: { type: 'progress', step: string, message: string }\r\n * { type: 'result', data: any }\r\n */\r\n executeIntelligentQueryStream(\r\n apiUrl: string,\r\n token: string,\r\n systemId: string,\r\n question: string,\r\n conversationHistory: { role: string; content: string }[] = [],\r\n baseContext?: string,\r\n skipPatternCache?: boolean,\r\n preferTableFormat?: boolean,\r\n userName?: string,\r\n personality?: string\r\n ): Observable<{ type: 'progress' | 'result'; step?: string; message?: string; data?: any }> {\r\n const body: any = { systemId, question, conversationHistory };\r\n if (baseContext) body.baseContext = baseContext;\r\n if (skipPatternCache) body.skipPatternCache = skipPatternCache;\r\n if (preferTableFormat !== undefined) body.preferTableFormat = preferTableFormat;\r\n if (userName) body.userName = userName;\r\n if (personality) body.personality = personality;\r\n\r\n return new Observable(observer => {\r\n const abortController = new AbortController();\r\n\r\n fetch(`${apiUrl}/query/stream`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json', 'X-Api-Key': token },\r\n body: JSON.stringify(body),\r\n signal: abortController.signal\r\n }).then(async response => {\r\n if (!response.ok || !response.body) {\r\n observer.error(new Error(`HTTP ${response.status}`));\r\n return;\r\n }\r\n const reader = response.body.getReader();\r\n const decoder = new TextDecoder();\r\n let buffer = '';\r\n\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n buffer += decoder.decode(value, { stream: true });\r\n\r\n const parts = buffer.split('\\n\\n');\r\n buffer = parts.pop() || '';\r\n for (const part of parts) {\r\n const lines = part.split('\\n');\r\n let eventType = '';\r\n let eventData = '';\r\n for (const line of lines) {\r\n if (line.startsWith('event: ')) eventType = line.slice(7);\r\n else if (line.startsWith('data: ')) eventData = line.slice(6);\r\n }\r\n if (!eventType || !eventData) continue;\r\n try {\r\n const parsed = JSON.parse(eventData);\r\n if (eventType === 'progress') {\r\n observer.next({ type: 'progress', step: parsed.step, message: parsed.message });\r\n } else if (eventType === 'result') {\r\n observer.next({ type: 'result', data: parsed });\r\n observer.complete();\r\n } else if (eventType === 'error') {\r\n observer.error(parsed);\r\n }\r\n } catch { /* skip malformed JSON */ }\r\n }\r\n }\r\n if (!observer.closed) observer.complete();\r\n }).catch(err => {\r\n if (err.name !== 'AbortError') observer.error(err);\r\n });\r\n\r\n return () => abortController.abort();\r\n });\r\n }\r\n\r\n /**\r\n * Standard orchestration ask (POST /api/cortex/ask).\r\n * Used when intelligent query mode is disabled.\r\n */\r\n ask(apiUrl: string, token: string, text: string): Observable<any> {\r\n const headers = this.buildHeaders(token);\r\n return this.http.post<any>(`${apiUrl}/cortex/ask`, { text }, { headers });\r\n }\r\n\r\n private buildHeaders(token: string): HttpHeaders {\r\n return new HttpHeaders({ 'X-Api-Key': token });\r\n }\r\n}\r\n","import {\r\n Component, Input, inject, signal, computed, ViewChild, ElementRef,\r\n AfterViewChecked, OnChanges, OnInit, OnDestroy, SimpleChanges, HostListener\r\n} from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { DomSanitizer, SafeHtml, SafeResourceUrl } from '@angular/platform-browser';\r\nimport { marked } from 'marked';\r\nimport { IntelligentChatConfig, ChatMessage, PluginTheme } from './intelligent-chat.models';\r\nimport { IntelligentChatService } from './intelligent-chat.service';\r\n\r\n@Component({\r\n selector: 'intelligent-chat-plugin',\r\n standalone: true,\r\n imports: [CommonModule, FormsModule],\r\n template: `\r\n <!-- Host theme overrides -->\r\n <div class=\"iq-theme-host\" [ngStyle]=\"themeStyles()\">\r\n\r\n <!-- Floating Bubble Button (hidden when expanded) -->\r\n @if (!isExpanded()) {\r\n <button\r\n class=\"iq-bubble\"\r\n [class.iq-bottom-left]=\"resolvedConfig().position === 'bottom-left'\"\r\n [class.iq-open]=\"isOpen()\"\r\n [style.position]=\"resolvedConfig().stickyBubble ? 'fixed' : 'absolute'\"\r\n (click)=\"toggleChat()\"\r\n [attr.aria-label]=\"isOpen() ? 'Cerrar chat' : 'Abrir chat'\"\r\n >\r\n @if (isOpen()) {\r\n <span class=\"iq-bubble-icon\">✕</span>\r\n } @else {\r\n @switch (resolvedConfig().bubbleIconType) {\r\n @case ('image') {\r\n <img [src]=\"resolvedConfig().bubbleImageUrl\" alt=\"Chat\" class=\"iq-bubble-img\" />\r\n }\r\n @case ('svg') {\r\n <span class=\"iq-bubble-svg\" [innerHTML]=\"sanitizedBubbleSvg()\"></span>\r\n }\r\n @default {\r\n <span class=\"iq-bubble-icon\">{{ resolvedConfig().bubbleIcon }}</span>\r\n }\r\n }\r\n }\r\n </button>\r\n }\r\n\r\n <!-- Chat Panel -->\r\n @if (isOpen()) {\r\n <div\r\n class=\"iq-panel\"\r\n [class.iq-bottom-left]=\"resolvedConfig().position === 'bottom-left'\"\r\n [class.iq-expanded]=\"isExpanded()\"\r\n [class]=\"resolvedConfig().themeClass || ''\"\r\n [style.position]=\"resolvedConfig().stickyBubble ? 'fixed' : 'absolute'\"\r\n >\r\n <!-- Header -->\r\n <div class=\"iq-header\">\r\n <span class=\"iq-header-title\">{{ resolvedConfig().title }}</span>\r\n <div class=\"iq-header-actions\">\r\n <button class=\"iq-header-btn\" (click)=\"clearChat()\" title=\"Limpiar chat\">🗑️</button>\r\n @if (resolvedConfig().allowExpand) {\r\n <button class=\"iq-header-btn iq-btn-expand\" (click)=\"toggleExpand()\" [title]=\"isExpanded() ? 'Contraer' : 'Expandir'\">\r\n {{ isExpanded() ? '⊡' : '⛶' }}\r\n </button>\r\n }\r\n <button class=\"iq-header-btn\" (click)=\"isExpanded() ? toggleExpand() : toggleChat()\">✕</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Auth Error Banner -->\r\n @if (authError()) {\r\n <div class=\"iq-auth-error\">\r\n <span>🔒</span>\r\n <span>{{ authError() }}</span>\r\n </div>\r\n }\r\n\r\n <!-- Messages -->\r\n <div class=\"iq-messages\" #chatContainer>\r\n @if (messages().length === 0 && !authError()) {\r\n <div class=\"iq-empty\">\r\n <div class=\"iq-empty-icon\">\r\n @switch (resolvedConfig().bubbleIconType) {\r\n @case ('image') {\r\n <img [src]=\"resolvedConfig().bubbleImageUrl\" alt=\"\" class=\"iq-empty-img\" />\r\n }\r\n @case ('svg') {\r\n <span class=\"iq-empty-svg\" [innerHTML]=\"sanitizedBubbleSvg()\"></span>\r\n }\r\n @default {\r\n <span>{{ resolvedConfig().bubbleIcon }}</span>\r\n }\r\n }\r\n </div>\r\n <p>{{ resolvedConfig().welcomeTitle }}</p>\r\n <p class=\"iq-text-muted\">{{ resolvedConfig().welcomeSubtitle }}</p>\r\n </div>\r\n }\r\n\r\n @for (msg of messages(); track msg.id) {\r\n <div class=\"iq-msg\" [class.iq-msg-user]=\"msg.sender === 'user'\" [class.iq-msg-bot]=\"msg.sender === 'bot'\">\r\n <div class=\"iq-msg-content\">\r\n @if (msg.sender === 'bot') {\r\n <div class=\"iq-md\" [innerHTML]=\"renderMarkdown(msg.text)\" (click)=\"onMessageClick($event)\"></div>\r\n } @else {\r\n <p>{{ msg.text }}</p>\r\n }\r\n <span class=\"iq-msg-time\">{{ formatTime(msg.timestamp) }}</span>\r\n </div>\r\n @if (msg.sender === 'bot' && msg.traceData && resolvedConfig().showTrace) {\r\n <button class=\"iq-btn-trace\" (click)=\"showTrace(msg)\">🔍 Ver Traza</button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Pipeline progress -->\r\n @if (isLoading()) {\r\n <div class=\"iq-msg iq-msg-bot\">\r\n <div class=\"iq-msg-content iq-pipeline\">\r\n <span class=\"iq-dot\"></span>\r\n <span class=\"iq-pipeline-text\">{{ pipelineStep }}</span>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Input -->\r\n <form class=\"iq-input-bar\" (ngSubmit)=\"sendMessage()\">\r\n <input\r\n type=\"text\"\r\n [(ngModel)]=\"inputText\"\r\n name=\"message\"\r\n [placeholder]=\"resolvedConfig().placeholder!\"\r\n [disabled]=\"isLoading() || !!authError()\"\r\n autocomplete=\"off\"\r\n />\r\n <button type=\"submit\" class=\"iq-btn-send\" [disabled]=\"isLoading() || !inputText.trim() || !!authError()\">\r\n ➤\r\n </button>\r\n </form>\r\n </div>\r\n }\r\n\r\n <!-- Trace Modal Overlay -->\r\n @if (selectedTrace()) {\r\n <div class=\"iq-trace-overlay\" (click)=\"closeTrace()\">\r\n <div class=\"iq-trace-modal\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"iq-trace-header\">\r\n <h3>🔍 Detalle de Traza</h3>\r\n <button class=\"iq-header-btn\" (click)=\"closeTrace()\">✕</button>\r\n </div>\r\n <div class=\"iq-trace-body\">\r\n @if (selectedTrace()?.fromCache !== undefined) {\r\n <div class=\"iq-trace-item\">\r\n <label>Origen</label>\r\n <code [class.iq-cache-hit]=\"selectedTrace()?.fromCache\">{{ selectedTrace()?.fromCache ? '📚 Desde Caché' : '🤖 Generado por GPT' }}</code>\r\n </div>\r\n }\r\n @if (selectedTrace()?.query) {\r\n <div class=\"iq-trace-item\">\r\n <label>Query Generada</label>\r\n <pre class=\"iq-query-code\">{{ selectedTrace()?.query }}</pre>\r\n </div>\r\n }\r\n @if (selectedTrace()?.explanation) {\r\n <div class=\"iq-trace-item\">\r\n <label>Explicación</label>\r\n <code>{{ selectedTrace()?.explanation }}</code>\r\n </div>\r\n }\r\n @if (selectedTrace()?.traceId) {\r\n <div class=\"iq-trace-item\">\r\n <label>Trace ID</label>\r\n <code>{{ selectedTrace()?.traceId }}</code>\r\n </div>\r\n }\r\n @if (selectedTrace()?.data) {\r\n <div class=\"iq-trace-item\">\r\n <label>Datos Retornados</label>\r\n <pre>{{ selectedTrace()?.data | json }}</pre>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Link Modal Overlay -->\r\n @if (modalUrl()) {\r\n <div class=\"iq-link-overlay\" (click)=\"closeLinkModal()\">\r\n <div class=\"iq-link-modal\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"iq-link-header\">\r\n @if (showHomeBtn()) {\r\n <button class=\"iq-header-btn iq-back-btn\" (click)=\"iframeGoHome()\" title=\"Volver al inicio\">🏠</button>\r\n }\r\n <span class=\"iq-link-title\" [title]=\"modalUrl()!\">{{ modalUrl() }}</span>\r\n <div class=\"iq-link-actions\">\r\n <a [href]=\"modalUrl()!\" target=\"_blank\" rel=\"noopener\" class=\"iq-header-btn\" title=\"Abrir en nueva pestaña\">↗</a>\r\n <button class=\"iq-header-btn\" (click)=\"closeLinkModal()\">✕</button>\r\n </div>\r\n </div>\r\n <div class=\"iq-iframe-wrapper\">\r\n @if (isModalImage()) {\r\n <img [src]=\"modalUrl()!\" class=\"iq-modal-img\" alt=\"Imagen\" />\r\n } @else {\r\n @if (modalLoading()) {\r\n <div class=\"iq-iframe-loader\">\r\n <div class=\"iq-spinner\"></div>\r\n <span class=\"iq-loader-text\">Cargando...</span>\r\n </div>\r\n }\r\n <iframe #linkIframe [src]=\"sanitizedModalUrl()\" class=\"iq-link-iframe\"\r\n [class.iq-iframe-hidden]=\"modalLoading()\"\r\n (load)=\"onIframeLoaded()\"></iframe>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n </div><!-- /iq-theme-host -->\r\n `,\r\n styles: [`\r\n /* ========= CSS Custom Properties (overridable by host) ========= */\r\n :host {\r\n --iq-primary: #1a3a5c;\r\n --iq-primary-light: #2a5a8c;\r\n --iq-accent: #00d4aa;\r\n --iq-accent-light: #33e0be;\r\n --iq-bg: #1e1e2f;\r\n --iq-bg-card: #252538;\r\n --iq-bg-tertiary: #35354a;\r\n --iq-text: #ffffff;\r\n --iq-text-secondary: #a0a0b0;\r\n --iq-text-muted: #6c6c7c;\r\n --iq-border: #3a3a4d;\r\n --iq-radius: 12px;\r\n --iq-bubble-size: 56px;\r\n --iq-panel-width: 400px;\r\n --iq-panel-height: 520px;\r\n --iq-z: 10000;\r\n --iq-font: 'Inter', 'Roboto', -apple-system, BlinkMacSystemFont, sans-serif;\r\n font-family: var(--iq-font);\r\n }\r\n\r\n /* ========= Bubble ========= */\r\n .iq-bubble {\r\n position: fixed;\r\n bottom: 24px;\r\n right: 24px;\r\n z-index: var(--iq-z);\r\n width: var(--iq-bubble-size);\r\n height: var(--iq-bubble-size);\r\n border-radius: 50%;\r\n border: none;\r\n background: linear-gradient(135deg, var(--iq-accent), var(--iq-accent-light));\r\n color: var(--iq-bg);\r\n font-size: 1.6rem;\r\n cursor: pointer;\r\n box-shadow: 0 4px 16px rgba(0, 212, 170, 0.4);\r\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n }\r\n .iq-bubble:hover {\r\n transform: scale(1.1);\r\n box-shadow: 0 6px 24px rgba(0, 212, 170, 0.5);\r\n }\r\n .iq-bubble .iq-bubble-icon {\r\n font-size: 1.5rem;\r\n pointer-events: none;\r\n }\r\n\r\n .iq-bubble-img {\r\n width: 60%; height: 60%;\r\n object-fit: contain; border-radius: 50%;\r\n pointer-events: none;\r\n }\r\n\r\n .iq-bubble-svg {\r\n width: 60%; height: 60%;\r\n display: flex; align-items: center; justify-content: center;\r\n pointer-events: none;\r\n }\r\n .iq-bubble-svg :deep(svg) { width: 100%; height: 100%; }\r\n\r\n .iq-bubble.iq-open {\r\n background: var(--iq-bg-tertiary);\r\n color: var(--iq-text);\r\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\r\n font-size: 1.2rem;\r\n }\r\n .iq-bubble.iq-bottom-left {\r\n right: auto;\r\n left: 24px;\r\n }\r\n .iq-bubble-icon { line-height: 1; }\r\n\r\n /* ========= Panel ========= */\r\n .iq-panel {\r\n position: fixed;\r\n bottom: 92px;\r\n right: 24px;\r\n z-index: var(--iq-z);\r\n width: var(--iq-panel-width);\r\n height: var(--iq-panel-height);\r\n background: var(--iq-bg);\r\n border: 1px solid var(--iq-border);\r\n border-radius: var(--iq-radius);\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n box-shadow: 0 12px 40px rgba(0,0,0,0.5);\r\n animation: iq-slide-up 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n }\r\n .iq-panel.iq-bottom-left {\r\n right: auto;\r\n left: 24px;\r\n }\r\n /* ========= Expanded / Fullscreen ========= */\r\n .iq-panel.iq-expanded {\r\n width: 100vw !important;\r\n height: 100vh !important;\r\n top: 0 !important;\r\n left: 0 !important;\r\n right: 0 !important;\r\n bottom: 0 !important;\r\n border: none;\r\n border-radius: 0;\r\n overflow: clip;\r\n z-index: calc(var(--iq-z) + 5);\r\n animation: iq-expand 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n }\r\n .iq-btn-expand {\r\n font-size: 1.1rem !important;\r\n }\r\n @keyframes iq-expand {\r\n from { opacity: 0.8; transform: scale(0.95); }\r\n to { opacity: 1; transform: scale(1); }\r\n }\r\n @keyframes iq-slide-up {\r\n from { opacity: 0; transform: translateY(16px) scale(0.96); }\r\n to { opacity: 1; transform: translateY(0) scale(1); }\r\n }\r\n\r\n /* ========= Header ========= */\r\n .iq-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 12px 16px;\r\n border-bottom: 1px solid var(--iq-border);\r\n background: var(--iq-bg-card);\r\n }\r\n .iq-header-title {\r\n font-weight: 600;\r\n font-size: 0.95rem;\r\n color: var(--iq-text);\r\n }\r\n .iq-header-actions {\r\n display: flex;\r\n gap: 4px;\r\n }\r\n .iq-header-btn {\r\n background: none;\r\n border: none;\r\n color: var(--iq-text-muted);\r\n cursor: pointer;\r\n font-size: 1rem;\r\n padding: 4px 6px;\r\n border-radius: 4px;\r\n transition: all 0.15s;\r\n }\r\n .iq-header-btn:hover {\r\n color: var(--iq-text);\r\n background: rgba(255,255,255,0.08);\r\n }\r\n\r\n /* ========= Auth Error ========= */\r\n .iq-auth-error {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 10px 16px;\r\n background: rgba(220, 53, 69, 0.15);\r\n color: #ff6b7a;\r\n font-size: 0.8rem;\r\n border-bottom: 1px solid rgba(220, 53, 69, 0.25);\r\n }\r\n\r\n /* ========= Messages ========= */\r\n .iq-messages {\r\n flex: 1;\r\n min-height: 0;\r\n overflow-y: auto;\r\n padding: 12px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 10px;\r\n }\r\n\r\n .iq-empty {\r\n flex: 1;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n text-align: center;\r\n color: var(--iq-text-secondary);\r\n }\r\n .iq-empty-icon { font-size: 3rem; margin-bottom: 8px; display: flex; align-items: center; justify-content: center; }\r\n .iq-empty-img { width: 48px; height: 48px; object-fit: contain; border-radius: 8px; }\r\n .iq-empty-svg { width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; }\r\n .iq-empty-svg :deep(svg) { width: 100%; height: 100%; }\r\n .iq-empty p { font-size: 0.95rem; margin: 2px 0; }\r\n .iq-text-muted { color: var(--iq-text-muted) !important; font-size: 0.8rem !important; }\r\n\r\n .iq-msg { display: flex; flex-direction: column; max-width: 85%; }\r\n .iq-msg-user { align-self: flex-end; }\r\n .iq-msg-bot { align-self: flex-start; max-width: 100%; }\r\n\r\n .iq-msg-user .iq-msg-content {\r\n background: linear-gradient(135deg, var(--iq-primary), var(--iq-primary-light));\r\n border-radius: 12px 12px 0 12px;\r\n }\r\n .iq-msg-bot .iq-msg-content {\r\n background: var(--iq-bg-tertiary);\r\n border-radius: 12px 12px 12px 0;\r\n }\r\n .iq-msg-content {\r\n padding: 10px 14px;\r\n color: var(--iq-text);\r\n font-size: 0.85rem;\r\n line-height: 1.45;\r\n }\r\n .iq-msg-content p { margin: 0; white-space: pre-wrap; }\r\n .iq-msg-time {\r\n display: block;\r\n margin-top: 4px;\r\n font-size: 0.65rem;\r\n color: rgba(255,255,255,0.5);\r\n }\r\n\r\n /* Markdown rendered content */\r\n .iq-md { line-height: 1.5; overflow-x: auto; max-width: 100%; }\r\n .iq-md :first-child { margin-top: 0; }\r\n .iq-md :last-child { margin-bottom: 0; }\r\n .iq-md p { margin: 0 0 0.4em 0; }\r\n .iq-md p:last-child { margin-bottom: 0; }\r\n .iq-md strong { color: var(--iq-accent); }\r\n .iq-md ul, .iq-md ol { margin: 0.3em 0; padding-left: 1.2em; }\r\n .iq-md li { margin: 0.15em 0; }\r\n .iq-md code {\r\n background: rgba(0,0,0,0.3);\r\n padding: 0.15em 0.4em;\r\n border-radius: 3px;\r\n font-size: 0.82em;\r\n }\r\n .iq-md pre {\r\n background: rgba(0,0,0,0.3);\r\n padding: 0.8em;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n font-size: 0.78em;\r\n margin: 0.4em 0;\r\n }\r\n .iq-md pre code { background: none; padding: 0; }\r\n .iq-md table {\r\n width: max-content; min-width: 100%;\r\n border-collapse: separate; border-spacing: 0;\r\n margin: 0.5em 0; font-size: 0.75rem;\r\n border-radius: 6px; overflow: hidden;\r\n }\r\n .iq-md thead th {\r\n background: rgba(99,102,241,0.18); color: #a5b4fc;\r\n font-weight: 600; text-align: left;\r\n padding: 0.5em 0.8em; border-bottom: 2px solid rgba(99,102,241,0.3);\r\n white-space: nowrap; font-size: 0.7rem;\r\n text-transform: uppercase; letter-spacing: 0.05em;\r\n }\r\n .iq-md tbody td {\r\n padding: 0.4em 0.8em; border-bottom: 1px solid rgba(255,255,255,0.06);\r\n white-space: nowrap; color: var(--iq-text-secondary);\r\n }\r\n .iq-md tbody tr:hover { background: rgba(99,102,241,0.08); }\r\n\r\n /* Inline images in bot messages – small thumbnails, click to enlarge */\r\n .iq-md img {\r\n max-height: 80px; max-width: 120px; object-fit: cover;\r\n border-radius: 8px; margin: 6px 4px 6px 0;\r\n display: inline-block; vertical-align: middle;\r\n border: 1px solid rgba(255,255,255,0.15);\r\n box-shadow: 0 1px 4px rgba(0,0,0,0.25);\r\n cursor: pointer; transition: transform 0.15s, box-shadow 0.15s;\r\n }\r\n .iq-md img:hover {\r\n transform: scale(1.05);\r\n box-shadow: 0 3px 12px rgba(99,102,241,0.35);\r\n border-color: var(--iq-accent);\r\n }\r\n .iq-md img[alt*=\"logo\"], .iq-md img[alt*=\"marca\"] {\r\n max-height: 28px; max-width: 90px; object-fit: contain;\r\n border: none; box-shadow: none; border-radius: 4px;\r\n background: rgba(255,255,255,0.9); padding: 2px 6px;\r\n }\r\n /* Trace button */\r\n .iq-btn-trace {\r\n align-self: flex-start; margin-top: 4px;\r\n background: transparent; border: 1px solid var(--iq-border);\r\n color: var(--iq-text-secondary); font-size: 0.7rem;\r\n padding: 3px 8px; border-radius: 4px; cursor: pointer;\r\n transition: all 0.15s;\r\n }\r\n .iq-btn-trace:hover { border-color: var(--iq-accent); color: var(--iq-accent); }\r\n\r\n /* Pipeline loading indicator */\r\n .iq-pipeline {\r\n display: flex; align-items: center; gap: 8px;\r\n animation: iq-fade-in 0.3s ease-out;\r\n }\r\n .iq-dot {\r\n width: 8px; height: 8px; border-radius: 50%;\r\n background: var(--iq-accent);\r\n animation: iq-pulse 1s ease-in-out infinite;\r\n }\r\n .iq-pipeline-text {\r\n font-size: 0.8rem; color: var(--iq-text-muted); font-style: italic;\r\n }\r\n @keyframes iq-pulse {\r\n 0%, 100% { opacity: 1; transform: scale(1); }\r\n 50% { opacity: 0.4; transform: scale(0.7); }\r\n }\r\n @keyframes iq-fade-in {\r\n from { opacity: 0; transform: translateX(-6px); }\r\n to { opacity: 1; transform: translateX(0); }\r\n }\r\n\r\n /* ========= Input Bar ========= */\r\n .iq-input-bar {\r\n display: flex; gap: 8px;\r\n padding: 10px 12px;\r\n border-top: 1px solid var(--iq-border);\r\n background: var(--iq-bg-card);\r\n }\r\n .iq-input-bar input {\r\n flex: 1; padding: 8px 12px;\r\n background: var(--iq-bg-tertiary);\r\n border: 1px solid var(--iq-border);\r\n border-radius: 8px;\r\n color: var(--iq-text);\r\n font-size: 0.85rem;\r\n font-family: var(--iq-font);\r\n outline: none;\r\n transition: border-color 0.15s;\r\n }\r\n .iq-input-bar input:focus { border-color: var(--iq-accent); }\r\n .iq-input-bar input::placeholder { color: var(--iq-text-muted); }\r\n .iq-input-bar input:disabled { opacity: 0.5; }\r\n .iq-btn-send {\r\n width: 36px; height: 36px;\r\n border-radius: 8px; border: none;\r\n background: linear-gradient(135deg, var(--iq-accent), var(--iq-accent-light));\r\n color: var(--iq-bg); font-size: 1rem;\r\n cursor: pointer; transition: all 0.2s;\r\n display: flex; align-items: center; justify-content: center;\r\n }\r\n .iq-btn-send:hover:not(:disabled) { box-shadow: 0 0 12px rgba(0,212,170,0.4); transform: translateY(-1px); }\r\n .iq-btn-send:disabled { opacity: 0.4; cursor: not-allowed; }\r\n\r\n /* ========= Trace Modal ========= */\r\n .iq-trace-overlay {\r\n position: fixed; inset: 0;\r\n z-index: calc(var(--iq-z) + 10);\r\n background: rgba(0,0,0,0.6);\r\n display: flex; align-items: center; justify-content: center;\r\n animation: iq-fade-in 0.2s ease-out;\r\n }\r\n .iq-trace-modal {\r\n width: 90%; max-width: 520px; max-height: 80vh;\r\n background: var(--iq-bg); border: 1px solid var(--iq-border);\r\n border-radius: var(--iq-radius);\r\n display: flex; flex-direction: column; overflow: hidden;\r\n box-shadow: 0 20px 50px rgba(0,0,0,0.6);\r\n }\r\n .iq-trace-header {\r\n display: flex; align-items: center; justify-content: space-between;\r\n padding: 14px 16px; border-bottom: 1px solid var(--iq-border);\r\n }\r\n .iq-trace-header h3 { margin: 0; font-size: 0.95rem; color: var(--iq-text); }\r\n .iq-trace-body {\r\n flex: 1; overflow-y: auto; padding: 16px;\r\n display: flex; flex-direction: column; gap: 12px;\r\n }\r\n .iq-trace-item label {\r\n display: block; font-size: 0.7rem; color: var(--iq-text-muted);\r\n margin-bottom: 4px; text-transform: uppercase; letter-spacing: 0.05em;\r\n }\r\n .iq-trace-item code {\r\n display: block; padding: 8px;\r\n background: var(--iq-bg-tertiary); border-radius: 4px;\r\n font-family: monospace; font-size: 0.8rem; color: var(--iq-accent);\r\n word-break: break-all;\r\n }\r\n .iq-trace-item pre {\r\n margin: 0; padding: 8px;\r\n background: var(--iq-bg-tertiary); border-radius: 4px;\r\n font-family: monospace; font-size: 0.7rem;\r\n overflow-x: auto; max-height: 180px; color: var(--iq-text-secondary);\r\n }\r\n .iq-cache-hit { background: rgba(16,185,129,0.15) !important; color: #10b981 !important; }\r\n .iq-query-code { color: var(--iq-accent) !important; }\r\n\r\n /* ========= Link Modal ========= */\r\n .iq-link-overlay {\r\n position: fixed; inset: 0;\r\n z-index: calc(var(--iq-z) + 20);\r\n background: rgba(0,0,0,0.7);\r\n display: flex; align-items: center; justify-content: center;\r\n animation: iq-fade-in 0.2s ease-out;\r\n backdrop-filter: blur(4px);\r\n }\r\n .iq-link-modal {\r\n width: 94vw; height: 92vh;\r\n background: var(--iq-bg); border: 1px solid var(--iq-border);\r\n border-radius: var(--iq-radius);\r\n display: flex; flex-direction: column; overflow: hidden;\r\n box-shadow: 0 24px 60px rgba(0,0,0,0.7);\r\n animation: iq-expand 0.25s cubic-bezier(0.4, 0, 0.2, 1);\r\n }\r\n .iq-link-header {\r\n display: flex; align-items: center; justify-content: space-between;\r\n padding: 10px 16px; border-bottom: 1px solid var(--iq-border);\r\n background: var(--iq-bg-card); gap: 12px; min-height: 44px;\r\n }\r\n .iq-link-title {\r\n flex: 1; font-size: 0.78rem; color: var(--iq-text-secondary);\r\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\r\n font-family: monospace;\r\n }\r\n .iq-link-actions {\r\n display: flex; gap: 4px; flex-shrink: 0;\r\n }\r\n .iq-link-actions a {\r\n text-decoration: none;\r\n }\r\n .iq-back-btn {\r\n flex-shrink: 0; font-size: 1.1rem;\r\n transition: transform 0.15s ease;\r\n }\r\n .iq-back-btn:hover {\r\n transform: translateX(-2px);\r\n }\r\n .iq-iframe-wrapper {\r\n flex: 1; position: relative; overflow: hidden;\r\n }\r\n .iq-link-iframe {\r\n width: 100%; height: 100%; border: none;\r\n background: #fff;\r\n transition: opacity 0.3s ease;\r\n }\r\n .iq-iframe-hidden {\r\n opacity: 0;\r\n }\r\n .iq-modal-img {\r\n width: 100%; height: 100%;\r\n object-fit: contain;\r\n background: #1a1a2e;\r\n }\r\n .iq-iframe-loader {\r\n position: absolute; inset: 0;\r\n display: flex; flex-direction: column;\r\n align-items: center; justify-content: center;\r\n background: var(--iq-bg);\r\n gap: 16px; z-index: 2;\r\n }\r\n .iq-spinner {\r\n width: 40px; height: 40px;\r\n border: 3px solid var(--iq-border);\r\n border-top-color: var(--iq-accent);\r\n border-radius: 50%;\r\n animation: iq-spin 0.8s linear infinite;\r\n }\r\n .iq-loader-text {\r\n font-size: 0.85rem; color: var(--iq-text-secondary);\r\n font-weight: 500;\r\n }\r\n @keyframes iq-spin {\r\n to { transform: rotate(360deg); }\r\n }\r\n\r\n /* ========= Link Modal — markdown link styling ========= */\r\n .iq-md a {\r\n color: var(--iq-accent); text-decoration: underline;\r\n cursor: pointer; transition: color 0.15s;\r\n }\r\n .iq-md a:hover {\r\n color: var(--iq-accent-light);\r\n }\r\n\r\n @media (max-width: 480px) {\r\n .iq-link-modal {\r\n width: 100vw; height: 100dvh;\r\n border-radius: 0;\r\n }\r\n .iq-link-header { padding: 8px 12px; }\r\n .iq-link-title { font-size: 0.7rem; }\r\n }\r\n\r\n /* ========= Scrollbar ========= */\r\n .iq-messages::-webkit-scrollbar { width: 5px; }\r\n .iq-messages::-webkit-scrollbar-track { background: transparent; }\r\n .iq-messages::-webkit-scrollbar-thumb { background: var(--iq-border); border-radius: 4px; }\r\n .iq-trace-body::-webkit-scrollbar { width: 5px; }\r\n .iq-trace-body::-webkit-scrollbar-track { background: transparent; }\r\n .iq-trace-body::-webkit-scrollbar-thumb { background: var(--iq-border); border-radius: 4px; }\r\n /* Wider scrollbar in fullscreen for easier grabbing */\r\n .iq-expanded .iq-messages::-webkit-scrollbar { width: 8px; }\r\n .iq-expanded .iq-messages { scrollbar-gutter: stable; }\r\n\r\n /* ========= Mobile Small Screens ========= */\r\n @media (max-width: 480px) {\r\n .iq-bubble {\r\n bottom: 16px;\r\n right: 16px;\r\n width: 48px;\r\n height: 48px;\r\n font-size: 1.3rem;\r\n }\r\n .iq-bubble.iq-bottom-left {\r\n left: 16px;\r\n }\r\n .iq-bubble .iq-bubble-icon { font-size: 1.2rem; }\r\n\r\n .iq-panel {\r\n right: 8px;\r\n left: 8px;\r\n bottom: 72px;\r\n width: auto !important;\r\n max-width: calc(100vw - 16px);\r\n height: calc(100dvh - 90px);\r\n max-height: calc(100dvh - 90px);\r\n }\r\n .iq-panel.iq-bottom-left {\r\n left: 8px;\r\n right: 8px;\r\n }\r\n .iq-panel.iq-expanded {\r\n top: 0 !important;\r\n left: 0 !important;\r\n right: 0 !important;\r\n bottom: 0 !important;\r\n width: 100vw !important;\r\n height: 100dvh !important;\r\n max-height: 100dvh !important;\r\n max-width: 100vw !important;\r\n border-radius: 0;\r\n }\r\n\r\n .iq-header {\r\n padding: 10px 12px;\r\n }\r\n .iq-header-title { font-size: 0.85rem; }\r\n .iq-header-btn { padding: 6px 8px; min-width: 32px; min-height: 32px; }\r\n\r\n .iq-messages { padding: 8px; gap: 8px; }\r\n\r\n .iq-msg { max-width: 92%; }\r\n .iq-msg-bot { max-width: 100%; }\r\n .iq-msg-content { padding: 8px 10px; font-size: 0.8rem; }\r\n\r\n .iq-md { overflow-x: auto; -webkit-overflow-scrolling: touch; }\r\n .iq-md table { font-size: 0.65rem; min-width: unset; }\r\n .iq-md thead th { padding: 0.35em 0.5em; font-size: 0.6rem; }\r\n .iq-md tbody td { padding: 0.3em 0.5em; font-size: 0.65rem; }\r\n\r\n .iq-empty-icon { font-size: 2.5rem; }\r\n .iq-empty p { font-size: 0.85rem; }\r\n\r\n .iq-input-bar { padding: 8px 10px; gap: 6px; }\r\n .iq-input-bar input { font-size: 16px; padding: 8px 10px; }\r\n .iq-btn-send { width: 38px; height: 38px; flex-shrink: 0; }\r\n\r\n .iq-trace-modal {\r\n width: calc(100vw - 24px);\r\n max-height: 90dvh;\r\n }\r\n .iq-trace-header { padding: 12px; }\r\n .iq-trace-header h3 { font-size: 0.85rem; }\r\n .iq-trace-body { padding: 12px; }\r\n .iq-trace-item pre { font-size: 0.65rem; max-height: 140px; }\r\n }\r\n\r\n /* ========= Landscape Mobile — fit floating panel ========= */\r\n @media (max-height: 500px) and (orientation: landscape) {\r\n .iq-bubble {\r\n bottom: 8px;\r\n right: 8px;\r\n width: 44px;\r\n height: 44px;\r\n font-size: 1.1rem;\r\n }\r\n .iq-bubble.iq-bottom-left { left: 8px; }\r\n\r\n .iq-panel {\r\n right: 60px;\r\n left: 8px;\r\n bottom: 8px;\r\n top: 8px;\r\n width: auto !important;\r\n max-width: calc(100vw - 76px);\r\n height: auto !important;\r\n max-height: calc(100dvh - 16px);\r\n border-radius: var(--iq-radius);\r\n }\r\n .iq-panel.iq-bottom-left {\r\n left: 60px;\r\n right: 8px;\r\n }\r\n .iq-panel.iq-expanded {\r\n top: 0 !important;\r\n left: 0 !important;\r\n right: 0 !important;\r\n bottom: 0 !important;\r\n width: 100vw !important;\r\n height: 100dvh !important;\r\n max-height: 100dvh !important;\r\n max-width: 100vw !important;\r\n border-radius: 0;\r\n }\r\n\r\n .iq-header { padding: 6px 12px; }\r\n .iq-header-title { font-size: 0.8rem; }\r\n .iq-messages { padding: 6px 10px; gap: 6px; }\r\n .iq-empty-icon { font-size: 1.8rem; margin-bottom: 4px; }\r\n .iq-empty p { font-size: 0.78rem; margin: 1px 0; }\r\n .iq-input-bar { padding: 6px 10px; }\r\n .iq-input-bar input { font-size: 16px; padding: 6px 10px; }\r\n .iq-btn-send { width: 32px; height: 32px; }\r\n }\r\n `]\r\n})\r\nexport class IntelligentChatPluginComponent implements AfterViewChecked, OnChanges, OnInit, OnDestroy {\r\n @ViewChild('chatContainer') private chatContainer!: ElementRef;\r\n\r\n @Input() config!: IntelligentChatConfig;\r\n\r\n private chatService = inject(IntelligentChatService);\r\n private hostEl = inject(ElementRef);\r\n\r\n // State\r\n isOpen = signal(false);\r\n isExpanded = signal(false);\r\n messages = signal<ChatMessage[]>([]);\r\n isLoading = signal(false);\r\n selectedTrace = signal<any>(null);\r\n authError = signal<string | null>(null);\r\n modalUrl = signal<string | null>(null);\r\n isModalImage = computed(() => {\r\n const url = this.modalUrl();\r\n if (!url) return false;\r\n return /\\.(jpg|jpeg|png|gif|webp|svg|bmp)(\\?.*)?$/i.test(url);\r\n });\r\n modalLoading = signal(false);\r\n showHomeBtn = signal(false);\r\n private originalModalUrl = '';\r\n private modalReadyForNav = false;\r\n private navReadyTimer: any = null;\r\n inputText = '';\r\n\r\n // Pipeline step (driven by real SSE events from backend)\r\n pipelineStep = '';\r\n\r\n private messageId = 0;\r\n private shouldScroll = false;\r\n\r\n // ─── Session Persistence ──────────────────────────\r\n private readonly STORAGE_PREFIX = 'iq_chat_session_';\r\n private sessionKey = '';\r\n private storageListener = (e: StorageEvent) => this.onStorageChange(e);\r\n\r\n /** Resolved config with defaults applied */\r\n private sanitizer = inject(DomSanitizer);\r\n\r\n resolvedConfig = signal<Required<IntelligentChatConfig>>({\r\n apiUrl: '',\r\n systemId: '',\r\n token: '',\r\n useIntelligentQuery: true,\r\n skipPatterns: true,\r\n baseContext: '',\r\n showTrace: false,\r\n showPipelineSteps: true,\r\n preferTableFormat: true,\r\n title: 'Maquito Chat',\r\n placeholder: 'Escribe tu consulta aquí...',\r\n welcomeTitle: '¡Hola! Soy Maquito.',\r\n welcomeSubtitle: 'Escribe tu consulta para comenzar.',\r\n position: 'bottom-right',\r\n bubbleIcon: '🤖',\r\n bubbleIconType: 'emoji',\r\n bubbleImageUrl: '',\r\n bubbleSvg: '',\r\n themeClass: '',\r\n stickyBubble: true,\r\n allowExpand: false,\r\n theme: {},\r\n userName: '',\r\n personality: ''\r\n });\r\n\r\n /** Map theme object → CSS variable overrides */\r\n themeStyles = computed(() => {\r\n const t = this.resolvedConfig().theme || {};\r\n const map: Record<string, string> = {};\r\n const pairs: [keyof PluginTheme, string][] = [\r\n ['primary', '--iq-primary'], ['primaryLight', '--iq-primary-light'],\r\n ['accent', '--iq-accent'], ['accentLight', '--iq-accent-light'],\r\n ['bg', '--iq-bg'], ['bgCard', '--iq-bg-card'], ['bgTertiary', '--iq-bg-tertiary'],\r\n ['text', '--iq-text'], ['textSecondary', '--iq-text-secondary'],\r\n ['textMuted', '--iq-text-muted'], ['border', '--iq-border']\r\n ];\r\n for (const [key, cssVar] of pairs) {\r\n if (t[key]) map[cssVar] = t[key]!;\r\n }\r\n return map;\r\n });\r\n\r\n /** Sanitised SVG HTML for bubble */\r\n sanitizedBubbleSvg = computed<SafeHtml>(() => {\r\n const raw = this.resolvedConfig().bubbleSvg || '';\r\n return this.sanitizer.bypassSecurityTrustHtml(raw);\r\n });\r\n\r\n /** Sanitised URL for the link modal iframe */\r\n sanitizedModalUrl = computed<SafeResourceUrl>(() => {\r\n const url = this.modalUrl() || '';\r\n return this.sanitizer.bypassSecurityTrustResourceUrl(url);\r\n });\r\n\r\n ngOnInit(): void {\r\n window.addEventListener('storage', this.storageListener);\r\n }\r\n\r\n ngOnDestroy(): void {\r\n window.removeEventListener('storage', this.storageListener);\r\n this.pipelineStep = '';\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if (changes['config'] && this.config) {\r\n this.resolvedConfig.set({\r\n apiUrl: this.config.apiUrl || '',\r\n systemId: this.config.systemId || '',\r\n token: this.config.token || '',\r\n useIntelligentQuery: this.config.useIntelligentQuery ?? true,\r\n skipPatterns: this.config.skipPatterns ?? true,\r\n baseContext: this.config.baseContext || '',\r\n showTrace: this.config.showTrace ?? false,\r\n showPipelineSteps: this.config.showPipelineSteps ?? true,\r\n preferTableFormat: this.config.preferTableFormat ?? true,\r\n title: this.config.title || 'Maquito Chat',\r\n placeholder: this.config.placeholder || 'Escribe tu consulta aquí...',\r\n welcomeTitle: this.config.welcomeTitle || '¡Hola! Soy Maquito.',\r\n welcomeSubtitle: this.config.welcomeSubtitle || 'Escribe tu consulta para comenzar.',\r\n position: this.config.position || 'bottom-right',\r\n bubbleIcon: this.config.bubbleIcon || '🤖',\r\n bubbleIconType: this.config.bubbleIconType || 'emoji',\r\n bubbleImageUrl: this.config.bubbleImageUrl || '',\r\n bubbleSvg: this.config.bubbleSvg || '',\r\n themeClass: this.config.themeClass || '',\r\n stickyBubble: this.config.stickyBubble ?? true,\r\n allowExpand: this.config.allowExpand ?? false,\r\n theme: this.config.theme || {},\r\n userName: this.config.userName || '',\r\n personality: this.config.personality || ''\r\n });\r\n // Rebuild session key when config changes\r\n const newKey = this.buildSessionKey();\r\n if (newKey !== this.sessionKey) {\r\n this.sessionKey = newKey;\r\n this.loadSession();\r\n }\r\n // Clear auth error when config changes (user may be testing a new token)\r\n this.authError.set(null);\r\n }\r\n }\r\n\r\n ngAfterViewChecked(): void {\r\n if (this.shouldScroll) {\r\n this.scrollToBottom();\r\n this.shouldScroll = false;\r\n }\r\n }\r\n\r\n toggleChat(): void {\r\n this.isOpen.update(v => !v);\r\n if (!this.isOpen()) {\r\n this.isExpanded.set(false);\r\n this.setHostScrollLock(false);\r\n }\r\n if (this.isOpen()) this.shouldScroll = true;\r\n }\r\n\r\n toggleExpand(): void {\r\n this.isExpanded.update(v => !v);\r\n this.setHostScrollLock(this.isExpanded());\r\n }\r\n\r\n /** Lock/unlock the host page scroll to prevent its scrollbar from overlapping ours */\r\n private setHostScrollLock(lock: boolean): void {\r\n document.body.style.overflow = lock ? 'hidden' : '';\r\n // Also target common host containers\r\n const mc = document.querySelector('.main-container') as HTMLElement;\r\n if (mc) mc.style.overflow = lock ? 'hidden' : '';\r\n }\r\n\r\n sendMessage(): void {\r\n const text = this.inputText.trim();\r\n if (!text) return;\r\n\r\n const cfg = this.resolvedConfig();\r\n\r\n // Validate required config\r\n if (!cfg.token) {\r\n this.authError.set('Token no configurado. El plugin requiere un token técnico válido.');\r\n return;\r\n }\r\n if (!cfg.apiUrl) {\r\n this.authError.set('API URL no configurada.');\r\n return;\r\n }\r\n\r\n this.authError.set(null);\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text,\r\n sender: 'user',\r\n timestamp: new Date()\r\n }]);\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n this.inputText = '';\r\n this.isLoading.set(true);\r\n\r\n if (cfg.showPipelineSteps) {\r\n this.pipelineStep = '⏳ Procesando...';\r\n } else {\r\n this.pipelineStep = '⏳ Procesando...';\r\n }\r\n\r\n if (cfg.useIntelligentQuery && cfg.systemId) {\r\n // Build conversation history from previous messages (last 6 pairs)\r\n const history = this.messages()\r\n .filter(m => m.sender === 'user' || m.sender === 'bot')\r\n .slice(-12)\r\n .map(msg => ({\r\n role: msg.sender === 'user' ? 'user' : 'assistant',\r\n content: msg.text\r\n }));\r\n\r\n const ctx = cfg.baseContext?.trim() || undefined;\r\n\r\n if (cfg.showPipelineSteps) {\r\n // Use SSE streaming for real-time pipeline progress\r\n this.chatService.executeIntelligentQueryStream(\r\n cfg.apiUrl, cfg.token, cfg.systemId, text, history, ctx, cfg.skipPatterns, cfg.preferTableFormat,\r\n cfg.userName || undefined, cfg.personality || undefined\r\n ).subscribe({\r\n next: (event) => {\r\n if (event.type === 'progress') {\r\n this.pipelineStep = event.message || '';\r\n } else if (event.type === 'result') {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n const response = event.data;\r\n const responseText = response.success\r\n ? (response.response || 'Consulta ejecutada correctamente')\r\n : (response.error || 'Error en la consulta');\r\n\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: responseText,\r\n sender: 'bot',\r\n timestamp: new Date(),\r\n traceData: {\r\n traceId: response.traceId,\r\n fromCache: response.fromCache,\r\n fromContext: response.fromContext,\r\n query: response.query,\r\n explanation: response.explanation,\r\n patternId: response.patternId,\r\n data: response.data\r\n }\r\n }]);\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n }\r\n },\r\n error: (error) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n this.handleError(error);\r\n }\r\n });\r\n } else {\r\n // Fallback: use standard non-streaming endpoint\r\n this.chatService.executeIntelligentQuery(\r\n cfg.apiUrl, cfg.token, cfg.systemId, text, history, ctx, cfg.skipPatterns, cfg.preferTableFormat,\r\n cfg.userName || undefined, cfg.personality || undefined\r\n ).subscribe({\r\n next: (response: any) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n const responseText = response.success\r\n ? (response.response || 'Consulta ejecutada correctamente')\r\n : (response.error || 'Error en la consulta');\r\n\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: responseText,\r\n sender: 'bot',\r\n timestamp: new Date(),\r\n traceData: {\r\n traceId: response.traceId,\r\n fromCache: response.fromCache,\r\n fromContext: response.fromContext,\r\n query: response.query,\r\n explanation: response.explanation,\r\n patternId: response.patternId,\r\n data: response.data\r\n }\r\n }]);\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n },\r\n error: (error) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n this.handleError(error);\r\n }\r\n });\r\n }\r\n } else {\r\n // Standard orchestration (non-intelligent)\r\n this.chatService.ask(cfg.apiUrl, cfg.token, text).subscribe({\r\n next: (response) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: response.data?.response || 'Sin respuesta',\r\n sender: 'bot',\r\n timestamp: new Date(),\r\n traceData: {\r\n traceId: response.traceId,\r\n responseTime: response.data?.processingTime,\r\n appliedRules: response.data?.appliedRules,\r\n decisions: response.data?.decisions\r\n }\r\n }]);\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n },\r\n error: (error) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n this.handleError(error);\r\n }\r\n });\r\n }\r\n }\r\n\r\n clearChat(): void {\r\n this.messages.set([]);\r\n this.selectedTrace.set(null);\r\n this.authError.set(null);\r\n this.clearSession();\r\n }\r\n\r\n showTrace(msg: ChatMessage): void {\r\n this.selectedTrace.set(msg.traceData);\r\n }\r\n\r\n closeTrace(): void {\r\n this.selectedTrace.set(null);\r\n }\r\n\r\n // ─── Link Modal ────────────────────────────────\r\n openLinkModal(url: string): void {\r\n this.modalLoading.set(true);\r\n this.showHomeBtn.set(false);\r\n this.modalReadyForNav = false;\r\n clearTimeout(this.navReadyTimer);\r\n this.originalModalUrl = url;\r\n this.modalUrl.set(url);\r\n }\r\n\r\n closeLinkModal(): void {\r\n this.modalUrl.set(null);\r\n this.modalLoading.set(false);\r\n this.showHomeBtn.set(false);\r\n this.modalReadyForNav = false;\r\n clearTimeout(this.navReadyTimer);\r\n this.originalModalUrl = '';\r\n }\r\n\r\n onIframeLoaded(): void {\r\n this.modalLoading.set(false);\r\n if (this.modalReadyForNav) {\r\n // A load AFTER the initial page settled = real navigation\r\n this.showHomeBtn.set(true);\r\n } else {\r\n // Initial page load (may fire multiple times for SPAs/redirects)\r\n // Wait 1s of stability before treating next loads as navigation\r\n clearTimeout(this.navReadyTimer);\r\n this.navReadyTimer = setTimeout(() => { this.modalReadyForNav = true; }, 1000);\r\n }\r\n }\r\n\r\n iframeGoHome(): void {\r\n const iframe = this.hostEl.nativeElement.querySelector('.iq-link-iframe') as HTMLIFrameElement;\r\n if (iframe && this.originalModalUrl) {\r\n this.modalLoading.set(true);\r\n this.showHomeBtn.set(false);\r\n this.modalReadyForNav = false;\r\n clearTimeout(this.navReadyTimer);\r\n iframe.src = this.originalModalUrl;\r\n }\r\n }\r\n\r\n /** Intercept clicks on <a> and <img> tags inside rendered markdown */\r\n onMessageClick(event: MouseEvent): void {\r\n const target = event.target as HTMLElement;\r\n\r\n // Clicking an image opens it full-size in the modal\r\n if (target.tagName === 'IMG') {\r\n const src = (target as HTMLImageElement).src;\r\n if (src) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n this.openLinkModal(src);\r\n return;\r\n }\r\n }\r\n\r\n const anchor = target.closest('a') as HTMLAnchorElement | null;\r\n if (anchor && anchor.href) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n this.openLinkModal(anchor.href);\r\n }\r\n }\r\n\r\n formatTime(date: Date): string {\r\n return date.toLocaleTimeString('es-CL', { hour: '2-digit', minute: '2-digit' });\r\n }\r\n\r\n renderMarkdown(text: string): SafeHtml {\r\n if (!text) return '';\r\n try {\r\n let preprocessed = this.preprocessMarkdownTable(text);\r\n // Encode spaces in markdown image & link URLs:  and [text](url)\r\n preprocessed = preprocessed.replace(\r\n /(!?\\[[^\\]]*\\])\\(([^)]+)\\)/g,\r\n (_match: string, bracket: string, url: string) => `${bracket}(${url.replace(/ /g, '%20')})`\r\n );\r\n let html = marked.parse(preprocessed, { breaks: true }) as string;\r\n // Inject inline styles + onerror on <img> to force small thumbnails & hide broken ones\r\n const imgStyle = `style=\"max-height:48px;max-width:100px;object-fit:contain;border-radius:6px;cursor:pointer;display:inline-block;vertical-align:middle;margin:2px 4px;border:1px solid rgba(255,255,255,0.15);box-shadow:0 1px 3px rgba(0,0,0,0.2);\"`;\r\n html = html.replace(/<img /g, `<img ${imgStyle} onerror=\"this.style.display='none'\" `);\r\n return this.sanitizer.bypassSecurityTrustHtml(html);\r\n } catch {\r\n return text;\r\n }\r\n }\r\n\r\n /**\r\n * Pre-process text to ensure pipe-delimited tables render as HTML tables.\r\n *\r\n * The API often returns header + separator + data on ONE line, e.g.:\r\n * \"| Col1 | Col2 | |---|---| | Val1 | Val2 |\"\r\n *\r\n * Step 1: Find the dash-separator pattern (|---|---|) and break the line\r\n * around it so each part (header / separator / data rows) is its\r\n * own line.\r\n * Step 2: Line-by-line cleanup — ensure a blank line exists before the\r\n * first pipe-row and inject a separator if one is still missing.\r\n */\r\n private preprocessMarkdownTable(text: string): string {\r\n // ── Step 1: Break inline separator onto its own line ───────────\r\n // Pattern: the separator row consists only of |, -, :, and spaces.\r\n // We insert \\n before and after it.\r\n text = text.replace(\r\n /\\s*(\\|(?:\\s*:?-{2,}:?\\s*\\|){2,})\\s*/g,\r\n '\\n$1\\n'\r\n );\r\n // Clean up excess blank lines created by step 1\r\n text = text.replace(/\\n{3,}/g, '\\n\\n');\r\n\r\n // ── Step 2: Line-by-line processing ───────────────────────────\r\n const lines = text.split('\\n');\r\n const result: string[] = [];\r\n let inTable = false;\r\n\r\n const isPipeLine = (l: string) => {\r\n const t = l.trim();\r\n return t.startsWith('|') && t.split('|').length > 3;\r\n };\r\n const isSepLine = (l: string) =>\r\n /^\\|(?:\\s*:?-{2,}:?\\s*\\|){2,}\\s*$/.test(l.trim());\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n const line = lines[i];\r\n const trimmed = line.trim();\r\n\r\n if (isPipeLine(trimmed) && !isSepLine(trimmed)) {\r\n if (!inTable) {\r\n inTable = true;\r\n // Insert blank line before table if preceded by non-empty text\r\n if (result.length > 0 && result[result.length - 1].trim() !== '') {\r\n result.push('');\r\n }\r\n result.push(line);\r\n // Inject separator if the next line isn't one\r\n const next = (i + 1 < lines.length) ? lines[i + 1] : '';\r\n if (!isSepLine(next)) {\r\n const cols = trimmed.split('|').filter(c => c.trim() !== '').length;\r\n result.push('| ' + Array(cols).fill('---').join(' | ') + ' |');\r\n }\r\n } else {\r\n result.push(line); // data row\r\n }\r\n } else if (isSepLine(trimmed)) {\r\n if (!inTable) inTable = true; // edge-case: separator before header\r\n result.push(line);\r\n } else {\r\n inTable = false;\r\n result.push(line);\r\n }\r\n }\r\n\r\n return result.join('\\n');\r\n }\r\n\r\n // ─── Private ───────────────────────────────────────────\r\n\r\n private handleError(error: any): void {\r\n const status = error?.status;\r\n if (status === 401 || status === 403) {\r\n const msg = status === 401 ? 'Token inválido o expirado' : 'Sin permisos para este sistema';\r\n this.authError.set(`🔒 ${msg}`);\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: `⚠️ ${msg}. Verifica el token y el systemId configurados.`,\r\n sender: 'bot',\r\n timestamp: new Date()\r\n }]);\r\n } else {\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: `Error: ${error.error?.message || error.error?.error || 'No se pudo procesar la consulta'}`,\r\n sender: 'bot',\r\n timestamp: new Date()\r\n }]);\r\n }\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n }\r\n\r\n private stopPipelineSteps(): void {\r\n this.pipelineStep = '';\r\n }\r\n\r\n private scrollToBottom(): void {\r\n if (this.chatContainer) {\r\n const el = this.chatContainer.nativeElement;\r\n el.scrollTop = el.scrollHeight;\r\n }\r\n }\r\n\r\n // ─── Session Persistence ──────────────────────────\r\n\r\n private buildSessionKey(): string {\r\n const cfg = this.resolvedConfig();\r\n if (!cfg.token || !cfg.systemId) return '';\r\n // Simple hash-like key from systemId + first 8 chars of token\r\n const tokenPrefix = cfg.token.substring(0, 8);\r\n return `${this.STORAGE_PREFIX}${cfg.systemId}_${tokenPrefix}`;\r\n }\r\n\r\n private saveSession(): void {\r\n if (!this.sessionKey) return;\r\n try {\r\n const data = this.messages().map(m => ({\r\n id: m.id,\r\n text: m.text,\r\n sender: m.sender,\r\n timestamp: m.timestamp,\r\n traceData: m.traceData\r\n }));\r\n localStorage.setItem(this.sessionKey, JSON.stringify(data));\r\n } catch { /* ignore quota errors */ }\r\n }\r\n\r\n private loadSession(): void {\r\n if (!this.sessionKey) return;\r\n try {\r\n const raw = localStorage.getItem(this.sessionKey);\r\n if (!raw) { this.messages.set([]); return; }\r\n const data: any[] = JSON.parse(raw);\r\n const msgs: ChatMessage[] = data.map(m => ({\r\n ...m,\r\n timestamp: new Date(m.timestamp)\r\n }));\r\n this.messages.set(msgs);\r\n this.messageId = msgs.length > 0 ? Math.max(...msgs.map(m => m.id)) + 1 : 0;\r\n this.shouldScroll = true;\r\n } catch { this.messages.set([]); }\r\n }\r\n\r\n private clearSession(): void {\r\n if (this.sessionKey) {\r\n try { localStorage.removeItem(this.sessionKey); } catch {}\r\n }\r\n }\r\n\r\n /** Called when another tab modifies localStorage */\r\n private onStorageChange(e: StorageEvent): void {\r\n if (!this.sessionKey || e.key !== this.sessionKey) return;\r\n if (e.newValue === null) {\r\n // Session was cleared in another tab\r\n this.messages.set([]);\r\n } else {\r\n this.loadSession();\r\n }\r\n this.shouldScroll = true;\r\n }\r\n}\r\n","/*\r\n * Public API Surface of maquito-chat-plugin\r\n */\r\n\r\nexport type { IntelligentChatConfig, ChatMessage, PluginTheme } from './lib/intelligent-chat.models';\r\nexport { IntelligentChatService } from './lib/intelligent-chat.service';\r\nexport { IntelligentChatPluginComponent } from './lib/intelligent-chat-plugin.component';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
2
|
import * as _angular_core from '@angular/core';
|
|
3
3
|
import { AfterViewChecked, OnChanges, OnInit, OnDestroy, SimpleChanges } from '@angular/core';
|
|
4
|
-
import { SafeHtml } from '@angular/platform-browser';
|
|
4
|
+
import { SafeHtml, SafeResourceUrl } from '@angular/platform-browser';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Maquito Chat Plugin — Configuration Model
|
|
@@ -125,12 +125,20 @@ declare class IntelligentChatPluginComponent implements AfterViewChecked, OnChan
|
|
|
125
125
|
private chatContainer;
|
|
126
126
|
config: IntelligentChatConfig;
|
|
127
127
|
private chatService;
|
|
128
|
+
private hostEl;
|
|
128
129
|
isOpen: _angular_core.WritableSignal<boolean>;
|
|
129
130
|
isExpanded: _angular_core.WritableSignal<boolean>;
|
|
130
131
|
messages: _angular_core.WritableSignal<ChatMessage[]>;
|
|
131
132
|
isLoading: _angular_core.WritableSignal<boolean>;
|
|
132
133
|
selectedTrace: _angular_core.WritableSignal<any>;
|
|
133
134
|
authError: _angular_core.WritableSignal<string>;
|
|
135
|
+
modalUrl: _angular_core.WritableSignal<string>;
|
|
136
|
+
isModalImage: _angular_core.Signal<boolean>;
|
|
137
|
+
modalLoading: _angular_core.WritableSignal<boolean>;
|
|
138
|
+
showHomeBtn: _angular_core.WritableSignal<boolean>;
|
|
139
|
+
private originalModalUrl;
|
|
140
|
+
private modalReadyForNav;
|
|
141
|
+
private navReadyTimer;
|
|
134
142
|
inputText: string;
|
|
135
143
|
pipelineStep: string;
|
|
136
144
|
private messageId;
|
|
@@ -145,18 +153,28 @@ declare class IntelligentChatPluginComponent implements AfterViewChecked, OnChan
|
|
|
145
153
|
themeStyles: _angular_core.Signal<Record<string, string>>;
|
|
146
154
|
/** Sanitised SVG HTML for bubble */
|
|
147
155
|
sanitizedBubbleSvg: _angular_core.Signal<SafeHtml>;
|
|
156
|
+
/** Sanitised URL for the link modal iframe */
|
|
157
|
+
sanitizedModalUrl: _angular_core.Signal<SafeResourceUrl>;
|
|
148
158
|
ngOnInit(): void;
|
|
149
159
|
ngOnDestroy(): void;
|
|
150
160
|
ngOnChanges(changes: SimpleChanges): void;
|
|
151
161
|
ngAfterViewChecked(): void;
|
|
152
162
|
toggleChat(): void;
|
|
153
163
|
toggleExpand(): void;
|
|
164
|
+
/** Lock/unlock the host page scroll to prevent its scrollbar from overlapping ours */
|
|
165
|
+
private setHostScrollLock;
|
|
154
166
|
sendMessage(): void;
|
|
155
167
|
clearChat(): void;
|
|
156
168
|
showTrace(msg: ChatMessage): void;
|
|
157
169
|
closeTrace(): void;
|
|
170
|
+
openLinkModal(url: string): void;
|
|
171
|
+
closeLinkModal(): void;
|
|
172
|
+
onIframeLoaded(): void;
|
|
173
|
+
iframeGoHome(): void;
|
|
174
|
+
/** Intercept clicks on <a> and <img> tags inside rendered markdown */
|
|
175
|
+
onMessageClick(event: MouseEvent): void;
|
|
158
176
|
formatTime(date: Date): string;
|
|
159
|
-
renderMarkdown(text: string):
|
|
177
|
+
renderMarkdown(text: string): SafeHtml;
|
|
160
178
|
/**
|
|
161
179
|
* Pre-process text to ensure pipe-delimited tables render as HTML tables.
|
|
162
180
|
*
|