diff --git a/zddc/internal/apps/embedded/archive.html b/zddc/internal/apps/embedded/archive.html index 67ca152..c2f582a 100644 --- a/zddc/internal/apps/embedded/archive.html +++ b/zddc/internal/apps/embedded/archive.html @@ -2582,7 +2582,7 @@ td[data-field="trackingNumber"] {
ZDDC Archive - v0.0.26 + v0.0.27-beta · 2026-06-01 18:30:53 · 5ed4f85
diff --git a/zddc/internal/apps/embedded/browse.html b/zddc/internal/apps/embedded/browse.html index 9818095..db04d6a 100644 --- a/zddc/internal/apps/embedded/browse.html +++ b/zddc/internal/apps/embedded/browse.html @@ -2476,7 +2476,7 @@ body {
ZDDC Browse - v0.0.26 + v0.0.27-beta · 2026-06-01 18:30:54 · 5ed4f85
@@ -9511,9 +9511,14 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr // .zddc files without diverting into the editor. User // clicks (or tabs) into the editor when they want to type. autofocus: false, - // CodeMirror's "nocursor" mode is the truest read-only: - // selection allowed for copy, no caret, no edit affordances. - readOnly: !writable ? 'nocursor' : false, + // Read-only uses readOnly:true (NOT "nocursor"): the editor + // stays focusable so the user can click in, select text, and + // copy — they just can't edit. "nocursor" removes the textarea + // from focus, which also kills click-drag selection (the whole + // reason a viewer would otherwise force admin mode just to copy + // a .zddc snippet). autofocus:false keeps arrow-key tree nav + // intact until the user deliberately clicks into the editor. + readOnly: !writable, }); // Stash the node on the editor so the lint helper can decide // whether to apply the .zddc schema layer. @@ -9681,6 +9686,24 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr return 'File'; } + var VERB_NAMES = { r: 'read', w: 'write', c: 'create', d: 'delete', a: 'admin' }; + function verbsLabel(verbs) { + return ['r', 'w', 'c', 'd', 'a'] + .filter(function (v) { return verbs.indexOf(v) !== -1; }) + .map(function (v) { return VERB_NAMES[v]; }) + .join(', '); + } + // permsValue renders the per-entry verb set the principal holds here. + // Server mode: node.verbs ("rwcda" subset). Offline (FS-API) mode has + // no ACL — access is whatever the filesystem grants. + function permsValue(verbs) { + if (typeof verbs !== 'string') { + return state.source === 'fs' ? 'local folder (filesystem)' : 'unknown'; + } + if (!verbs) return 'none (read-only)'; + return verbsLabel(verbs) + ' (' + verbs + ')'; + } + function buildRowsHtml(node) { var tree = window.app.modules.tree; var z = window.zddc; @@ -9739,6 +9762,18 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr if (node.modTime) html += kv('Modified', fmtDate(node.modTime)); if (node.virtual) html += kv('Virtual', 'Not yet created on disk'); + // ── Effective access for the current principal at this location ── + // "Your permissions" is the per-entry verb set (sync, from the + // listing). "Your roles" is cascade-scoped — it can differ by + // location — so it needs a path-scoped fetch; render a placeholder + // that fillRoles() updates once /.profile/access?path= resolves. + html += '
'; + html += kv('Your permissions', permsValue(node.verbs)); + if (state.source === 'server') { + html += 'Your roles' + + ''; + } + // Path comes last (longest, most likely to wrap). var path = tree ? tree.pathFor(node) : ''; if (path) html += kv('Path', path, true); @@ -9831,6 +9866,25 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr render(node); position(row); card.classList.add('is-visible'); + fillRoles(row, node); + } + + // Async-fill the "Your roles" row from the path-scoped access view + // (zddc.cap.at memoises per path, so repeat hovers are instant). + // Bails if the card has moved to another row before the fetch lands. + async function fillRoles(row, node) { + if (state.source !== 'server') return; + if (!window.zddc || !window.zddc.cap) return; + var tree = window.app.modules.tree; + var path = tree ? tree.pathFor(node) : ''; + if (!path) return; + var view; + try { view = await window.zddc.cap.at(path); } catch (_e) { return; } + if (currentRow !== row) return; + var el = card && card.querySelector('#hc-roles'); + if (!el) return; + var roles = (view && Array.isArray(view.path_roles)) ? view.path_roles : []; + el.textContent = roles.length ? roles.join(', ') : 'none'; } function init() { diff --git a/zddc/internal/apps/embedded/classifier.html b/zddc/internal/apps/embedded/classifier.html index d48a531..f4ffd63 100644 --- a/zddc/internal/apps/embedded/classifier.html +++ b/zddc/internal/apps/embedded/classifier.html @@ -1793,7 +1793,7 @@ body.is-elevated::after {
ZDDC Classifier - v0.0.26 + v0.0.27-beta · 2026-06-01 18:30:54 · 5ed4f85
diff --git a/zddc/internal/apps/embedded/index.html b/zddc/internal/apps/embedded/index.html index 04eea72..831e6ff 100644 --- a/zddc/internal/apps/embedded/index.html +++ b/zddc/internal/apps/embedded/index.html @@ -1536,7 +1536,7 @@ body {
ZDDC - v0.0.26 + v0.0.27-beta · 2026-06-01 18:30:54 · 5ed4f85
diff --git a/zddc/internal/apps/embedded/transmittal.html b/zddc/internal/apps/embedded/transmittal.html index 13d1d4f..756a834 100644 --- a/zddc/internal/apps/embedded/transmittal.html +++ b/zddc/internal/apps/embedded/transmittal.html @@ -2635,7 +2635,7 @@ dialog.modal--narrow {
ZDDC Transmittal - v0.0.26 + v0.0.27-beta · 2026-06-01 18:30:53 · 5ed4f85
JavaScript not available