fix(browse): don't inject front matter on open; no conflict modal on rename
Two fixes to the markdown editor's identity handling: - Sync-on-open now only RECONCILES front-matter identity keys the author already wrote (correcting a stale title/revision/…); it never ADDS them. A blank or new file opens blank instead of getting an auto-generated title at the top. The converter derives identity from the filename regardless, so an empty front matter needs nothing baked in. (Cancel/revert likewise only touches existing keys.) - The "Rename file & reopen" flow force-writes the buffer (no If-Match) instead of routing through save(), which raised the conflict-resolution modal on a (spurious) 412. The rename is a deliberate user action and the identity edit that triggered it is consumed by the new filename, so we commit the buffer rather than interrupting with a merge dialog. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
cfe379d4f9
commit
84f93ba56d
1 changed files with 34 additions and 10 deletions
|
|
@ -603,16 +603,22 @@
|
||||||
// even if we tweak whitespace in the YAML lines.
|
// even if we tweak whitespace in the YAML lines.
|
||||||
var initialParsed = parseFrontMatter(text);
|
var initialParsed = parseFrontMatter(text);
|
||||||
var bodyText = initialParsed.body;
|
var bodyText = initialParsed.body;
|
||||||
// On open, mirror the filename-derived identity into the front matter
|
// On open, RECONCILE existing front-matter identity keys with the
|
||||||
// (the filename is the single source of truth; this keeps the values
|
// filename (the single source of truth) — but never ADD them. A blank
|
||||||
// baked in for the converter). No-op for non-ZDDC filenames. The dirty
|
// or new file opens blank (we don't inject a title etc.); a file whose
|
||||||
|
// author already wrote a now-stale title/revision/… gets corrected.
|
||||||
|
// The converter derives identity from the filename regardless, so
|
||||||
|
// there's nothing to "bake in" for an empty front matter. The dirty
|
||||||
// baseline stays the ON-DISK state, so a correction opens the buffer
|
// baseline stays the ON-DISK state, so a correction opens the buffer
|
||||||
// dirty and a save persists it.
|
// dirty and a save persists it.
|
||||||
var onDiskFM = stringifyFrontMatter(initialParsed.data);
|
var onDiskFM = stringifyFrontMatter(initialParsed.data);
|
||||||
var fid = filenameIdentity(node.name);
|
var fid = filenameIdentity(node.name);
|
||||||
if (fid) {
|
if (fid) {
|
||||||
for (var ik in fid) {
|
for (var ik in fid) {
|
||||||
if (Object.prototype.hasOwnProperty.call(fid, ik)) initialParsed.data[ik] = fid[ik];
|
if (Object.prototype.hasOwnProperty.call(fid, ik)
|
||||||
|
&& Object.prototype.hasOwnProperty.call(initialParsed.data, ik)) {
|
||||||
|
initialParsed.data[ik] = fid[ik];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var syncedFM = stringifyFrontMatter(initialParsed.data);
|
var syncedFM = stringifyFrontMatter(initialParsed.data);
|
||||||
|
|
@ -891,7 +897,10 @@
|
||||||
if (!fid) return;
|
if (!fid) return;
|
||||||
var data = parseFrontMatter('---\n' + fmCM.getValue() + '\n---\n').data || {};
|
var data = parseFrontMatter('---\n' + fmCM.getValue() + '\n---\n').data || {};
|
||||||
for (var k in fid) {
|
for (var k in fid) {
|
||||||
if (Object.prototype.hasOwnProperty.call(fid, k)) data[k] = fid[k];
|
if (Object.prototype.hasOwnProperty.call(fid, k)
|
||||||
|
&& Object.prototype.hasOwnProperty.call(data, k)) {
|
||||||
|
data[k] = fid[k];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fmCM.setValue(stringifyFrontMatter(data));
|
fmCM.setValue(stringifyFrontMatter(data));
|
||||||
var body = editor.getMarkdown();
|
var body = editor.getMarkdown();
|
||||||
|
|
@ -909,11 +918,26 @@
|
||||||
async function renameToMatch(newName) {
|
async function renameToMatch(newName) {
|
||||||
var up = window.app.modules.upload;
|
var up = window.app.modules.upload;
|
||||||
if (!up || !up.renameNode || !newName) return;
|
if (!up || !up.renameNode || !newName) return;
|
||||||
// 1. Save first so body/FM edits survive the rename. A failed save
|
// 1. Persist the current buffer first so body edits survive the
|
||||||
// (conflict, ACL) leaves the buffer dirty — abort the rename.
|
// rename. Force the write (no If-Match) — the user deliberately
|
||||||
if (instance.dirty) {
|
// initiated this rename, so we commit their version rather than
|
||||||
await save();
|
// interrupting with the conflict-resolution modal (which save()
|
||||||
if (currentInstance !== instance || instance.dirty) return;
|
// raises on a 412). The identity edit that triggered the rename
|
||||||
|
// is consumed by the new filename, so there's nothing to merge.
|
||||||
|
if (instance.dirty && canSave(node)) {
|
||||||
|
try {
|
||||||
|
var content = assembleContent(fmCM.getValue(), editor.getMarkdown());
|
||||||
|
statusEl.textContent = 'Saving…';
|
||||||
|
var res = await saveContent(node, content, { force: true });
|
||||||
|
await markSaved(content, res);
|
||||||
|
if (currentInstance !== instance) return;
|
||||||
|
} catch (e) {
|
||||||
|
statusEl.textContent = '';
|
||||||
|
if (window.zddc && window.zddc.toast) {
|
||||||
|
window.zddc.toast('Save failed: ' + (e.message || e), 'error');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 2. Rename on disk.
|
// 2. Rename on disk.
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue