refac
This commit is contained in:
@@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
import ModelEditor from '$lib/components/workspace/Models/ModelEditor.svelte';
|
import ModelEditor from '$lib/components/workspace/Models/ModelEditor.svelte';
|
||||||
import { toast } from 'svelte-sonner';
|
import { toast } from 'svelte-sonner';
|
||||||
|
import Badge from '$lib/components/common/Badge.svelte';
|
||||||
import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
|
import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
|
||||||
import Cog6 from '$lib/components/icons/Cog6.svelte';
|
import Cog6 from '$lib/components/icons/Cog6.svelte';
|
||||||
import ConfigureModelsModal from './Models/ConfigureModelsModal.svelte';
|
import ConfigureModelsModal from './Models/ConfigureModelsModal.svelte';
|
||||||
@@ -322,6 +323,69 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex w-full justify-end gap-1.5">
|
<div class="flex w-full justify-end gap-1.5">
|
||||||
|
{#if $user?.role === 'admin'}
|
||||||
|
<input
|
||||||
|
id="models-import-input"
|
||||||
|
bind:this={modelsImportInputElement}
|
||||||
|
bind:files={importFiles}
|
||||||
|
type="file"
|
||||||
|
accept=".json"
|
||||||
|
hidden
|
||||||
|
on:change={() => {
|
||||||
|
if (importFiles.length > 0) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = async (event) => {
|
||||||
|
modelsImportInProgress = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const models = JSON.parse(String(event.target.result));
|
||||||
|
const res = await importModels(localStorage.token, models);
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
toast.success($i18n.t('Models imported successfully'));
|
||||||
|
await init();
|
||||||
|
} else {
|
||||||
|
toast.error($i18n.t('Failed to import models'));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
toast.error(e?.detail ?? $i18n.t('Invalid JSON file'));
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
modelsImportInProgress = false;
|
||||||
|
};
|
||||||
|
reader.readAsText(importFiles[0]);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 dark:text-gray-200 transition"
|
||||||
|
disabled={modelsImportInProgress}
|
||||||
|
on:click={() => {
|
||||||
|
modelsImportInputElement.click();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{#if modelsImportInProgress}
|
||||||
|
<Spinner className="size-3" />
|
||||||
|
{/if}
|
||||||
|
<div class=" self-center font-medium line-clamp-1">
|
||||||
|
{$i18n.t('Import')}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 dark:text-gray-200 transition"
|
||||||
|
on:click={async () => {
|
||||||
|
downloadModels(models);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class=" self-center font-medium line-clamp-1">
|
||||||
|
{$i18n.t('Export')}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 dark:text-gray-200 transition"
|
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 dark:text-gray-200 transition"
|
||||||
type="button"
|
type="button"
|
||||||
@@ -335,7 +399,7 @@
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 dark:text-gray-200 transition"
|
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-black hover:bg-gray-900 text-white dark:bg-white dark:hover:bg-gray-100 dark:text-black transition font-medium"
|
||||||
type="button"
|
type="button"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
showConfigModal = true;
|
showConfigModal = true;
|
||||||
@@ -445,7 +509,7 @@
|
|||||||
selectedModelId = model.id;
|
selectedModelId = model.id;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class=" self-center w-8">
|
<div class=" self-center w-9">
|
||||||
<div
|
<div
|
||||||
class=" rounded-full object-cover {(model?.is_active ?? true)
|
class=" rounded-full object-cover {(model?.is_active ?? true)
|
||||||
? ''
|
? ''
|
||||||
@@ -473,7 +537,27 @@
|
|||||||
className=" w-fit"
|
className=" w-fit"
|
||||||
placement="top-start"
|
placement="top-start"
|
||||||
>
|
>
|
||||||
<div class=" font-semibold line-clamp-1">{model.name}</div>
|
<div class="font-medium line-clamp-1 flex items-center gap-1.5">
|
||||||
|
{model.name}
|
||||||
|
<Badge
|
||||||
|
type={(model?.access_grants ?? []).some(
|
||||||
|
(g) =>
|
||||||
|
g.principal_type === 'user' &&
|
||||||
|
g.principal_id === '*' &&
|
||||||
|
g.permission === 'read'
|
||||||
|
)
|
||||||
|
? 'success'
|
||||||
|
: 'muted'}
|
||||||
|
content={(model?.access_grants ?? []).some(
|
||||||
|
(g) =>
|
||||||
|
g.principal_type === 'user' &&
|
||||||
|
g.principal_id === '*' &&
|
||||||
|
g.permission === 'read'
|
||||||
|
)
|
||||||
|
? $i18n.t('Public')
|
||||||
|
: $i18n.t('Private')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<div class=" text-xs overflow-hidden text-ellipsis line-clamp-1 text-gray-500">
|
<div class=" text-xs overflow-hidden text-ellipsis line-clamp-1 text-gray-500">
|
||||||
<span class=" line-clamp-1">
|
<span class=" line-clamp-1">
|
||||||
@@ -590,103 +674,6 @@
|
|||||||
<Pagination bind:page={currentPage} count={filteredModels.length} {perPage} />
|
<Pagination bind:page={currentPage} count={filteredModels.length} {perPage} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if $user?.role === 'admin'}
|
|
||||||
<div class=" flex justify-end w-full mb-3">
|
|
||||||
<div class="flex space-x-1">
|
|
||||||
<input
|
|
||||||
id="models-import-input"
|
|
||||||
bind:this={modelsImportInputElement}
|
|
||||||
bind:files={importFiles}
|
|
||||||
type="file"
|
|
||||||
accept=".json"
|
|
||||||
hidden
|
|
||||||
on:change={() => {
|
|
||||||
if (importFiles.length > 0) {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = async (event) => {
|
|
||||||
modelsImportInProgress = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const models = JSON.parse(String(event.target.result));
|
|
||||||
const res = await importModels(localStorage.token, models);
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
toast.success($i18n.t('Models imported successfully'));
|
|
||||||
await init();
|
|
||||||
} else {
|
|
||||||
toast.error($i18n.t('Failed to import models'));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
toast.error(e?.detail ?? $i18n.t('Invalid JSON file'));
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
modelsImportInProgress = false;
|
|
||||||
};
|
|
||||||
reader.readAsText(importFiles[0]);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition"
|
|
||||||
disabled={modelsImportInProgress}
|
|
||||||
on:click={() => {
|
|
||||||
modelsImportInputElement.click();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{#if modelsImportInProgress}
|
|
||||||
<Spinner className="size-3" />
|
|
||||||
{/if}
|
|
||||||
<div class=" self-center mr-2 font-medium line-clamp-1">
|
|
||||||
{$i18n.t('Import Presets')}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=" self-center">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
fill="currentColor"
|
|
||||||
class="w-3.5 h-3.5"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M4 2a1.5 1.5 0 0 0-1.5 1.5v9A1.5 1.5 0 0 0 4 14h8a1.5 1.5 0 0 0 1.5-1.5V6.621a1.5 1.5 0 0 0-.44-1.06L9.94 2.439A1.5 1.5 0 0 0 8.878 2H4Zm4 9.5a.75.75 0 0 1-.75-.75V8.06l-.72.72a.75.75 0 0 1-1.06-1.06l2-2a.75.75 0 0 1 1.06 0l2 2a.75.75 0 1 1-1.06 1.06l-.72-.72v2.69a.75.75 0 0 1-.75.75Z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition"
|
|
||||||
on:click={async () => {
|
|
||||||
downloadModels(models);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div class=" self-center mr-2 font-medium line-clamp-1">
|
|
||||||
{$i18n.t('Export Presets')} ({models.length})
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=" self-center">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
fill="currentColor"
|
|
||||||
class="w-3.5 h-3.5"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M4 2a1.5 1.5 0 0 0-1.5 1.5v9A1.5 1.5 0 0 0 4 14h8a1.5 1.5 0 0 0 1.5-1.5V6.621a1.5 1.5 0 0 0-.44-1.06L9.94 2.439A1.5 1.5 0 0 0 8.878 2H4Zm4 3.5a.75.75 0 0 1 .75.75v2.69l.72-.72a.75.75 0 1 1 1.06 1.06l-2 2a.75.75 0 0 1-1.06 0l-2-2a.75.75 0 0 1 1.06-1.06l.72.72V6.25A.75.75 0 0 1 8 5.5Z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{:else}
|
{:else}
|
||||||
<ModelEditor
|
<ModelEditor
|
||||||
edit
|
edit
|
||||||
|
|||||||
Reference in New Issue
Block a user