From 69f5078b049bb71ef17e629bf1bd1f15f282993b Mon Sep 17 00:00:00 2001 From: Alastair Grant <85125580+aldo-g@users.noreply.github.com> Date: Fri, 14 Feb 2025 15:26:42 +0100 Subject: [PATCH] improving ui more --- src/components/TestDashboardView.ts | 87 ++++++++++++++++------------- styles.css | 4 +- 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/src/components/TestDashboardView.ts b/src/components/TestDashboardView.ts index 3c2e984..5d74939 100644 --- a/src/components/TestDashboardView.ts +++ b/src/components/TestDashboardView.ts @@ -1,10 +1,9 @@ /* This file implements a custom sidebar view (dashboard) for the Obsidian RAG Test Plugin. It displays a list of all indexed notes with checkboxes for selection and a "Create Tests" button. -When "Create Tests" is clicked, an OpenAI API call is made for each selected note (using that note's full content) -to generate test questions. While tests are being generated, a spinner is shown next to the respective file name. -Once the tests are generated for a file, the spinner is replaced by a clickable icon which, when clicked, -opens a full-screen view displaying the generated tests. +Each row initially shows a greyed-out document icon. When tests are being generated for that note, +the icon is replaced by a spinner. Once tests are generated, the spinner is replaced by an active, +colored document icon that opens the full-screen test questions view when clicked. */ import { App, ItemView, Notice, WorkspaceLeaf } from "obsidian"; @@ -62,13 +61,13 @@ export default class TestDashboardView extends ItemView { } /** - * Renders the dashboard: a list of notes with selection checkboxes and a "Create Tests" button. + * Renders the dashboard: a list of notes with checkboxes, file names, and a status icon. */ async render(): Promise { const container = this.containerEl; container.empty(); - // Header with "Create Tests" button + // Header with "Create Tests" button. const headerEl = container.createEl("div", { cls: "test-view-header" }); const createTestsButton = headerEl.createEl("button", { text: "Create Tests" }); createTestsButton.disabled = true; @@ -76,22 +75,27 @@ export default class TestDashboardView extends ItemView { await this.createTests(); }); - // Container for the list of notes + // Container for the list of notes. const listEl = container.createEl("ul"); this.pluginData.forEach((note) => { const itemEl = listEl.createEl("li"); const checkbox = itemEl.createEl("input", { type: "checkbox" }); checkbox.dataset.filePath = note.filePath; + // Display the file name. itemEl.createEl("span", { text: ` ${note.filePath}` }); - // Create spinner element (hidden by default) - const spinnerEl = itemEl.createEl("div", { cls: "spinner" }); - spinnerEl.style.display = "none"; - spinnerEl.style.marginLeft = "0.5em"; + // Create a status icon container. + const statusIconEl = itemEl.createEl("span", { cls: "status-icon" }); + statusIconEl.style.marginLeft = "0.5em"; + // Initially, display a greyed-out document icon. + statusIconEl.innerHTML = ` + + + +`; checkbox.addEventListener("change", () => { this.updateCreateTestsButtonState(createTestsButton, listEl); }); }); - this.updateCreateTestsButtonState(createTestsButton, listEl); } @@ -113,12 +117,13 @@ export default class TestDashboardView extends ItemView { /** * For each selected note, calls the LLM API to generate test questions, - * and replaces the spinner with an icon that, when clicked, opens the full-screen view for that file's tests. + * updates the row's status icon to a spinner during generation, and then replaces it + * with a clickable document icon (active) that opens the full-screen view. */ async createTests(): Promise { const container = this.containerEl; const checkboxes = container.querySelectorAll('input[type="checkbox"]'); - // Retrieve API key from plugin settings stored in the main plugin instance. + // Retrieve API key from plugin settings. const plugin = (this.app as any).plugins.plugins["obsidian-rag-test-plugin"] as any; const apiKey = plugin?.settings?.apiKey; if (!apiKey) { @@ -133,41 +138,43 @@ export default class TestDashboardView extends ItemView { if (!note) continue; console.log(`Generating tests for: ${filePath}`); const listItem = input.parentElement; - const spinnerEl = listItem?.querySelector(".spinner"); - if (spinnerEl) { - spinnerEl.style.display = "inline-block"; + const statusIconEl = listItem?.querySelector(".status-icon"); + // Change icon to spinner. + if (statusIconEl) { + statusIconEl.innerHTML = `
`; } try { - // Generate tests for this note. const response = await generateTestQuestions([note], apiKey); console.log(`Generated tests for ${filePath}:`, response); - // Remove spinner and add a view icon. - if (spinnerEl) { - spinnerEl.style.display = "none"; - // Create a button with a document icon. - const iconBtn = document.createElement("button"); - iconBtn.classList.add("view-tests-icon"); - iconBtn.title = "View Generated Tests"; - // Example inline SVG for a document icon (adjust as needed). - iconBtn.innerHTML = ` - - - -`; - // Append the icon button to the list item. - listItem?.appendChild(iconBtn); - // When clicked, open a full-screen view for this file's tests. - iconBtn.addEventListener("click", () => { - (plugin as any).openQuestionDocument(response); - }); + // After generation, update icon to active document icon. + if (statusIconEl) { + statusIconEl.innerHTML = ``; + // Remove grey color by changing fill attribute via CSS class. + const iconBtn = statusIconEl.querySelector("button.view-tests-icon") as HTMLButtonElement; + if (iconBtn) { + iconBtn.addEventListener("click", () => { + (plugin as any).openQuestionDocument(response); + }); + } } } catch (error) { console.error(`Error generating tests for ${filePath}:`, error); - if (spinnerEl) { - spinnerEl.style.display = "none"; - } + if (statusIconEl) { + // Revert icon to greyed-out document icon. + statusIconEl.innerHTML = ` + + + +`; } } } } +} } \ No newline at end of file diff --git a/styles.css b/styles.css index c24a81f..4907a94 100644 --- a/styles.css +++ b/styles.css @@ -8,6 +8,7 @@ If your plugin does not need CSS, delete this file. */ .spinner { + display: inline-block; border: 2px solid rgba(0, 0, 0, 0.1); border-left-color: #000; border-radius: 50%; @@ -19,13 +20,12 @@ If your plugin does not need CSS, delete this file. @keyframes spin { to { transform: rotate(360deg); } } - + .view-tests-icon { background: none; border: none; cursor: pointer; padding: 0; - margin-left: 0.5em; } .view-tests-icon svg {