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
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:
co-authored by
Claude Opus 5
parent
4aa8bd6a40
commit
3a02bc8304
@@ -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([]);
|
||||
});
|
||||
|
||||
@@ -363,6 +363,15 @@
|
||||
overProject = project.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Et slip på et projekt, uanset hvad der bliver sluppet.
|
||||
*
|
||||
* Rækken kaldte den her for opgaver og lod noter falde ned i grenen, der
|
||||
* omarrangerer projekter — hvor en note ikke betyder noget. Samtidig tog
|
||||
* `onTaskDragOver` imod begge, så rækken lyste op, når en note blev trukket hen
|
||||
* over den. Den værst mulige form for i stykker: den så ud, som om den ville
|
||||
* virke, helt indtil man slap.
|
||||
*/
|
||||
async function onTaskDrop(event, project) {
|
||||
event.preventDefault();
|
||||
overProject = null;
|
||||
@@ -569,14 +578,17 @@
|
||||
ondragstart={(e) => sortable && onDragStart(e, project)}
|
||||
ondragend={clearDrag}
|
||||
ondragover={(e) => {
|
||||
if (carries(e, TASK)) onTaskDragOver(e, project);
|
||||
if (carries(e, TASK) || carries(e, NOTE)) onTaskDragOver(e, project);
|
||||
else if (sortable) onDragOver(e, project);
|
||||
}}
|
||||
ondragleave={() => {
|
||||
overId = null;
|
||||
overProject = null;
|
||||
}}
|
||||
ondrop={(e) => (carries(e, TASK) ? onTaskDrop(e, project) : sortable && onDrop(e, project))}
|
||||
ondrop={(e) =>
|
||||
carries(e, TASK) || carries(e, NOTE)
|
||||
? onTaskDrop(e, project)
|
||||
: sortable && onDrop(e, project)}
|
||||
>
|
||||
<span class="dot" style="background: {colorVar(project.color)}" aria-hidden="true"></span>
|
||||
{projectName(project)}
|
||||
|
||||
@@ -53,7 +53,16 @@
|
||||
|
||||
// Favoritter står øverst uanset rækkefølge. Det er hele meningen med at gøre en
|
||||
// note til favorit, og en sortering, der blandede dem ind igen, ville tage den.
|
||||
let ordered = $derived(
|
||||
let ordered = $derived.by(() => {
|
||||
// En søgning har allerede en rækkefølge, og den er bedre end nogen af de
|
||||
// tre herunder: serveren har sorteret efter hvor godt hver note matchede.
|
||||
// Sorterede vi den om efter dato, ville vi kaste netop det væk, der gør en
|
||||
// søgning i tolv hundrede noter brugbar.
|
||||
if (query.trim()) return notes;
|
||||
return sortedByChoice();
|
||||
});
|
||||
|
||||
const sortedByChoice = () =>
|
||||
[...notes].sort((a, b) => {
|
||||
if (a.pinned !== b.pinned) return a.pinned ? -1 : 1;
|
||||
if (order === 'title') {
|
||||
@@ -61,8 +70,7 @@
|
||||
}
|
||||
const field = order === 'created' ? 'created_at' : 'updated_at';
|
||||
return new Date(b[field]).getTime() - new Date(a[field]).getTime();
|
||||
})
|
||||
);
|
||||
});
|
||||
let selected = $state(null);
|
||||
let query = $state('');
|
||||
let status = $state('loading');
|
||||
@@ -151,6 +159,14 @@
|
||||
return at.toLocaleDateString(tag(), { day: '2-digit', month: '2-digit', year: 'numeric' });
|
||||
}
|
||||
|
||||
/** Hvilken dato rækken viser: den, der sorteres efter. */
|
||||
const shownDate = (note) => (order === 'created' ? note.created_at : note.updated_at);
|
||||
|
||||
/** Begge datoer, til den, der holder musen stille. */
|
||||
const stamp = (note) =>
|
||||
`${t('notes.sortCreated')}: ${new Date(note.created_at).toLocaleString(tag())}\n` +
|
||||
`${t('notes.sortUpdated')}: ${new Date(note.updated_at).toLocaleString(tag())}`;
|
||||
|
||||
function projectName(id) {
|
||||
return app.projects.find((p) => p.id === id)?.name ?? '';
|
||||
}
|
||||
@@ -329,7 +345,12 @@
|
||||
linjer pr. note frem for tre, og datoen er dét, man skanner
|
||||
efter, når man leder efter noget, man skrev i tirsdags. -->
|
||||
<span class="under">
|
||||
<span class="when">{when(note.updated_at)}</span>
|
||||
<!-- Datoen, der svarer til den rækkefølge, listen står i.
|
||||
Den viste altid `updated_at`, og 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. -->
|
||||
<span class="when" title={stamp(note)}>{when(shownDate(note))}</span>
|
||||
<span class="preview">{plain(note.body)}</span>
|
||||
</span>
|
||||
{#if note.project_id}
|
||||
|
||||
Reference in New Issue
Block a user