This commit is contained in:
Timothy Jaeryang Baek
2026-03-29 18:40:09 -05:00
parent bcb71bb520
commit 2388dd7dc3
4 changed files with 113 additions and 6 deletions
@@ -18,7 +18,7 @@
{#if tasks.length > 0 && hasActive}
<div
class="my-2 rounded-xl border border-gray-50 dark:border-gray-850 bg-white dark:bg-gray-900"
class="my-2 rounded-2xl border border-gray-50 dark:border-gray-850 bg-white dark:bg-gray-900"
transition:slide={{ duration: 200 }}
>
<!-- Header -->
@@ -26,7 +26,10 @@
<div class="flex items-center gap-1.5 text-xs text-gray-600 dark:text-gray-400">
<TaskListIcon className="w-3.5 h-3.5" />
<span>
{completedCount} {$i18n.t('out of')} {totalCount} {$i18n.t('tasks completed')}
{completedCount}
{$i18n.t('out of')}
{totalCount}
{$i18n.t('tasks completed')}
</span>
</div>
@@ -50,19 +53,43 @@
<div class="flex items-start gap-2 py-0.5 text-xs">
<span class="flex-shrink-0 mt-0.5 text-gray-400 dark:text-gray-500">
{#if task.status === 'completed'}
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
<svg
class="w-3.5 h-3.5"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2.5"
>
<path d="M5 13l4 4L19 7" stroke-linecap="round" stroke-linejoin="round" />
</svg>
{:else if task.status === 'in_progress'}
<svg class="w-3.5 h-3.5 animate-spin" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
<svg
class="w-3.5 h-3.5 animate-spin"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2.5"
>
<path d="M12 3a9 9 0 1 0 9 9" stroke-linecap="round" />
</svg>
{:else if task.status === 'cancelled'}
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<svg
class="w-3.5 h-3.5"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="12" cy="12" r="9" stroke-dasharray="4 3" />
</svg>
{:else}
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<svg
class="w-3.5 h-3.5"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="12" cy="12" r="9" />
</svg>
{/if}
@@ -26,6 +26,7 @@
export let unloadModelHandler: (modelValue: string) => void = () => {};
export let pinModelHandler: (modelId: string) => void = () => {};
export let deleteModelHandler: (model: any) => void = () => {};
export let onClick: () => void = () => {};
@@ -255,6 +256,7 @@
bind:show={showMenu}
model={item.model}
{pinModelHandler}
{deleteModelHandler}
copyLinkHandler={() => {
copyLinkHandler(item.model);
}}
@@ -18,6 +18,7 @@
export let pinModelHandler: (modelId: string) => void = () => {};
export let copyLinkHandler: Function = () => {};
export let deleteModelHandler: Function = () => {};
export let onClose: Function = () => {};
</script>
@@ -66,6 +67,37 @@
<div class="flex items-center">{$i18n.t('Edit')}</div>
</button>
{#if $user?.role === 'admin' && model?.owned_by === 'ollama'}
<button
type="button"
class="select-none flex rounded-xl py-1.5 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition items-center gap-2"
on:click={(e) => {
e.stopPropagation();
e.preventDefault();
deleteModelHandler(model);
show = false;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="size-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
/>
</svg>
<div class="flex items-center">{$i18n.t('Delete')}</div>
</button>
{/if}
<hr class="border-gray-50 dark:border-gray-800/30 my-1" />
{/if}
@@ -8,6 +8,7 @@
dayjs.extend(relativeTime);
import Spinner from '$lib/components/common/Spinner.svelte';
import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
import { flyAndScale } from '$lib/utils/transitions';
import { createEventDispatcher, onMount, getContext, tick } from 'svelte';
@@ -375,6 +376,41 @@
}
};
let showDeleteConfirm = false;
let deleteModelTarget: any = null;
const deleteModelHandler = async (model: any) => {
deleteModelTarget = model;
showDeleteConfirm = true;
};
const confirmDeleteModel = async () => {
const model = deleteModelTarget;
if (!model) return;
const res = await deleteModel(localStorage.token, model.id).catch((error) => {
toast.error($i18n.t('Error deleting model: {{error}}', { error }));
});
if (res) {
toast.success($i18n.t('Model {{modelName}} deleted successfully', { modelName: model.name ?? model.id }));
// If the deleted model was selected, clear the selection
if (value === model.id) {
value = '';
}
models.set(
await getModels(
localStorage.token,
$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
)
);
}
deleteModelTarget = null;
};
const ITEM_HEIGHT = 42;
const OVERSCAN = 10;
@@ -388,6 +424,15 @@
);
</script>
<ConfirmDialog
bind:show={showDeleteConfirm}
title={$i18n.t('Delete Model')}
message={$i18n.t('Are you sure you want to delete **{{modelName}}**?', { modelName: deleteModelTarget?.name ?? deleteModelTarget?.id ?? '' })}
on:confirm={() => {
confirmDeleteModel();
}}
/>
<DropdownMenu.Root
bind:open={show}
onOpenChange={async () => {
@@ -646,6 +691,7 @@
{value}
{pinModelHandler}
{unloadModelHandler}
{deleteModelHandler}
onClick={() => {
value = item.value;
selectedModelIdx = index;