Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 196d28ca25 | |||
| f3ba4c8876 |
@@ -18,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
// Version is set at build time via -ldflags, or defaults to dev
|
||||
var Version = "0.5.0"
|
||||
var Version = "0.5.1"
|
||||
|
||||
func getEnvOrDefault(key, defaultValue string) string {
|
||||
if value := os.Getenv(key); value != "" {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vessel",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import { projectsState, toastState } from '$lib/stores';
|
||||
import type { Project } from '$lib/stores/projects.svelte.js';
|
||||
import { addProjectLink, deleteProjectLink, getProjectLinks, type ProjectLink } from '$lib/storage/projects.js';
|
||||
import { ConfirmDialog } from '$lib/components/shared';
|
||||
|
||||
interface Props {
|
||||
isOpen: boolean;
|
||||
@@ -26,6 +27,7 @@
|
||||
let newLinkDescription = $state('');
|
||||
let isLoading = $state(false);
|
||||
let activeTab = $state<'settings' | 'instructions' | 'links'>('settings');
|
||||
let showDeleteConfirm = $state(false);
|
||||
|
||||
// Predefined colors for quick selection
|
||||
const presetColors = [
|
||||
@@ -121,13 +123,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDelete() {
|
||||
function handleDeleteClick() {
|
||||
if (!projectId) return;
|
||||
showDeleteConfirm = true;
|
||||
}
|
||||
|
||||
if (!confirm('Delete this project? Conversations will be unlinked but not deleted.')) {
|
||||
return;
|
||||
}
|
||||
|
||||
async function handleDeleteConfirm() {
|
||||
if (!projectId) return;
|
||||
showDeleteConfirm = false;
|
||||
isLoading = true;
|
||||
|
||||
try {
|
||||
@@ -429,7 +432,7 @@
|
||||
{#if projectId}
|
||||
<button
|
||||
type="button"
|
||||
onclick={handleDelete}
|
||||
onclick={handleDeleteClick}
|
||||
disabled={isLoading}
|
||||
class="rounded-lg px-4 py-2 text-sm font-medium text-red-500 transition-colors hover:bg-red-900/30 disabled:opacity-50"
|
||||
>
|
||||
@@ -458,3 +461,13 @@
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<ConfirmDialog
|
||||
isOpen={showDeleteConfirm}
|
||||
title="Delete Project"
|
||||
message="Delete this project? Conversations will be unlinked but not deleted."
|
||||
confirmText="Delete"
|
||||
variant="danger"
|
||||
onConfirm={handleDeleteConfirm}
|
||||
onCancel={() => (showDeleteConfirm = false)}
|
||||
/>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
} from '$lib/memory';
|
||||
import type { StoredDocument } from '$lib/storage/db';
|
||||
import { toastState, modelsState } from '$lib/stores';
|
||||
import { ConfirmDialog } from '$lib/components/shared';
|
||||
|
||||
let documents = $state<StoredDocument[]>([]);
|
||||
let stats = $state({ documentCount: 0, chunkCount: 0, totalTokens: 0 });
|
||||
@@ -22,6 +23,7 @@
|
||||
let uploadProgress = $state({ current: 0, total: 0 });
|
||||
let selectedModel = $state(DEFAULT_EMBEDDING_MODEL);
|
||||
let dragOver = $state(false);
|
||||
let deleteConfirm = $state<{ show: boolean; doc: StoredDocument | null }>({ show: false, doc: null });
|
||||
|
||||
let fileInput: HTMLInputElement;
|
||||
|
||||
@@ -90,10 +92,14 @@
|
||||
uploadProgress = { current: 0, total: 0 };
|
||||
}
|
||||
|
||||
async function handleDelete(doc: StoredDocument) {
|
||||
if (!confirm(`Delete "${doc.name}"? This cannot be undone.`)) {
|
||||
return;
|
||||
}
|
||||
function handleDeleteClick(doc: StoredDocument) {
|
||||
deleteConfirm = { show: true, doc };
|
||||
}
|
||||
|
||||
async function confirmDelete() {
|
||||
if (!deleteConfirm.doc) return;
|
||||
const doc = deleteConfirm.doc;
|
||||
deleteConfirm = { show: false, doc: null };
|
||||
|
||||
try {
|
||||
await deleteDocument(doc.id);
|
||||
@@ -232,7 +238,7 @@
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => handleDelete(doc)}
|
||||
onclick={() => handleDeleteClick(doc)}
|
||||
class="rounded p-2 text-theme-muted transition-colors hover:bg-red-900/30 hover:text-red-400"
|
||||
aria-label="Delete document"
|
||||
>
|
||||
@@ -273,3 +279,13 @@
|
||||
{/if}
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<ConfirmDialog
|
||||
isOpen={deleteConfirm.show}
|
||||
title="Delete Document"
|
||||
message={`Delete "${deleteConfirm.doc?.name}"? This cannot be undone.`}
|
||||
confirmText="Delete"
|
||||
variant="danger"
|
||||
onConfirm={confirmDelete}
|
||||
onCancel={() => (deleteConfirm = { show: false, doc: null })}
|
||||
/>
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
type PromptTemplate,
|
||||
type PromptCategory
|
||||
} from '$lib/prompts/templates';
|
||||
import { ConfirmDialog } from '$lib/components/shared';
|
||||
|
||||
type Tab = 'my-prompts' | 'browse-templates';
|
||||
let activeTab = $state<Tab>('my-prompts');
|
||||
let deleteConfirm = $state<{ show: boolean; prompt: Prompt | null }>({ show: false, prompt: null });
|
||||
|
||||
let showEditor = $state(false);
|
||||
let editingPrompt = $state<Prompt | null>(null);
|
||||
@@ -106,10 +108,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDelete(prompt: Prompt): Promise<void> {
|
||||
if (confirm(`Delete "${prompt.name}"? This cannot be undone.`)) {
|
||||
await promptsState.remove(prompt.id);
|
||||
}
|
||||
function handleDeleteClick(prompt: Prompt): void {
|
||||
deleteConfirm = { show: true, prompt };
|
||||
}
|
||||
|
||||
async function confirmDelete(): Promise<void> {
|
||||
if (!deleteConfirm.prompt) return;
|
||||
await promptsState.remove(deleteConfirm.prompt.id);
|
||||
deleteConfirm = { show: false, prompt: null };
|
||||
}
|
||||
|
||||
async function handleSetDefault(prompt: Prompt): Promise<void> {
|
||||
@@ -286,7 +292,7 @@
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button" onclick={() => handleDelete(prompt)} class="rounded p-1.5 text-theme-muted hover:bg-red-900/30 hover:text-red-400" title="Delete">
|
||||
<button type="button" onclick={() => handleDeleteClick(prompt)} class="rounded p-1.5 text-theme-muted hover:bg-red-900/30 hover:text-red-400" title="Delete">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
||||
</svg>
|
||||
@@ -444,3 +450,13 @@
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<ConfirmDialog
|
||||
isOpen={deleteConfirm.show}
|
||||
title="Delete Prompt"
|
||||
message={`Delete "${deleteConfirm.prompt?.name}"? This cannot be undone.`}
|
||||
confirmText="Delete"
|
||||
variant="danger"
|
||||
onConfirm={confirmDelete}
|
||||
onCancel={() => (deleteConfirm = { show: false, prompt: null })}
|
||||
/>
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
import { toolsState } from '$lib/stores';
|
||||
import type { ToolDefinition, CustomTool } from '$lib/tools';
|
||||
import { ToolEditor } from '$lib/components/tools';
|
||||
import { ConfirmDialog } from '$lib/components/shared';
|
||||
|
||||
let showEditor = $state(false);
|
||||
let editingTool = $state<CustomTool | null>(null);
|
||||
let searchQuery = $state('');
|
||||
let expandedDescriptions = $state<Set<string>>(new Set());
|
||||
let deleteConfirm = $state<{ show: boolean; tool: CustomTool | null }>({ show: false, tool: null });
|
||||
|
||||
function openCreateEditor(): void {
|
||||
editingTool = null;
|
||||
@@ -32,9 +34,14 @@
|
||||
}
|
||||
|
||||
function handleDeleteTool(tool: CustomTool): void {
|
||||
if (confirm(`Delete "${tool.name}"? This cannot be undone.`)) {
|
||||
toolsState.removeCustomTool(tool.id);
|
||||
deleteConfirm = { show: true, tool };
|
||||
}
|
||||
|
||||
function confirmDeleteTool(): void {
|
||||
if (deleteConfirm.tool) {
|
||||
toolsState.removeCustomTool(deleteConfirm.tool.id);
|
||||
}
|
||||
deleteConfirm = { show: false, tool: null };
|
||||
}
|
||||
|
||||
const allTools = $derived(toolsState.getAllToolsWithState());
|
||||
@@ -509,3 +516,13 @@
|
||||
onClose={() => { showEditor = false; editingTool = null; }}
|
||||
onSave={handleSaveTool}
|
||||
/>
|
||||
|
||||
<ConfirmDialog
|
||||
isOpen={deleteConfirm.show}
|
||||
title="Delete Tool"
|
||||
message={`Delete "${deleteConfirm.tool?.name}"? This cannot be undone.`}
|
||||
confirmText="Delete"
|
||||
variant="danger"
|
||||
onConfirm={confirmDeleteTool}
|
||||
onCancel={() => (deleteConfirm = { show: false, tool: null })}
|
||||
/>
|
||||
|
||||
@@ -175,7 +175,7 @@ export async function updateProject(
|
||||
*/
|
||||
export async function deleteProject(id: string): Promise<StorageResult<void>> {
|
||||
return withErrorHandling(async () => {
|
||||
await db.transaction('rw', [db.projects, db.projectLinks, db.conversations, db.documents, db.chatChunks], async () => {
|
||||
await db.transaction('rw', [db.projects, db.projectLinks, db.conversations, db.documents, db.chunks, db.chatChunks], async () => {
|
||||
// Unlink all conversations from this project
|
||||
const conversations = await db.conversations.where('projectId').equals(id).toArray();
|
||||
for (const conv of conversations) {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
import type { StoredDocument } from '$lib/storage/db';
|
||||
import ProjectModal from '$lib/components/projects/ProjectModal.svelte';
|
||||
import { searchProjectChatHistory, type ChatSearchResult } from '$lib/services/chat-indexer.js';
|
||||
import { ConfirmDialog } from '$lib/components/shared';
|
||||
|
||||
// Get project ID from URL
|
||||
const projectId = $derived($page.params.id);
|
||||
@@ -50,6 +51,7 @@
|
||||
let isSearching = $state(false);
|
||||
let searchResults = $state<ChatSearchResult[]>([]);
|
||||
let searchDebounceTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
let deleteDocConfirm = $state<{ show: boolean; doc: StoredDocument | null }>({ show: false, doc: null });
|
||||
|
||||
// Map of conversationId -> best matching snippet from search
|
||||
const searchSnippetMap = $derived.by(() => {
|
||||
@@ -323,8 +325,14 @@
|
||||
await loadProjectData();
|
||||
}
|
||||
|
||||
async function handleDeleteDocument(doc: StoredDocument) {
|
||||
if (!confirm(`Delete "${doc.name}"? This cannot be undone.`)) return;
|
||||
function handleDeleteDocumentClick(doc: StoredDocument) {
|
||||
deleteDocConfirm = { show: true, doc };
|
||||
}
|
||||
|
||||
async function confirmDeleteDocument() {
|
||||
if (!deleteDocConfirm.doc) return;
|
||||
const doc = deleteDocConfirm.doc;
|
||||
deleteDocConfirm = { show: false, doc: null };
|
||||
|
||||
try {
|
||||
await deleteDocument(doc.id);
|
||||
@@ -632,7 +640,7 @@
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => handleDeleteDocument(doc)}
|
||||
onclick={() => handleDeleteDocumentClick(doc)}
|
||||
class="rounded p-1.5 text-theme-muted transition-colors hover:bg-red-900/30 hover:text-red-400"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
@@ -705,3 +713,14 @@
|
||||
{projectId}
|
||||
onUpdate={() => loadProjectData()}
|
||||
/>
|
||||
|
||||
<!-- Delete Document Confirm -->
|
||||
<ConfirmDialog
|
||||
isOpen={deleteDocConfirm.show}
|
||||
title="Delete Document"
|
||||
message={`Delete "${deleteDocConfirm.doc?.name}"? This cannot be undone.`}
|
||||
confirmText="Delete"
|
||||
variant="danger"
|
||||
onConfirm={confirmDeleteDocument}
|
||||
onCancel={() => (deleteDocConfirm = { show: false, doc: null })}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user