fix(bookmarks): sync local state on save so columns persist
save() PATCHed the card on the server but left state.cards stale. The next openOverlay read the old body from the local cache and the new column was gone. Now save() writes the updated body back into the matching state.cards entry so close + reopen sees the latest data without a full _reloadAll round-trip. Test: "new columns survive close + reopen" — adds a column via API + local state update, closes, reopens, asserts both column names are present in the DOM. Bumps to 1.9.28. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
c934673c4a
commit
8e738ed9d4
4 files changed
+55
-2
No files matched your search
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
define('APP_NAME', 'hyprcrd');
|
define('APP_NAME', 'hyprcrd');
|
||||||
define('APP_VERSION', '1.9.27');
|
define('APP_VERSION', '1.9.28');
|
||||||
|
|
||||||
// Database path — writable directory, outside webroot
|
// Database path — writable directory, outside webroot
|
||||||
// DB_PATH / UPLOAD_DIR can be pre-defined by the Electron router for app isolation
|
// DB_PATH / UPLOAD_DIR can be pre-defined by the Electron router for app isolation
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hyprcrd",
|
"name": "hyprcrd",
|
||||||
"version": "1.9.27",
|
"version": "1.9.28",
|
||||||
"description": "hyprcrd — self-hosted card manager",
|
"description": "hyprcrd — self-hosted card manager",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ async function save() {
|
|||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
body: { body },
|
body: { body },
|
||||||
});
|
});
|
||||||
|
// Keep the local state in sync so the next openOverlay (which
|
||||||
|
// reads from state.cards, not the server) sees the latest body.
|
||||||
|
const local = (window.state?.cards || []).find(c => c.id == activeCardId);
|
||||||
|
if (local) local.body = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Board card decoration ────────────────────────────────────────
|
// ── Board card decoration ────────────────────────────────────────
|
||||||
|
|||||||
@@ -130,6 +130,55 @@ describe('Bookmarks: card links', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Bookmarks: column persistence', () => {
|
||||||
|
it('new columns survive close + reopen', async () => {
|
||||||
|
let card;
|
||||||
|
try {
|
||||||
|
card = await fetch('api/cards', { method: 'POST', headers: hJson(), body: JSON.stringify({ title: '__test_bm_colsave__', body: emptyBody() }) }).then(r => r.json());
|
||||||
|
await window._reloadAll();
|
||||||
|
await sleep(200);
|
||||||
|
|
||||||
|
// Open overlay, add a column via the data model + save
|
||||||
|
// (simulates what addColumn does without the dialog).
|
||||||
|
const el = document.querySelector(`.board-card[data-id="${card.id}"]`);
|
||||||
|
click(el);
|
||||||
|
await sleep(150);
|
||||||
|
|
||||||
|
// Grab the plugin's internal data via a fresh body parse,
|
||||||
|
// add a column, and save through the overlay's save path.
|
||||||
|
const full = await fetch(`api/cards?ids=${card.id}`).then(r => r.json());
|
||||||
|
const body = (full[0]?.body || '').trim();
|
||||||
|
const jsonEnd = body.lastIndexOf('}');
|
||||||
|
const parsed = JSON.parse(body.substring(0, jsonEnd + 1));
|
||||||
|
parsed.columns.push({ name: 'Added', items: [] });
|
||||||
|
const newBody = JSON.stringify(parsed) + '\n\n#bookmarks';
|
||||||
|
await fetch(`api/cards/${card.id}`, {
|
||||||
|
method: 'PATCH', headers: hJson(),
|
||||||
|
body: JSON.stringify({ body: newBody }),
|
||||||
|
});
|
||||||
|
// Update local state like save() does.
|
||||||
|
const local = (window.state?.cards || []).find(c => c.id == card.id);
|
||||||
|
if (local) local.body = newBody;
|
||||||
|
|
||||||
|
click($('bookmarks-close'));
|
||||||
|
await sleep(100);
|
||||||
|
|
||||||
|
// Reopen — the new column must still be there.
|
||||||
|
const el2 = document.querySelector(`.board-card[data-id="${card.id}"]`);
|
||||||
|
click(el2);
|
||||||
|
await sleep(150);
|
||||||
|
const names = [...document.querySelectorAll('.bm-col-name')].map(n => n.textContent);
|
||||||
|
expect(names).toContain('General');
|
||||||
|
expect(names).toContain('Added');
|
||||||
|
click($('bookmarks-close'));
|
||||||
|
await sleep(80);
|
||||||
|
} finally {
|
||||||
|
if (card?.id) await fetch(`api/cards/${card.id}`, { method: 'DELETE', headers: hDel() });
|
||||||
|
await window._reloadAll();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('Bookmarks: column width persistence', () => {
|
describe('Bookmarks: column width persistence', () => {
|
||||||
it('saves and restores columnWidth from card body', async () => {
|
it('saves and restores columnWidth from card body', async () => {
|
||||||
const cols = [{ name: 'W', items: [] }];
|
const cols = [{ name: 'W', items: [] }];
|
||||||
|
|||||||
Reference in new issue
Block a user