Refinement-Runde Panel/Wiki: Bedienung, Themes, Archiv-Wahl, Frontend-Tests
- Slug transliteriert Umlaute/ß (fuer statt f-r); aktiver Tab mit Akzent + Unterstrich; kein aktiver Tab bei zugeklapptem Panel (mode.clear) - Suche: Live-Update auch beim Löschen (<3 Zeichen: Hinweis), #tag-Filter in der Query, Treffer öffnen im Dokument-Tab (panel_load, ohne Frontmatter); Wiki-Sprung-Button im Dokument; Wiki-Fehler sichtbar als Toast - Archiv-Formular am Archiv-Button (Ordner/Beschreibung/Schlagwörter); panel_archive_cmd nimmt Meta entgegen - Wiki-Übersicht: Zuletzt-Sektion, Backlink-Zähler, Wurzel-Eyebrow - Themes: Panel-Farben über CSS-Variablen, applyTheme leitet sie aus dem jeweiligen Theme ab (auch helle); gemeinsames themes.ts - Fenster: Doppelklick maximiert; gelöstes Fenster merkt Größe/Position (Window-ACL: set-position/outer-position/inner-size ergänzt); open_panel_window async (GTK-Deadlock-Vorgabe); Panel-Fenster spiegelt JS-Fehler ins Dev-Log - Archiv pro Projekt wähl-/abwählbar (Einstellungsdialog, setzt/entfernt Permissions); require_archive_home legt den Ordner an; ohne Archiv nur Befehle+Dokument im Panel - Frontend-Tests: vitest + happy-dom, 27 Tests über Modus-, Such-, Wiki-, Editor- und Formular-Logik (npm test)
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
// Modus-Logik (Tabs) und Kachel-Ansicht der Befehls-History.
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { initCommandsView, initPanelMode } from "./commands-view";
|
||||
|
||||
function modeSetup() {
|
||||
document.body.innerHTML = `
|
||||
<div id="tabs">
|
||||
<button data-mode="commands">Befehle</button>
|
||||
<button data-mode="draft">Dokument</button>
|
||||
<button data-mode="wiki">Wiki</button>
|
||||
<button data-mode="search">Suche</button>
|
||||
</div>
|
||||
<div id="title">Mein Titel</div>
|
||||
<div id="draft-el"></div>
|
||||
<div id="cc" hidden></div>
|
||||
<div id="sc" hidden></div>
|
||||
<div id="wc" hidden></div>`;
|
||||
const el = (id: string) => document.getElementById(id)!;
|
||||
const flush = vi.fn();
|
||||
const mode = initPanelMode({
|
||||
tabsEl: el("tabs"),
|
||||
draftEls: [el("draft-el")],
|
||||
commandsContent: el("cc"),
|
||||
searchContent: el("sc"),
|
||||
wikiContent: el("wc"),
|
||||
titleEl: el("title"),
|
||||
flush,
|
||||
});
|
||||
const tab = (m: string) =>
|
||||
document.querySelector<HTMLElement>(`[data-mode="${m}"]`)!;
|
||||
return { mode, flush, el, tab };
|
||||
}
|
||||
|
||||
describe("initPanelMode", () => {
|
||||
it("startet im Dokument-Modus mit aktivem Tab", () => {
|
||||
const { el, tab } = modeSetup();
|
||||
expect(el("draft-el").hidden).toBe(false);
|
||||
expect(el("cc").hidden).toBe(true);
|
||||
expect(tab("draft").classList.contains("active")).toBe(true);
|
||||
});
|
||||
|
||||
it("wechselt Sichtbarkeit, Titel und aktive Markierung", () => {
|
||||
const { mode, flush, el, tab } = modeSetup();
|
||||
mode.to("commands");
|
||||
expect(flush).toHaveBeenCalledOnce();
|
||||
expect(el("cc").hidden).toBe(false);
|
||||
expect(el("draft-el").hidden).toBe(true);
|
||||
expect(el("title").textContent).toBe("Befehle");
|
||||
expect(tab("commands").classList.contains("active")).toBe(true);
|
||||
expect(tab("draft").classList.contains("active")).toBe(false);
|
||||
mode.to("draft");
|
||||
expect(el("title").textContent).toBe("Mein Titel");
|
||||
});
|
||||
|
||||
it("Tab-Klick wechselt den Modus", () => {
|
||||
const { el, tab } = modeSetup();
|
||||
tab("wiki").click();
|
||||
expect(el("wc").hidden).toBe(false);
|
||||
expect(el("draft-el").hidden).toBe(true);
|
||||
});
|
||||
|
||||
it("clear hebt die Auswahl auf; danach wählt to() wieder aus", () => {
|
||||
const { mode, el, tab } = modeSetup();
|
||||
mode.clear();
|
||||
expect(document.querySelectorAll(".active").length).toBe(0);
|
||||
expect(mode.current()).toBe(null);
|
||||
mode.to("draft");
|
||||
expect(tab("draft").classList.contains("active")).toBe(true);
|
||||
expect(el("title").textContent).toBe("Mein Titel");
|
||||
});
|
||||
});
|
||||
|
||||
describe("initCommandsView", () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = `<div id="c"></div>`;
|
||||
});
|
||||
|
||||
const jsonl = [
|
||||
JSON.stringify({ ts: 1700000000, session: true }),
|
||||
JSON.stringify({
|
||||
ts: 1700000100,
|
||||
commands: [{ cmd: "ls -la", note: "Liste" }, { cmd: "pwd" }],
|
||||
}),
|
||||
].join("\n");
|
||||
|
||||
it("rendert Kacheln, Session-Trenner und meldet empty korrekt", () => {
|
||||
const view = initCommandsView(document.getElementById("c")!, () => {});
|
||||
view.set(jsonl);
|
||||
expect(view.empty()).toBe(false);
|
||||
expect(document.querySelectorAll(".cmd-tile").length).toBe(2);
|
||||
expect(document.querySelectorAll(".cmd-sep").length).toBe(1);
|
||||
expect(document.querySelector(".cmd-text")!.textContent).toBe("ls -la");
|
||||
view.set("");
|
||||
expect(view.empty()).toBe(true);
|
||||
});
|
||||
|
||||
it("meldet Löschen mit Record- und Eintrags-Index", () => {
|
||||
const onDelete = vi.fn();
|
||||
const view = initCommandsView(document.getElementById("c")!, onDelete);
|
||||
view.set(jsonl);
|
||||
const dels = document.querySelectorAll<HTMLElement>(".cmd-del");
|
||||
dels[1].click(); // zweite Kachel im Record 1
|
||||
expect(onDelete).toHaveBeenCalledWith(1, 1);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user