@kodaris/krubble-app-components 1.0.87 → 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 +79 -40
- package/dist/chatbot.js.map +1 -1
- package/dist/krubble-app.bundled.js +79 -40
- package/dist/krubble-app.bundled.js.map +1 -1
- package/dist/krubble-app.bundled.min.js +39 -31
- package/dist/krubble-app.bundled.min.js.map +1 -1
- package/dist/krubble-app.umd.js +79 -40
- 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,31 +5859,54 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
5859
5859
|
// --- Lifecycle ---
|
|
5860
5860
|
connectedCallback() {
|
|
5861
5861
|
super.connectedCallback();
|
|
5862
|
-
// Default to loading a
|
|
5863
|
-
//
|
|
5864
|
-
// conversation
|
|
5865
|
-
//
|
|
5866
|
-
//
|
|
5867
|
-
//
|
|
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`.
|
|
5868
5869
|
if (!this.load) {
|
|
5869
5870
|
this.load = () => {
|
|
5871
|
+
let resolve = Promise.resolve();
|
|
5870
5872
|
if (this.conversationId == null) {
|
|
5871
|
-
|
|
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(() => { });
|
|
5872
5879
|
}
|
|
5873
|
-
return
|
|
5874
|
-
|
|
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());
|
|
5875
5886
|
})
|
|
5876
|
-
.then((
|
|
5877
|
-
|
|
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 = [];
|
|
5878
5894
|
try {
|
|
5879
|
-
|
|
5880
|
-
if (ids.length) {
|
|
5881
|
-
msg.conversationFiles = ids.map((id) => ({ conversationFileID: id }));
|
|
5882
|
-
}
|
|
5895
|
+
ids = JSON.parse(msg.conversationFileIDs || '[]');
|
|
5883
5896
|
}
|
|
5884
5897
|
catch { /* no/invalid attachments — leave empty */ }
|
|
5885
|
-
|
|
5886
|
-
|
|
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
|
+
})));
|
|
5887
5910
|
};
|
|
5888
5911
|
}
|
|
5889
5912
|
this.load().then((messages) => {
|
|
@@ -6678,10 +6701,18 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6678
6701
|
}
|
|
6679
6702
|
/** Open the shared full-screen previewer for a message image. */
|
|
6680
6703
|
_openImage(img) {
|
|
6681
|
-
|
|
6682
|
-
|
|
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`,
|
|
6683
6708
|
name: img.niceName || 'image',
|
|
6684
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
|
+
});
|
|
6685
6716
|
}
|
|
6686
6717
|
/** Whether the send button is active: needs text or at least one image. */
|
|
6687
6718
|
_canSend() {
|
|
@@ -7530,7 +7561,7 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
7530
7561
|
@click=${() => this._openImage(img)}
|
|
7531
7562
|
>
|
|
7532
7563
|
<img
|
|
7533
|
-
src="/api/system/conversationFile/${img.conversationFileID}/view"
|
|
7564
|
+
src="${KRHttp.getBaseUrl()}/api/system/conversationFile/${img.conversationFileID}/view"
|
|
7534
7565
|
alt=${img.niceName || ''}
|
|
7535
7566
|
/>
|
|
7536
7567
|
</button>
|
|
@@ -7554,7 +7585,7 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
7554
7585
|
${msg.content ? b `
|
|
7555
7586
|
<button
|
|
7556
7587
|
class="message-copy"
|
|
7557
|
-
title
|
|
7588
|
+
title=${this._copiedIndex === index ? 'Copied' : 'Copy'}
|
|
7558
7589
|
@click=${() => this._handleCopyMessage(msg.content, index)}
|
|
7559
7590
|
>
|
|
7560
7591
|
${this._copiedIndex === index ? b `
|
|
@@ -7568,7 +7599,6 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
7568
7599
|
>
|
|
7569
7600
|
<path d="M20 6 9 17l-5-5" />
|
|
7570
7601
|
</svg>
|
|
7571
|
-
Copied
|
|
7572
7602
|
` : b `
|
|
7573
7603
|
<svg
|
|
7574
7604
|
viewBox="0 0 24 24"
|
|
@@ -7587,7 +7617,6 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
7587
7617
|
/>
|
|
7588
7618
|
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
|
|
7589
7619
|
</svg>
|
|
7590
|
-
Copy
|
|
7591
7620
|
`}
|
|
7592
7621
|
</button>
|
|
7593
7622
|
` : A}
|
|
@@ -7954,7 +7983,7 @@ KRChatbot.styles = i$6 `
|
|
|
7954
7983
|
flex: 1;
|
|
7955
7984
|
display: flex;
|
|
7956
7985
|
flex-direction: column;
|
|
7957
|
-
gap:
|
|
7986
|
+
gap: 36px;
|
|
7958
7987
|
padding: 32px;
|
|
7959
7988
|
width: 100%;
|
|
7960
7989
|
max-width: 768px;
|
|
@@ -7983,6 +8012,17 @@ KRChatbot.styles = i$6 `
|
|
|
7983
8012
|
flex-direction: column;
|
|
7984
8013
|
max-width: 100%;
|
|
7985
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;
|
|
7986
8026
|
}
|
|
7987
8027
|
|
|
7988
8028
|
@keyframes chatbot-msg-in {
|
|
@@ -8031,43 +8071,41 @@ KRChatbot.styles = i$6 `
|
|
|
8031
8071
|
color: #b45309;
|
|
8032
8072
|
}
|
|
8033
8073
|
|
|
8034
|
-
/* Per-message copy button.
|
|
8035
|
-
|
|
8036
|
-
|
|
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. */
|
|
8037
8078
|
.message-copy {
|
|
8038
|
-
|
|
8039
|
-
|
|
8040
|
-
|
|
8079
|
+
position: absolute;
|
|
8080
|
+
bottom: 0;
|
|
8081
|
+
left: 0;
|
|
8041
8082
|
display: inline-flex;
|
|
8042
8083
|
align-items: center;
|
|
8043
|
-
|
|
8044
|
-
|
|
8045
|
-
|
|
8084
|
+
justify-content: center;
|
|
8085
|
+
width: 26px;
|
|
8086
|
+
height: 26px;
|
|
8087
|
+
padding: 0;
|
|
8046
8088
|
background: none;
|
|
8047
8089
|
border: none;
|
|
8048
8090
|
border-radius: 6px;
|
|
8049
|
-
|
|
8050
|
-
font-size: 12px;
|
|
8051
|
-
color: #64668b;
|
|
8091
|
+
color: #000000;
|
|
8052
8092
|
cursor: pointer;
|
|
8053
8093
|
opacity: 0;
|
|
8054
|
-
pointer-events: none;
|
|
8055
8094
|
transition: opacity 0.15s, background-color 0.15s, color 0.15s;
|
|
8056
8095
|
}
|
|
8057
8096
|
|
|
8058
8097
|
.message--user .message-copy {
|
|
8059
|
-
|
|
8098
|
+
left: auto;
|
|
8099
|
+
right: 0;
|
|
8060
8100
|
}
|
|
8061
8101
|
|
|
8062
8102
|
.message:hover .message-copy,
|
|
8063
8103
|
.message-copy:focus-visible {
|
|
8064
8104
|
opacity: 1;
|
|
8065
|
-
pointer-events: auto;
|
|
8066
8105
|
}
|
|
8067
8106
|
|
|
8068
8107
|
.message-copy:hover {
|
|
8069
8108
|
background: rgba(0, 0, 0, 0.06);
|
|
8070
|
-
color: #1a1a2e;
|
|
8071
8109
|
}
|
|
8072
8110
|
|
|
8073
8111
|
.message-copy svg {
|
|
@@ -8641,6 +8679,7 @@ KRChatbot.styles = i$6 `
|
|
|
8641
8679
|
|
|
8642
8680
|
.message--user .attachments {
|
|
8643
8681
|
justify-content: flex-end;
|
|
8682
|
+
margin-bottom: 24px;
|
|
8644
8683
|
}
|
|
8645
8684
|
|
|
8646
8685
|
.attachment {
|