fix(notes): søgningen svarede med det forkerte først, og et træk gjorde ingenting
Release / Build and publish image (push) Failing after 9m55s

**Søgningen sorterede efter dato.** Usynligt med ti noter og ubrugeligt med tolv
hundrede: de blev alle importeret samme aften, så `updated_at` siger ingenting, og
loftet skar listen af ved halvtreds vilkårlige rækker. At søge "Tesla" svarede med
en note om nginx først og noten, der hedder "Tesla Model Y", bagefter — hvilket
læses som en søgning, der ikke virker, fordi det fra brugerens plads er præcis
dét.

Nu bm25, med titlen vægtet ti gange kroppen: et ord i titlen er, hvad noten
*handler om*, mens det samme ord én gang i en lang krop er en henvisning. `fold`
vejer som kroppen, ellers ville et dansk match slå et præcist. Sammenføjet frem
for `rowid IN (…)`, fordi rangeringen hører til matchet, og en underforespørgsel
smider den væk. Fladen sorterer ikke om, når der er søgt — det ville kaste netop
det væk, der gør en søgning i tolv hundrede noter brugbar.

**Et træk af en note hen på et projekt gjorde ingenting.** `ondragover` tog imod
både opgaver og noter, så rækken lyste op — og `ondrop` sendte kun opgaver videre,
mens noten faldt ned i grenen, der omarrangerer projekter, hvor den ikke betyder
noget. Den værst mulige form for i stykker: den så ud, som om den ville virke,
helt indtil man slap.

Det står i overleveringen som "virker i koden, men ikke fastholdt i prøver, fordi
prøven blev upålidelig". Den er skrevet igen, og den ser på resultatet — ligger
noten i projektet bagefter — frem for på om rækken blev fremhævet, hvilket var
netop det, den gamle kunne se og som blev ved med at være sandt, mens funktionen
var i stykker.

**Og datoen i listen var altid `updated_at`.** For tolv hundrede importerede noter
er det i aftes, så en note fra 2017 stod som "i går", og den dato, man sorterede
efter, var ingen steder at se. Rækken viser nu den dato, listen er sorteret efter,
og har begge i sit værktøjstip.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kristian Wind
2026-08-20 09:58:41 +02:00
co-authored by Claude Opus 5
parent 4aa8bd6a40
commit 3a02bc8304
5 changed files with 165 additions and 13 deletions
+54
View File
@@ -2740,3 +2740,57 @@ test('en note kan oprettes inde fra et projekt og hører til det med det samme',
expect(trouble).toEqual([]);
});
test('en note kan trækkes hen på et projekt i sidebjælken', async ({ page }) => {
const trouble = watchForTrouble(page);
const sidebar = page.getByRole('navigation', { name: 'Hovedmenu' });
await page.goto('/');
await sidebar.getByLabel('Nyt projekt').click();
await sidebar.getByLabel('Projektnavn').fill('Trækmål');
await sidebar.getByLabel('Projektnavn').press('Enter');
await expect(sidebar.getByRole('link', { name: 'Trækmål' })).toBeVisible();
const id = await page.evaluate(async () => {
const r = await fetch('/api/v1/notes', {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json', 'Sec-Fetch-Site': 'same-origin' },
body: JSON.stringify({ body: '# Løs note\n\nSkal flyttes ved at trække.\n' })
});
return (await r.json()).id;
});
await page.goto('/noter?note=' + id);
await page.evaluate((noteId) => (window.__noteId = noteId), id);
const row = page.locator('.notes button.row').filter({ hasText: 'Løs note' }).first();
await expect(row).toBeVisible();
// Selve gesten, med de rigtige hændelser og den nyttelast, appen sender.
// Rækken tog imod dragover og lod slippet falde ned i grenen, der omarrangerer
// projekter — så den lyste op og gjorde ingenting. Prøven skal derfor gå hele
// vejen til slippet og se på resultatet, ikke på at rækken blev fremhævet.
await page.evaluate(() => {
const dt = new DataTransfer();
dt.setData('application/x-verdande-note', window.__noteId);
const target = [...document.querySelectorAll('nav a')].find((a) =>
a.textContent.includes('Trækmål')
);
for (const type of ['dragover', 'drop']) {
target.dispatchEvent(new DragEvent(type, { dataTransfer: dt, bubbles: true, cancelable: true }));
}
});
await page.waitForTimeout(1000);
// Det, der tæller: noten ligger i projektet bagefter.
const body = await page.evaluate(async (noteId) => {
const r = await fetch('/api/v1/notes/' + noteId, {
credentials: 'include',
headers: { 'Sec-Fetch-Site': 'same-origin' }
});
return await r.json();
}, id);
expect(body.project_id).toBeTruthy();
expect(trouble).toEqual([]);
});