open-webui/src/lib/components/admin/Settings/Database.svelte
Timothy Jaeryang Baek 131ddc32ec refac
2026-10-21 11:07:10 +09:00

180 lines
4.8 KiB
Svelte

<script lang="ts">
import fileSaver from 'file-saver';
const { saveAs } = fileSaver;
import { downloadDatabase } from '$lib/apis/utils';
import { getContext } from 'svelte';
import { config } from '$lib/stores';
import { toast } from 'svelte-sonner';
import { getAllUserChats } from '$lib/apis/chats';
import { getAllUsers } from '$lib/apis/users';
import { exportConfig, importConfig } from '$lib/apis/configs';
import AdminSettingRow from './AdminSettingRow.svelte';
import AdminSettingSection from './AdminSettingSection.svelte';
const i18n: any = getContext('i18n');
export let saveHandler: Function;
let configImportInputElement: HTMLInputElement;
const actionButtonClass =
'text-xs text-gray-500 transition-colors hover:text-gray-900 dark:text-gray-500 dark:hover:text-white';
const exportAllUserChats = async () => {
let blob = new Blob([JSON.stringify(await getAllUserChats(localStorage.token))], {
type: 'application/json'
});
saveAs(blob, `all-chats-export-${Date.now()}.json`);
};
const exportUsers = async () => {
const users = await getAllUsers(localStorage.token);
const headers = ['id', 'name', 'email', 'role'];
const csv = [
headers.join(','),
...users.users.map((user) => {
return headers
.map((header) => {
if (user[header] === null || user[header] === undefined) {
return '';
}
return `"${String(user[header]).replace(/"/g, '""')}"`;
})
.join(',');
})
].join('\n');
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
saveAs(blob, 'users.csv');
};
</script>
<div class="flex flex-col h-full justify-between text-sm">
<h2 class="text-sm font-medium text-gray-900 dark:text-white mb-4">
{$i18n.t('settings.admin.db.title')}
</h2>
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5">
<input
id="config-json-input"
bind:this={configImportInputElement}
hidden
type="file"
accept=".json"
on:change={(e) => {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = async (e) => {
const res = await importConfig(localStorage.token, JSON.parse(e.target.result)).catch(
(error) => {
toast.error(`${error}`);
}
);
if (res) {
toast.success($i18n.t('Config imported successfully'));
}
e.target.value = null;
};
reader.readAsText(file);
}}
/>
<AdminSettingSection title={$i18n.t('settings.admin.db.sections.config.title')} first>
<AdminSettingRow
let:labelId
label={$i18n.t('settings.admin.db.importConfig.label')}
description={$i18n.t('settings.admin.db.importConfig.description')}
>
<button
id={`${labelId}-control`}
class={actionButtonClass}
on:click={() => {
configImportInputElement.click();
}}
type="button"
>
{$i18n.t('Import')}
</button>
</AdminSettingRow>
<AdminSettingRow
let:labelId
label={$i18n.t('settings.admin.db.exportConfig.label')}
description={$i18n.t('settings.admin.db.exportConfig.description')}
>
<button
id={`${labelId}-control`}
class={actionButtonClass}
on:click={async () => {
const config = await exportConfig(localStorage.token);
const blob = new Blob([JSON.stringify(config)], {
type: 'application/json'
});
saveAs(blob, `config-${Date.now()}.json`);
}}
type="button"
>
{$i18n.t('Export')}
</button>
</AdminSettingRow>
</AdminSettingSection>
{#if $config?.features.enable_admin_export ?? true}
<AdminSettingSection title={$i18n.t('settings.admin.db.sections.export.title')}>
<AdminSettingRow
let:labelId
label={$i18n.t('settings.admin.db.database.label')}
description={$i18n.t('settings.admin.db.database.description')}
>
<button
id={`${labelId}-control`}
class={actionButtonClass}
on:click={() => {
downloadDatabase(localStorage.token).catch((error) => {
toast.error(`${error}`);
});
}}
type="button"
>
{$i18n.t('settings.admin.db.database.label')}
</button>
</AdminSettingRow>
<AdminSettingRow
let:labelId
label={$i18n.t('settings.admin.db.allChats.label')}
description={$i18n.t('settings.admin.db.allChats.description')}
>
<button
id={`${labelId}-control`}
class={actionButtonClass}
on:click={exportAllUserChats}
type="button"
>
{$i18n.t('Export')}
</button>
</AdminSettingRow>
<AdminSettingRow
let:labelId
label={$i18n.t('settings.admin.db.users.label')}
description={$i18n.t('settings.admin.db.users.description')}
>
<button
id={`${labelId}-control`}
class={actionButtonClass}
on:click={exportUsers}
type="button"
>
{$i18n.t('Export')}
</button>
</AdminSettingRow>
</AdminSettingSection>
{/if}
</div>
</div>