mirror of
https://github.com/open-webui/open-webui
synced 2024-11-25 13:29:53 +00:00
enh: export table as csv
Some checks are pending
Deploy to HuggingFace Spaces / check-secret (push) Waiting to run
Deploy to HuggingFace Spaces / deploy (push) Blocked by required conditions
Create and publish Docker images with specific build args / build-main-image (linux/amd64) (push) Waiting to run
Create and publish Docker images with specific build args / build-main-image (linux/arm64) (push) Waiting to run
Create and publish Docker images with specific build args / build-cuda-image (linux/amd64) (push) Waiting to run
Create and publish Docker images with specific build args / build-cuda-image (linux/arm64) (push) Waiting to run
Create and publish Docker images with specific build args / build-ollama-image (linux/amd64) (push) Waiting to run
Create and publish Docker images with specific build args / build-ollama-image (linux/arm64) (push) Waiting to run
Create and publish Docker images with specific build args / merge-main-images (push) Blocked by required conditions
Create and publish Docker images with specific build args / merge-cuda-images (push) Blocked by required conditions
Create and publish Docker images with specific build args / merge-ollama-images (push) Blocked by required conditions
Python CI / Format Backend (3.11) (push) Waiting to run
Frontend Build / Format & Build Frontend (push) Waiting to run
Frontend Build / Frontend Unit Tests (push) Waiting to run
Integration Test / Run Cypress Integration Tests (push) Waiting to run
Integration Test / Run Migration Tests (push) Waiting to run
Some checks are pending
Deploy to HuggingFace Spaces / check-secret (push) Waiting to run
Deploy to HuggingFace Spaces / deploy (push) Blocked by required conditions
Create and publish Docker images with specific build args / build-main-image (linux/amd64) (push) Waiting to run
Create and publish Docker images with specific build args / build-main-image (linux/arm64) (push) Waiting to run
Create and publish Docker images with specific build args / build-cuda-image (linux/amd64) (push) Waiting to run
Create and publish Docker images with specific build args / build-cuda-image (linux/arm64) (push) Waiting to run
Create and publish Docker images with specific build args / build-ollama-image (linux/amd64) (push) Waiting to run
Create and publish Docker images with specific build args / build-ollama-image (linux/arm64) (push) Waiting to run
Create and publish Docker images with specific build args / merge-main-images (push) Blocked by required conditions
Create and publish Docker images with specific build args / merge-cuda-images (push) Blocked by required conditions
Create and publish Docker images with specific build args / merge-ollama-images (push) Blocked by required conditions
Python CI / Format Backend (3.11) (push) Waiting to run
Frontend Build / Format & Build Frontend (push) Waiting to run
Frontend Build / Frontend Unit Tests (push) Waiting to run
Integration Test / Run Cypress Integration Tests (push) Waiting to run
Integration Test / Run Migration Tests (push) Waiting to run
Co-Authored-By: Muhammad Afzaal <mafzaal@gmail.com>
This commit is contained in:
parent
5ae6d05a53
commit
70498d7bbe
@ -1,6 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import DOMPurify from 'dompurify';
|
import DOMPurify from 'dompurify';
|
||||||
import { createEventDispatcher, onMount } from 'svelte';
|
import { createEventDispatcher, onMount, getContext } from 'svelte';
|
||||||
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
|
import fileSaver from 'file-saver';
|
||||||
|
const { saveAs } = fileSaver;
|
||||||
|
|
||||||
import { marked, type Token } from 'marked';
|
import { marked, type Token } from 'marked';
|
||||||
import { revertSanitizedResponseContent, unescapeHtml } from '$lib/utils';
|
import { revertSanitizedResponseContent, unescapeHtml } from '$lib/utils';
|
||||||
|
|
||||||
@ -10,6 +15,8 @@
|
|||||||
import MarkdownInlineTokens from '$lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte';
|
import MarkdownInlineTokens from '$lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte';
|
||||||
import KatexRenderer from './KatexRenderer.svelte';
|
import KatexRenderer from './KatexRenderer.svelte';
|
||||||
import Collapsible from '$lib/components/common/Collapsible.svelte';
|
import Collapsible from '$lib/components/common/Collapsible.svelte';
|
||||||
|
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||||
|
import ArrowDownTray from '$lib/components/icons/ArrowDownTray.svelte';
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
@ -22,6 +29,31 @@
|
|||||||
const headerComponent = (depth: number) => {
|
const headerComponent = (depth: number) => {
|
||||||
return 'h' + depth;
|
return 'h' + depth;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const exportTableToCSVHandler = (token, tokenIdx = 0) => {
|
||||||
|
console.log('Exporting table to CSV');
|
||||||
|
|
||||||
|
// Create an array for rows that will hold the mapped cell text.
|
||||||
|
const rows = token.rows.map((row) =>
|
||||||
|
row.map((cell) => cell.tokens.map((token) => token.text).join(''))
|
||||||
|
);
|
||||||
|
|
||||||
|
// Join the rows using commas (,) as the separator and rows using newline (\n).
|
||||||
|
const csvContent = rows.map((row) => row.join(',')).join('\n');
|
||||||
|
|
||||||
|
// Log rows and CSV content to ensure everything is correct.
|
||||||
|
console.log(rows);
|
||||||
|
console.log(csvContent);
|
||||||
|
|
||||||
|
// To handle Unicode characters, you need to prefix the data with a BOM:
|
||||||
|
const bom = '\uFEFF'; // BOM for UTF-8
|
||||||
|
|
||||||
|
// Create a new Blob prefixed with the BOM to ensure proper Unicode encoding.
|
||||||
|
const blob = new Blob([bom + csvContent], { type: 'text/csv;charset=UTF-8' });
|
||||||
|
|
||||||
|
// Use FileSaver.js's saveAs function to save the generated CSV file.
|
||||||
|
saveAs(blob, `table-${id}-${tokenIdx}.csv`);
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- {JSON.stringify(tokens)} -->
|
<!-- {JSON.stringify(tokens)} -->
|
||||||
@ -55,35 +87,68 @@
|
|||||||
{token.text}
|
{token.text}
|
||||||
{/if}
|
{/if}
|
||||||
{:else if token.type === 'table'}
|
{:else if token.type === 'table'}
|
||||||
<div class="scrollbar-hidden relative whitespace-nowrap overflow-x-auto max-w-full">
|
<div class="relative w-full group">
|
||||||
<table class="w-full">
|
<div
|
||||||
<thead>
|
class="scrollbar-hidden relative whitespace-nowrap overflow-x-auto max-w-full rounded-lg"
|
||||||
<tr>
|
>
|
||||||
{#each token.header as header, headerIdx}
|
<table
|
||||||
<th style={token.align[headerIdx] ? '' : `text-align: ${token.align[headerIdx]}`}>
|
class="table-auto w-full text-sm text-left text-gray-500 dark:text-gray-400 max-w-full rounded-xl"
|
||||||
<MarkdownInlineTokens
|
>
|
||||||
id={`${id}-${tokenIdx}-header-${headerIdx}`}
|
<thead
|
||||||
tokens={header.tokens}
|
class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-850 dark:text-gray-400 border-none"
|
||||||
/>
|
>
|
||||||
</th>
|
<tr class="">
|
||||||
{/each}
|
{#each token.header as header, headerIdx}
|
||||||
</tr>
|
<th
|
||||||
</thead>
|
scope="col"
|
||||||
<tbody>
|
class="!px-2 !py-1.5 cursor-pointer select-none border border-gray-50 dark:border-gray-850"
|
||||||
{#each token.rows as row, rowIdx}
|
style={token.align[headerIdx] ? '' : `text-align: ${token.align[headerIdx]}`}
|
||||||
<tr>
|
>
|
||||||
{#each row ?? [] as cell, cellIdx}
|
<div class="flex gap-1.5 items-center">
|
||||||
<td style={token.align[cellIdx] ? '' : `text-align: ${token.align[cellIdx]}`}>
|
<MarkdownInlineTokens
|
||||||
<MarkdownInlineTokens
|
id={`${id}-${tokenIdx}-header-${headerIdx}`}
|
||||||
id={`${id}-${tokenIdx}-row-${rowIdx}-${cellIdx}`}
|
tokens={header.tokens}
|
||||||
tokens={cell.tokens}
|
/>
|
||||||
/>
|
</div>
|
||||||
</td>
|
</th>
|
||||||
{/each}
|
{/each}
|
||||||
</tr>
|
</tr>
|
||||||
{/each}
|
</thead>
|
||||||
</tbody>
|
<tbody>
|
||||||
</table>
|
{#each token.rows as row, rowIdx}
|
||||||
|
<tr class="bg-white dark:bg-gray-900 dark:border-gray-850 text-xs">
|
||||||
|
{#each row ?? [] as cell, cellIdx}
|
||||||
|
<td
|
||||||
|
class="!px-2 !py-1.5 font-medium text-gray-900 dark:text-white w-max border border-gray-50 dark:border-gray-850"
|
||||||
|
style={token.align[cellIdx] ? '' : `text-align: ${token.align[cellIdx]}`}
|
||||||
|
>
|
||||||
|
<div class="flex">
|
||||||
|
<MarkdownInlineTokens
|
||||||
|
id={`${id}-${tokenIdx}-row-${rowIdx}-${cellIdx}`}
|
||||||
|
tokens={cell.tokens}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
{/each}
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class=" absolute top-1 right-1.5 z-20 invisible group-hover:visible">
|
||||||
|
<Tooltip content={$i18n.t('Export to CSV')}>
|
||||||
|
<button
|
||||||
|
class="p-1 rounded-lg bg-transparent transition"
|
||||||
|
on:click={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
exportTableToCSVHandler(token, tokenIdx);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ArrowDownTray className=" size-3.5" strokeWidth="1.5" />
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else if token.type === 'blockquote'}
|
{:else if token.type === 'blockquote'}
|
||||||
<blockquote>
|
<blockquote>
|
||||||
|
Loading…
Reference in New Issue
Block a user