@kodaris/krubble-app-components 1.0.104 → 1.0.105

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.
@@ -5533,15 +5533,23 @@
5533
5533
  };
5534
5534
  /** Image extensions the chatbot renders as thumbnails (used when MIME is absent). */
5535
5535
  const IMAGE_EXTENSIONS = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
5536
+ /**
5537
+ * Video extensions the picker accepts. The AI cannot watch video — these upload
5538
+ * and store for playback and tool use only, and the backend tells the model so.
5539
+ * Matches what kr-file-preview can play back.
5540
+ */
5541
+ const VIDEO_EXTENSIONS = ['mp4', 'webm', 'ogg', 'mov'];
5536
5542
  /**
5537
5543
  * File extensions the picker accepts. Mirrors what the backend can read: the
5538
5544
  * document/spreadsheet family Bedrock ingests, the plain-text family read as
5539
- * fallback, and the image formats. This is a UX convenience — the backend
5545
+ * fallback, and the image formats. Videos are accepted for upload/storage even
5546
+ * though the model can't read them. This is a UX convenience — the backend
5540
5547
  * accepts anything and just tells the model when a type can't be read.
5541
5548
  */
5542
5549
  const ACCEPTED_FILE_EXTENSIONS = [
5543
5550
  'pdf', 'doc', 'docx', 'xls', 'xlsx', 'csv', 'html', 'md', 'txt', 'json', 'xml',
5544
5551
  ...IMAGE_EXTENSIONS,
5552
+ ...VIDEO_EXTENSIONS,
5545
5553
  ];
5546
5554
  /**
5547
5555
  * AI chatbot component with SSE streaming.
@@ -6855,8 +6863,9 @@
6855
6863
  return;
6856
6864
  }
6857
6865
  files.forEach((file) => {
6858
- // Only images get a local preview thumbnail; documents render an icon.
6859
- // Prefer the File's MIME, falling back to the extension when it's absent.
6866
+ // Only images get a local preview thumbnail; documents (and videos, which are
6867
+ // tiles too) render an icon. Prefer the File's MIME, falling back to the
6868
+ // extension when it's absent.
6860
6869
  let previewUrl;
6861
6870
  if (file.type.startsWith('image/') || IMAGE_EXTENSIONS.includes(this._getFileExtension(file.name))) {
6862
6871
  previewUrl = URL.createObjectURL(file);
@@ -6887,22 +6896,25 @@
6887
6896
  });
6888
6897
  this._pendingConversationFiles = [];
6889
6898
  }
6890
- /** Open the shared full-screen previewer for a message image. */
6891
- _handleImageOpen(img) {
6899
+ /** Open the shared full-screen previewer for a message attachment (image or video). */
6900
+ _handleFileOpen(file) {
6892
6901
  // Use the local preview if the upload hasn't finished yet; otherwise the
6893
6902
  // backend view URL (prefixed with the base URL — a raw fetch of a relative
6894
6903
  // path would hit the page origin, e.g. the dev server, not the backend).
6895
- const src = img.previewUrl
6896
- || `${krubbleHttp.Http.getBaseUrl()}/api/system/conversationFile/${img.conversationFileID}/view`;
6904
+ // The previewer picks image vs video playback off the name's extension, so
6905
+ // niceName has to carry it — hence the generic fallback keeps no extension
6906
+ // only when there's no name at all.
6907
+ const src = file.previewUrl
6908
+ || `${krubbleHttp.Http.getBaseUrl()}/api/system/conversationFile/${file.conversationFileID}/view`;
6897
6909
  const preview = krubbleComponents.FilePreview.open({
6898
6910
  src,
6899
- name: img.niceName || 'image',
6911
+ name: file.niceName || 'file',
6900
6912
  });
6901
6913
  // The previewer's download button only fires a `download` event — the
6902
6914
  // consumer performs the actual download. Hit the view endpoint with
6903
6915
  // `?download=true` (Content-Disposition: attachment) in a new tab.
6904
6916
  preview.addEventListener('download', () => {
6905
- window.open(`${krubbleHttp.Http.getBaseUrl()}/api/system/conversationFile/${img.conversationFileID}/view?download=true`, '_blank');
6917
+ window.open(`${krubbleHttp.Http.getBaseUrl()}/api/system/conversationFile/${file.conversationFileID}/view?download=true`, '_blank');
6906
6918
  });
6907
6919
  }
6908
6920
  _handleSubmit() {
@@ -7837,15 +7849,18 @@
7837
7849
  if (file.mimeType) {
7838
7850
  isImage = file.mimeType.startsWith('image/');
7839
7851
  }
7840
- // Images open in the previewer; documents just show a tile
7841
- // (the previewer is image-only).
7852
+ // An image shows its thumbnail; everything else shows a
7853
+ // file-type tile. Both open the previewer on click — it renders
7854
+ // images, video, PDFs, and text inline, and shows a download
7855
+ // tile for the rest (Office formats), so a click always does
7856
+ // something useful.
7842
7857
  if (isImage) {
7843
7858
  return b `
7844
7859
  <button
7845
7860
  class="attachment"
7846
7861
  type="button"
7847
7862
  title=${file.niceName || 'View image'}
7848
- @click=${() => this._handleImageOpen(file)}
7863
+ @click=${() => this._handleFileOpen(file)}
7849
7864
  >
7850
7865
  <img
7851
7866
  src=${file.previewUrl || `${krubbleHttp.Http.getBaseUrl()}/api/system/conversationFile/${file.conversationFileID}/view`}
@@ -7855,13 +7870,15 @@
7855
7870
  `;
7856
7871
  }
7857
7872
  return b `
7858
- <div
7859
- class="attachment attachment--doc"
7873
+ <button
7874
+ class="attachment attachment--doc attachment--openable"
7875
+ type="button"
7860
7876
  title=${fileName}
7877
+ @click=${() => this._handleFileOpen(file)}
7861
7878
  >
7862
7879
  <span class="attachment__type">${this._getFileExtension(fileName) || 'File'}</span>
7863
7880
  <span class="attachment__name">${fileName}</span>
7864
- </div>
7881
+ </button>
7865
7882
  `;
7866
7883
  })}
7867
7884
  </div>
@@ -9133,15 +9150,22 @@
9133
9150
  display: block;
9134
9151
  }
9135
9152
 
9136
- /* Non-image attachment in a sent message — file-type label above the filename
9137
- (the previewer is image-only, so this isn't clickable). */
9153
+ /* Non-image attachment in a sent message — file-type label above the filename. */
9138
9154
  .attachment--doc {
9139
9155
  display: flex;
9140
9156
  flex-direction: column;
9141
9157
  padding: 16px 14px;
9142
9158
  box-sizing: border-box;
9143
9159
  text-align: left;
9144
- cursor: default;
9160
+ }
9161
+
9162
+ /* Opens the previewer on click — same affordance as the composer's doc chip. */
9163
+ .attachment--openable {
9164
+ cursor: pointer;
9165
+ }
9166
+
9167
+ .attachment--openable:hover {
9168
+ background: #dfdddd;
9145
9169
  }
9146
9170
 
9147
9171
  .attachment__type {