mirror of
https://github.com/aldo-g/obsidian-llm-test.git
synced 2026-07-22 05:42:19 +00:00
improving ui more
This commit is contained in:
parent
92dd59c827
commit
69f5078b04
2 changed files with 49 additions and 42 deletions
|
|
@ -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<void> {
|
||||
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 = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="gray" class="bi bi-file-text" viewBox="0 0 16 16">
|
||||
<path d="M4 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V5.5L9.5 0H4z"/>
|
||||
<path d="M9.5 0v4a1 1 0 0 0 1 1h4"/>
|
||||
<path d="M4.5 7a.5.5 0 0 1 .5.5v.5h5v-1h-5V7.5a.5.5 0 0 1 .5-.5z"/>
|
||||
</svg>`;
|
||||
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<void> {
|
||||
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 = `<div class="spinner"></div>`;
|
||||
}
|
||||
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 = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-text" viewBox="0 0 16 16">
|
||||
<path d="M4 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V5.5L9.5 0H4z"/>
|
||||
<path d="M9.5 0v4a1 1 0 0 0 1 1h4"/>
|
||||
<path fill-rule="evenodd" d="M4.5 7a.5.5 0 0 1 .5.5v.5h5v-1h-5V7.5a.5.5 0 0 1 .5-.5z"/>
|
||||
</svg>`;
|
||||
// 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 = `<button class="view-tests-icon" title="View Generated Tests">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-text" viewBox="0 0 16 16">
|
||||
<path d="M4 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V5.5L9.5 0H4z"/>
|
||||
<path d="M9.5 0v4a1 1 0 0 0 1 1h4"/>
|
||||
<path d="M4.5 7a.5.5 0 0 1 .5.5v.5h5v-1h-5V7.5a.5.5 0 0 1 .5-.5z"/>
|
||||
</svg>
|
||||
</button>`;
|
||||
// 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 = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="gray" class="bi bi-file-text" viewBox="0 0 16 16">
|
||||
<path d="M4 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V5.5L9.5 0H4z"/>
|
||||
<path d="M9.5 0v4a1 1 0 0 0 1 1h4"/>
|
||||
<path d="M4.5 7a.5.5 0 0 1 .5.5v.5h5v-1h-5V7.5a.5.5 0 0 1 .5-.5z"/>
|
||||
</svg>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue