mirror of
https://github.com/zadam/trilium.git
synced 2026-02-27 00:53:35 +01:00
fix(server): LLM launcher & option still not removed
This commit is contained in:
parent
c735870b95
commit
22341bf0b1
@ -1,177 +0,0 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import App from "./support/app";
|
||||
|
||||
test.describe("AI Settings", () => {
|
||||
test("Should access settings page", async ({ page, context }) => {
|
||||
page.setDefaultTimeout(15_000);
|
||||
|
||||
const app = new App(page, context);
|
||||
await app.goto();
|
||||
|
||||
// Go to settings
|
||||
await app.goToSettings();
|
||||
|
||||
// Wait for navigation to complete
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Verify we're in settings by checking for common settings elements
|
||||
const settingsElements = page.locator('.note-split, .options-section, .component');
|
||||
await expect(settingsElements.first()).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Look for any content in the main area
|
||||
const mainContent = page.locator('.note-split:not(.hidden-ext)');
|
||||
await expect(mainContent).toBeVisible();
|
||||
|
||||
// Basic test passes - settings are accessible
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test("Should handle AI features if available", async ({ page, context }) => {
|
||||
const app = new App(page, context);
|
||||
await app.goto();
|
||||
|
||||
await app.goToSettings();
|
||||
|
||||
// Look for AI-related elements anywhere in settings
|
||||
const aiElements = page.locator('[class*="ai-"], [data-option*="ai"], input[name*="ai"]');
|
||||
const aiElementsCount = await aiElements.count();
|
||||
|
||||
if (aiElementsCount > 0) {
|
||||
// AI features are present, test basic interaction
|
||||
const firstAiElement = aiElements.first();
|
||||
await expect(firstAiElement).toBeVisible();
|
||||
|
||||
// If it's a checkbox, test toggling
|
||||
const elementType = await firstAiElement.getAttribute('type');
|
||||
if (elementType === 'checkbox') {
|
||||
const initialState = await firstAiElement.isChecked();
|
||||
await firstAiElement.click();
|
||||
|
||||
// Wait a moment for any async operations
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
const newState = await firstAiElement.isChecked();
|
||||
expect(newState).toBe(!initialState);
|
||||
|
||||
// Restore original state
|
||||
await firstAiElement.click();
|
||||
await page.waitForTimeout(500);
|
||||
}
|
||||
} else {
|
||||
// AI features not available - this is acceptable in test environment
|
||||
console.log("AI features not found in settings - this may be expected in test environment");
|
||||
}
|
||||
|
||||
// Test always passes - we're just checking if AI features work when present
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test("Should handle AI provider configuration if available", async ({ page, context }) => {
|
||||
const app = new App(page, context);
|
||||
await app.goto();
|
||||
|
||||
await app.goToSettings();
|
||||
|
||||
// Look for provider-related selects or inputs
|
||||
const providerSelects = page.locator('select[class*="provider"], select[name*="provider"]');
|
||||
const apiKeyInputs = page.locator('input[type="password"][class*="api"], input[type="password"][name*="key"]');
|
||||
|
||||
const hasProviderConfig = await providerSelects.count() > 0 || await apiKeyInputs.count() > 0;
|
||||
|
||||
if (hasProviderConfig) {
|
||||
// Provider configuration is available
|
||||
if (await providerSelects.count() > 0) {
|
||||
const firstSelect = providerSelects.first();
|
||||
await expect(firstSelect).toBeVisible();
|
||||
|
||||
// Test selecting different options if available
|
||||
const options = await firstSelect.locator('option').count();
|
||||
if (options > 1) {
|
||||
const firstOptionValue = await firstSelect.locator('option').nth(1).getAttribute('value');
|
||||
if (firstOptionValue) {
|
||||
await firstSelect.selectOption(firstOptionValue);
|
||||
await expect(firstSelect).toHaveValue(firstOptionValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (await apiKeyInputs.count() > 0) {
|
||||
const firstApiKeyInput = apiKeyInputs.first();
|
||||
await expect(firstApiKeyInput).toBeVisible();
|
||||
|
||||
// Test input functionality (without actually setting sensitive data)
|
||||
await firstApiKeyInput.fill('test-key-placeholder');
|
||||
await expect(firstApiKeyInput).toHaveValue('test-key-placeholder');
|
||||
|
||||
// Clear the test value
|
||||
await firstApiKeyInput.fill('');
|
||||
}
|
||||
} else {
|
||||
console.log("AI provider configuration not found - this may be expected in test environment");
|
||||
}
|
||||
|
||||
// Test always passes
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test("Should handle model configuration if available", async ({ page, context }) => {
|
||||
const app = new App(page, context);
|
||||
await app.goto();
|
||||
|
||||
await app.goToSettings();
|
||||
|
||||
// Look for model-related configuration
|
||||
const modelSelects = page.locator('select[class*="model"], select[name*="model"]');
|
||||
const temperatureInputs = page.locator('input[name*="temperature"], input[class*="temperature"]');
|
||||
|
||||
if (await modelSelects.count() > 0) {
|
||||
const firstModelSelect = modelSelects.first();
|
||||
await expect(firstModelSelect).toBeVisible();
|
||||
}
|
||||
|
||||
if (await temperatureInputs.count() > 0) {
|
||||
const temperatureInput = temperatureInputs.first();
|
||||
await expect(temperatureInput).toBeVisible();
|
||||
|
||||
// Test temperature setting (common AI parameter)
|
||||
await temperatureInput.fill('0.7');
|
||||
await expect(temperatureInput).toHaveValue('0.7');
|
||||
}
|
||||
|
||||
// Test always passes
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test("Should display settings interface correctly", async ({ page, context }) => {
|
||||
const app = new App(page, context);
|
||||
await app.goto();
|
||||
|
||||
await app.goToSettings();
|
||||
|
||||
// Wait for navigation to complete
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Verify basic settings interface elements exist
|
||||
const mainContent = page.locator('.note-split:not(.hidden-ext)');
|
||||
await expect(mainContent).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Look for common settings elements
|
||||
const forms = page.locator('form, .form-group, .options-section, .component');
|
||||
const inputs = page.locator('input, select, textarea');
|
||||
const labels = page.locator('label, .form-label');
|
||||
|
||||
// Wait for content to load
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Settings should have some form elements or components
|
||||
const formCount = await forms.count();
|
||||
const inputCount = await inputs.count();
|
||||
const labelCount = await labels.count();
|
||||
|
||||
// At least one of these should be present in settings
|
||||
expect(formCount + inputCount + labelCount).toBeGreaterThan(0);
|
||||
|
||||
// Basic UI structure test passes
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
@ -2,6 +2,7 @@ import { deferred, LOCALES } from "@triliumnext/commons";
|
||||
import { beforeAll, describe, expect, it } from "vitest";
|
||||
|
||||
import becca from "../becca/becca.js";
|
||||
import becca_loader from "../becca/becca_loader.js";
|
||||
import branches from "./branches.js";
|
||||
import cls from "./cls.js";
|
||||
import hiddenSubtreeService from "./hidden_subtree.js";
|
||||
@ -172,22 +173,24 @@ describe("Hidden Subtree", () => {
|
||||
it("cleans up item to be deleted", async () => {
|
||||
const noteId = "_lbLlmChat";
|
||||
let llmNote = becca.getNote(noteId);
|
||||
if (!llmNote) {
|
||||
llmNote = notes.createNewNote({
|
||||
parentNoteId: "_lbVisibleLaunchers",
|
||||
noteId,
|
||||
title: "LLM chat",
|
||||
type: "launcher",
|
||||
content: ""
|
||||
}).note;
|
||||
}
|
||||
|
||||
cls.init(() => hiddenSubtreeService.checkHiddenSubtree());
|
||||
expect(llmNote.isDeleted).toBeTruthy();
|
||||
cls.init(() => {
|
||||
if (!llmNote) {
|
||||
llmNote = notes.createNewNote({
|
||||
parentNoteId: "_lbVisibleLaunchers",
|
||||
noteId,
|
||||
title: "LLM chat",
|
||||
type: "launcher",
|
||||
content: ""
|
||||
}).note;
|
||||
}
|
||||
|
||||
// Check twice for idempotency.
|
||||
cls.init(() => hiddenSubtreeService.checkHiddenSubtree());
|
||||
expect(llmNote.isDeleted).toBeTruthy();
|
||||
hiddenSubtreeService.checkHiddenSubtree();
|
||||
becca_loader.reload("test");
|
||||
});
|
||||
|
||||
llmNote = becca.getNote(noteId);
|
||||
expect(llmNote).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -4,6 +4,7 @@ import { t } from "i18next";
|
||||
import becca from "../becca/becca.js";
|
||||
import BAttribute from "../becca/entities/battribute.js";
|
||||
import BBranch from "../becca/entities/bbranch.js";
|
||||
import BNote from "../becca/entities/bnote.js";
|
||||
import buildLaunchBarConfig from "./hidden_subtree_launcherbar.js";
|
||||
import buildHiddenSubtreeTemplates from "./hidden_subtree_templates.js";
|
||||
import { cleanUpHelp, getHelpHiddenSubtreeData } from "./in_app_help.js";
|
||||
@ -246,7 +247,7 @@ function buildHiddenSubtreeDefinition(helpSubtree: HiddenSubtreeItem[]): HiddenS
|
||||
{ id: "_optionsEtapi", title: t("hidden-subtree.etapi-title"), type: "contentWidget", icon: "bx-extension" },
|
||||
{ id: "_optionsBackup", title: t("hidden-subtree.backup-title"), type: "contentWidget", icon: "bx-data" },
|
||||
{ id: "_optionsSync", title: t("hidden-subtree.sync-title"), type: "contentWidget", icon: "bx-wifi" },
|
||||
|
||||
{ id: "_optionsAi", title: "AI Chat", type: "contentWidget", enforceDeleted: true },
|
||||
{ id: "_optionsOther", title: t("hidden-subtree.other"), type: "contentWidget", icon: "bx-dots-horizontal" },
|
||||
{ id: "_optionsLocalization", title: t("hidden-subtree.localization"), type: "contentWidget", icon: "bx-world" },
|
||||
{ id: "_optionsAdvanced", title: t("hidden-subtree.advanced-title"), type: "contentWidget" }
|
||||
@ -341,8 +342,13 @@ function checkHiddenSubtreeRecursively(parentNoteId: string, item: HiddenSubtree
|
||||
throw new Error(`ID has to start with underscore, given '${item.id}'`);
|
||||
}
|
||||
|
||||
let note = becca.notes[item.id];
|
||||
let branch;
|
||||
let note = becca.notes[item.id] as BNote | undefined;
|
||||
let branch: BBranch | undefined;
|
||||
|
||||
if (item.enforceDeleted) {
|
||||
note?.deleteNote();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!note) {
|
||||
// Missing item, add it.
|
||||
@ -363,9 +369,7 @@ function checkHiddenSubtreeRecursively(parentNoteId: string, item: HiddenSubtree
|
||||
note.setContent(item.content);
|
||||
}
|
||||
|
||||
if (item.enforceDeleted) {
|
||||
note.deleteNote();
|
||||
} else if (item.enforceBranches || item.id.startsWith("_help")) {
|
||||
if (item.enforceBranches || item.id.startsWith("_help")) {
|
||||
// Clean up any branches that shouldn't exist according to the meta definition
|
||||
// For hidden subtree notes, we want to ensure they only exist in their designated locations
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user