mirror of
https://github.com/open-webui/open-webui.git
synced 2026-07-11 04:50:11 +02:00
refac
This commit is contained in:
@@ -441,6 +441,18 @@
|
||||
{filePdfData}
|
||||
{fileContent}
|
||||
onDownload={() => downloadFile(selectedFile)}
|
||||
onSave={async (content) => {
|
||||
const terminal = selectedTerminal;
|
||||
if (!terminal || !selectedFile) return;
|
||||
const fileName = selectedFile.split('/').pop() ?? 'file';
|
||||
const dir = selectedFile.substring(0, selectedFile.lastIndexOf('/') + 1) || '/';
|
||||
const file = new File([content], fileName, { type: 'text/plain' });
|
||||
const result = await uploadToTerminal(terminal.url, terminal.key, dir, file);
|
||||
toast[result ? 'success' : 'error'](
|
||||
$i18n.t(result ? 'File saved' : 'Failed to save file')
|
||||
);
|
||||
if (result) fileContent = content;
|
||||
}}
|
||||
/>
|
||||
{:else}
|
||||
{#if uploading}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import PDFViewer from '../../common/PDFViewer.svelte';
|
||||
import Tooltip from '../../common/Tooltip.svelte';
|
||||
import Reset from '../../icons/Reset.svelte';
|
||||
import PenAlt from '../../icons/PenAlt.svelte';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
@@ -17,6 +18,41 @@
|
||||
export let fileContent: string | null = null;
|
||||
|
||||
export let onDownload: () => void = () => {};
|
||||
export let onSave: ((content: string) => Promise<void>) | null = null;
|
||||
|
||||
let editing = false;
|
||||
let editContent = '';
|
||||
let saving = false;
|
||||
|
||||
// Reset edit state when switching files
|
||||
$: selectedFile, resetEdit();
|
||||
|
||||
const resetEdit = () => {
|
||||
editing = false;
|
||||
editContent = '';
|
||||
saving = false;
|
||||
};
|
||||
|
||||
const startEdit = () => {
|
||||
editContent = fileContent ?? '';
|
||||
editing = true;
|
||||
showRaw = true;
|
||||
};
|
||||
|
||||
const saveEdit = async () => {
|
||||
if (!onSave) return;
|
||||
saving = true;
|
||||
await onSave(editContent);
|
||||
saving = false;
|
||||
editing = false;
|
||||
};
|
||||
|
||||
const cancelEdit = () => {
|
||||
editing = false;
|
||||
editContent = '';
|
||||
};
|
||||
|
||||
$: isTextFile = fileContent !== null && fileImageUrl === null && filePdfData === null;
|
||||
|
||||
const MD_EXTS = new Set(['md', 'markdown', 'mdx']);
|
||||
const CSV_EXTS = new Set(['csv', 'tsv']);
|
||||
@@ -127,7 +163,10 @@
|
||||
<Tooltip content={showRaw ? $i18n.t('Preview') : $i18n.t('Source')}>
|
||||
<button
|
||||
class="p-1.5 rounded-lg bg-white/80 dark:bg-gray-850/80 backdrop-blur-sm shadow-sm hover:bg-gray-100 dark:hover:bg-gray-800 transition text-gray-500 dark:text-gray-400"
|
||||
on:click={() => (showRaw = !showRaw)}
|
||||
on:click={() => {
|
||||
if (editing) cancelEdit();
|
||||
showRaw = !showRaw;
|
||||
}}
|
||||
aria-label={showRaw ? $i18n.t('Preview') : $i18n.t('Source')}
|
||||
>
|
||||
{#if showRaw}
|
||||
@@ -171,6 +210,49 @@
|
||||
</button>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
{#if isTextFile && onSave}
|
||||
{#if editing}
|
||||
<Tooltip content={$i18n.t('Cancel')}>
|
||||
<button
|
||||
class="p-1.5 rounded-lg bg-white/80 dark:bg-gray-850/80 backdrop-blur-sm shadow-sm hover:bg-gray-100 dark:hover:bg-gray-800 transition text-gray-500 dark:text-gray-400"
|
||||
on:click={cancelEdit}
|
||||
aria-label={$i18n.t('Cancel')}
|
||||
>
|
||||
<!-- X icon -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-4">
|
||||
<path d="M6.28 5.22a.75.75 0 0 0-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 1 0 1.06 1.06L10 11.06l3.72 3.72a.75.75 0 1 0 1.06-1.06L11.06 10l3.72-3.72a.75.75 0 0 0-1.06-1.06L10 8.94 6.28 5.22Z" />
|
||||
</svg>
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip content={$i18n.t('Save')}>
|
||||
<button
|
||||
class="p-1.5 rounded-lg bg-white/80 dark:bg-gray-850/80 backdrop-blur-sm shadow-sm hover:bg-gray-100 dark:hover:bg-gray-800 transition text-gray-500 dark:text-gray-400"
|
||||
on:click={saveEdit}
|
||||
disabled={saving}
|
||||
aria-label={$i18n.t('Save')}
|
||||
>
|
||||
{#if saving}
|
||||
<Spinner className="size-4" />
|
||||
{:else}
|
||||
<!-- Check icon -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-4">
|
||||
<path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 0 1 .143 1.052l-8 10.5a.75.75 0 0 1-1.127.075l-4.5-4.5a.75.75 0 0 1 1.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 0 1 1.05-.143Z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
{/if}
|
||||
</button>
|
||||
</Tooltip>
|
||||
{:else}
|
||||
<Tooltip content={$i18n.t('Edit')}>
|
||||
<button
|
||||
class="p-1.5 rounded-lg bg-white/80 dark:bg-gray-850/80 backdrop-blur-sm shadow-sm hover:bg-gray-100 dark:hover:bg-gray-800 transition text-gray-500 dark:text-gray-400"
|
||||
on:click={startEdit}
|
||||
aria-label={$i18n.t('Edit')}
|
||||
>
|
||||
<PenAlt className="size-4" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
{/if}
|
||||
<button
|
||||
class="p-1.5 rounded-lg bg-white/80 dark:bg-gray-850/80 backdrop-blur-sm shadow-sm hover:bg-gray-100 dark:hover:bg-gray-800 transition text-gray-500 dark:text-gray-400"
|
||||
on:click={onDownload}
|
||||
@@ -240,8 +322,16 @@
|
||||
</table>
|
||||
</div>
|
||||
{:else}
|
||||
<pre
|
||||
class="text-xs font-mono text-gray-800 dark:text-gray-200 whitespace-pre-wrap break-all leading-relaxed p-3">{fileContent}</pre>
|
||||
{#if editing}
|
||||
<textarea
|
||||
bind:value={editContent}
|
||||
class="w-full h-full text-xs font-mono text-gray-800 dark:text-gray-200 whitespace-pre break-all leading-relaxed p-3 bg-transparent border-none outline-none resize-none"
|
||||
spellcheck="false"
|
||||
/>
|
||||
{:else}
|
||||
<pre
|
||||
class="text-xs font-mono text-gray-800 dark:text-gray-200 whitespace-pre-wrap break-all leading-relaxed p-3">{fileContent}</pre>
|
||||
{/if}
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="text-sm text-gray-400 text-center pt-8">
|
||||
|
||||
18
src/lib/components/icons/PenAlt.svelte
Normal file
18
src/lib/components/icons/PenAlt.svelte
Normal file
@@ -0,0 +1,18 @@
|
||||
<script lang="ts">
|
||||
export let className = 'size-4';
|
||||
</script>
|
||||
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
class={className}
|
||||
>
|
||||
<path
|
||||
d="M14.3632 5.65156L15.8431 4.17157C16.6242 3.39052 17.8905 3.39052 18.6716 4.17157L20.0858 5.58579C20.8668 6.36683 20.8668 7.63316 20.0858 8.41421L18.6058 9.8942M14.3632 5.65156L4.74749 15.2672C4.41542 15.5993 4.21079 16.0376 4.16947 16.5054L3.92738 19.2459C3.87261 19.8659 4.39148 20.3848 5.0115 20.33L7.75191 20.0879C8.21972 20.0466 8.65806 19.8419 8.99013 19.5099L18.6058 9.8942M14.3632 5.65156L18.6058 9.8942"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
Reference in New Issue
Block a user