@kodaris/krubble-app-components 1.0.86 → 1.0.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chatbot.d.ts.map +1 -1
- package/dist/chatbot.js +87 -32
- package/dist/chatbot.js.map +1 -1
- package/dist/krubble-app.bundled.js +87 -32
- package/dist/krubble-app.bundled.js.map +1 -1
- package/dist/krubble-app.bundled.min.js +41 -33
- package/dist/krubble-app.bundled.min.js.map +1 -1
- package/dist/krubble-app.umd.js +87 -32
- package/dist/krubble-app.umd.js.map +1 -1
- package/dist/krubble-app.umd.min.js +36 -28
- package/dist/krubble-app.umd.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -5859,16 +5859,55 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
5859
5859
|
// --- Lifecycle ---
|
|
5860
5860
|
connectedCallback() {
|
|
5861
5861
|
super.connectedCallback();
|
|
5862
|
-
// Default to loading
|
|
5863
|
-
//
|
|
5864
|
-
//
|
|
5865
|
-
// they
|
|
5862
|
+
// Default to loading a conversation's messages when the consumer hasn't
|
|
5863
|
+
// provided their own `load`. With `conversationId` set we rebuild that
|
|
5864
|
+
// conversation; with none set we resume the caller's most recent one via
|
|
5865
|
+
// `/conversation/last` (KRHttp rejects its 404 when they have none yet →
|
|
5866
|
+
// stays null → empty chat) and pin it so this session continues it. Rows
|
|
5867
|
+
// already match KRChatbotMessage ({ type, content }); we only parse each row's
|
|
5868
|
+
// `conversationFileIDs` (a JSON array string of ids) into `conversationFiles`.
|
|
5866
5869
|
if (!this.load) {
|
|
5867
|
-
this.load = () =>
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5870
|
+
this.load = () => {
|
|
5871
|
+
let resolve = Promise.resolve();
|
|
5872
|
+
if (this.conversationId == null) {
|
|
5873
|
+
resolve = KRHttp.fetch({ url: '/api/system/conversation/last' })
|
|
5874
|
+
.then((r) => r.json())
|
|
5875
|
+
.then((res) => {
|
|
5876
|
+
this.conversationId = res?.data?.conversationID ?? null;
|
|
5877
|
+
})
|
|
5878
|
+
.catch(() => { });
|
|
5879
|
+
}
|
|
5880
|
+
return resolve
|
|
5881
|
+
.then(() => {
|
|
5882
|
+
if (this.conversationId == null) {
|
|
5883
|
+
return { data: [] };
|
|
5884
|
+
}
|
|
5885
|
+
return KRHttp.fetch({ url: `/api/system/conversation/${this.conversationId}/messages` }).then((r) => r.json());
|
|
5886
|
+
})
|
|
5887
|
+
.then((res) => Promise.all((res?.data || []).map((msg) => {
|
|
5888
|
+
// Resolve this message's `conversationFileIDs` (a JSON array string of
|
|
5889
|
+
// ids) into full file objects — each fetch response IS the
|
|
5890
|
+
// KRChatbotConversationFile (id + niceName + mimeType), and niceName
|
|
5891
|
+
// drives the previewer's file-type detection. A failed fetch drops
|
|
5892
|
+
// that file rather than rendering a broken thumbnail.
|
|
5893
|
+
let ids = [];
|
|
5894
|
+
try {
|
|
5895
|
+
ids = JSON.parse(msg.conversationFileIDs || '[]');
|
|
5896
|
+
}
|
|
5897
|
+
catch { /* no/invalid attachments — leave empty */ }
|
|
5898
|
+
if (!ids.length) {
|
|
5899
|
+
return Promise.resolve(msg);
|
|
5900
|
+
}
|
|
5901
|
+
return Promise.all(ids.map((id) => KRHttp.fetch({ url: `/api/system/conversationFile/${id}` })
|
|
5902
|
+
.then((r) => r.json())
|
|
5903
|
+
.then((meta) => meta?.data)
|
|
5904
|
+
.catch(() => null)))
|
|
5905
|
+
.then((files) => {
|
|
5906
|
+
msg.conversationFiles = files.filter((f) => f != null);
|
|
5907
|
+
return msg;
|
|
5908
|
+
});
|
|
5909
|
+
})));
|
|
5910
|
+
};
|
|
5872
5911
|
}
|
|
5873
5912
|
this.load().then((messages) => {
|
|
5874
5913
|
if (messages && messages.length) {
|
|
@@ -6662,10 +6701,18 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6662
6701
|
}
|
|
6663
6702
|
/** Open the shared full-screen previewer for a message image. */
|
|
6664
6703
|
_openImage(img) {
|
|
6665
|
-
|
|
6666
|
-
|
|
6704
|
+
// Prefix the configured backend base URL — a raw fetch of a relative path
|
|
6705
|
+
// would hit the page origin (e.g. the dev server), not the backend.
|
|
6706
|
+
const preview = KRFilePreview.open({
|
|
6707
|
+
src: `${KRHttp.getBaseUrl()}/api/system/conversationFile/${img.conversationFileID}/view`,
|
|
6667
6708
|
name: img.niceName || 'image',
|
|
6668
6709
|
});
|
|
6710
|
+
// The previewer's download button only fires a `download` event — the
|
|
6711
|
+
// consumer performs the actual download. Hit the view endpoint with
|
|
6712
|
+
// `?download=true` (Content-Disposition: attachment) in a new tab.
|
|
6713
|
+
preview.addEventListener('download', () => {
|
|
6714
|
+
window.open(`${KRHttp.getBaseUrl()}/api/system/conversationFile/${img.conversationFileID}/view?download=true`, '_blank');
|
|
6715
|
+
});
|
|
6669
6716
|
}
|
|
6670
6717
|
/** Whether the send button is active: needs text or at least one image. */
|
|
6671
6718
|
_canSend() {
|
|
@@ -7514,7 +7561,7 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
7514
7561
|
@click=${() => this._openImage(img)}
|
|
7515
7562
|
>
|
|
7516
7563
|
<img
|
|
7517
|
-
src="/api/system/conversationFile/${img.conversationFileID}/view"
|
|
7564
|
+
src="${KRHttp.getBaseUrl()}/api/system/conversationFile/${img.conversationFileID}/view"
|
|
7518
7565
|
alt=${img.niceName || ''}
|
|
7519
7566
|
/>
|
|
7520
7567
|
</button>
|
|
@@ -7538,7 +7585,7 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
7538
7585
|
${msg.content ? b `
|
|
7539
7586
|
<button
|
|
7540
7587
|
class="message-copy"
|
|
7541
|
-
title
|
|
7588
|
+
title=${this._copiedIndex === index ? 'Copied' : 'Copy'}
|
|
7542
7589
|
@click=${() => this._handleCopyMessage(msg.content, index)}
|
|
7543
7590
|
>
|
|
7544
7591
|
${this._copiedIndex === index ? b `
|
|
@@ -7552,7 +7599,6 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
7552
7599
|
>
|
|
7553
7600
|
<path d="M20 6 9 17l-5-5" />
|
|
7554
7601
|
</svg>
|
|
7555
|
-
Copied
|
|
7556
7602
|
` : b `
|
|
7557
7603
|
<svg
|
|
7558
7604
|
viewBox="0 0 24 24"
|
|
@@ -7571,7 +7617,6 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
7571
7617
|
/>
|
|
7572
7618
|
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
|
|
7573
7619
|
</svg>
|
|
7574
|
-
Copy
|
|
7575
7620
|
`}
|
|
7576
7621
|
</button>
|
|
7577
7622
|
` : A}
|
|
@@ -7938,7 +7983,7 @@ KRChatbot.styles = i$6 `
|
|
|
7938
7983
|
flex: 1;
|
|
7939
7984
|
display: flex;
|
|
7940
7985
|
flex-direction: column;
|
|
7941
|
-
gap:
|
|
7986
|
+
gap: 36px;
|
|
7942
7987
|
padding: 32px;
|
|
7943
7988
|
width: 100%;
|
|
7944
7989
|
max-width: 768px;
|
|
@@ -7967,6 +8012,17 @@ KRChatbot.styles = i$6 `
|
|
|
7967
8012
|
flex-direction: column;
|
|
7968
8013
|
max-width: 100%;
|
|
7969
8014
|
animation: chatbot-msg-in 0.3s ease-out;
|
|
8015
|
+
/* Reserve room for the copy button INSIDE the message box (so the button is
|
|
8016
|
+
part of the message's hover region — no dead zone to cross), then cancel
|
|
8017
|
+
that space for layout so message spacing is unchanged. */
|
|
8018
|
+
padding-bottom: 30px;
|
|
8019
|
+
margin-bottom: -30px;
|
|
8020
|
+
}
|
|
8021
|
+
|
|
8022
|
+
/* The reserved padding overhangs into the next message; lift the hovered one
|
|
8023
|
+
so its copy button isn't covered by (or stealing hover from) the sibling. */
|
|
8024
|
+
.message:hover {
|
|
8025
|
+
z-index: 1;
|
|
7970
8026
|
}
|
|
7971
8027
|
|
|
7972
8028
|
@keyframes chatbot-msg-in {
|
|
@@ -8015,43 +8071,41 @@ KRChatbot.styles = i$6 `
|
|
|
8015
8071
|
color: #b45309;
|
|
8016
8072
|
}
|
|
8017
8073
|
|
|
8018
|
-
/* Per-message copy button.
|
|
8019
|
-
|
|
8020
|
-
|
|
8074
|
+
/* Per-message copy button. Sits in the message's reserved bottom padding —
|
|
8075
|
+
inside the hover box, so moving the cursor down onto it never leaves the
|
|
8076
|
+
message. Height is reserved (via the message padding) so spacing doesn't
|
|
8077
|
+
jump; only opacity toggles on hover. */
|
|
8021
8078
|
.message-copy {
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
|
|
8079
|
+
position: absolute;
|
|
8080
|
+
bottom: 0;
|
|
8081
|
+
left: 0;
|
|
8025
8082
|
display: inline-flex;
|
|
8026
8083
|
align-items: center;
|
|
8027
|
-
|
|
8028
|
-
|
|
8029
|
-
|
|
8084
|
+
justify-content: center;
|
|
8085
|
+
width: 26px;
|
|
8086
|
+
height: 26px;
|
|
8087
|
+
padding: 0;
|
|
8030
8088
|
background: none;
|
|
8031
8089
|
border: none;
|
|
8032
8090
|
border-radius: 6px;
|
|
8033
|
-
|
|
8034
|
-
font-size: 12px;
|
|
8035
|
-
color: #64668b;
|
|
8091
|
+
color: #000000;
|
|
8036
8092
|
cursor: pointer;
|
|
8037
8093
|
opacity: 0;
|
|
8038
|
-
pointer-events: none;
|
|
8039
8094
|
transition: opacity 0.15s, background-color 0.15s, color 0.15s;
|
|
8040
8095
|
}
|
|
8041
8096
|
|
|
8042
8097
|
.message--user .message-copy {
|
|
8043
|
-
|
|
8098
|
+
left: auto;
|
|
8099
|
+
right: 0;
|
|
8044
8100
|
}
|
|
8045
8101
|
|
|
8046
8102
|
.message:hover .message-copy,
|
|
8047
8103
|
.message-copy:focus-visible {
|
|
8048
8104
|
opacity: 1;
|
|
8049
|
-
pointer-events: auto;
|
|
8050
8105
|
}
|
|
8051
8106
|
|
|
8052
8107
|
.message-copy:hover {
|
|
8053
8108
|
background: rgba(0, 0, 0, 0.06);
|
|
8054
|
-
color: #1a1a2e;
|
|
8055
8109
|
}
|
|
8056
8110
|
|
|
8057
8111
|
.message-copy svg {
|
|
@@ -8625,6 +8679,7 @@ KRChatbot.styles = i$6 `
|
|
|
8625
8679
|
|
|
8626
8680
|
.message--user .attachments {
|
|
8627
8681
|
justify-content: flex-end;
|
|
8682
|
+
margin-bottom: 24px;
|
|
8628
8683
|
}
|
|
8629
8684
|
|
|
8630
8685
|
.attachment {
|