diff --git a/tables/js/main.js b/tables/js/main.js index 2171d19..d395b52 100644 --- a/tables/js/main.js +++ b/tables/js/main.js @@ -125,6 +125,33 @@ addRowBtn.addEventListener('keydown', function (ev) { if (ev.key === 'Enter' || ev.key === ' ') handleAdd(ev); }); + + // Permission gate: fetch the path-scoped verbs for the + // current directory and disable + Add row when the + // cascade denies create. Async — the button shows up + // optimistically and disables a tick later if the + // server says no, which is the same race window every + // path-scoped fetch has. Server still gates the POST, + // so the worst case is a 403 toast on click. + if (window.zddc && window.zddc.cap) { + window.zddc.cap.at(location.pathname).then(function (view) { + if (!view) return; + var verbs = view.path_verbs || ''; + if (verbs.indexOf('c') === -1) { + addRowBtn.classList.add('is-disabled'); + addRowBtn.setAttribute('aria-disabled', 'true'); + addRowBtn.title = "You don't have create access in this folder."; + // Swallow clicks so the no-op feedback is the + // tooltip, not a 403 toast on submission. + addRowBtn.addEventListener('click', function (ev) { + if (addRowBtn.classList.contains('is-disabled')) { + ev.preventDefault(); + ev.stopPropagation(); + } + }, true); + } + }); + } } } diff --git a/tables/js/save.js b/tables/js/save.js index 2dffcaf..79503ad 100644 --- a/tables/js/save.js +++ b/tables/js/save.js @@ -316,6 +316,17 @@ return { status: 'invalid', errors: errs }; } + if (resp.status === 403) { + setRowState(rowId, 'errored'); + if (window.zddc && window.zddc.cap) { + window.zddc.cap.handleForbidden(resp, { + context: 'Save row', + path: location.pathname + }); + } + return { status: 'forbidden' }; + } + // Other status — generic error. console.warn('[tables] save returned', resp.status); setRowState(rowId, 'errored'); @@ -395,6 +406,17 @@ return { status: 'invalid', errors: errs }; } + if (resp.status === 403) { + setRowState(rowId, 'errored'); + if (window.zddc && window.zddc.cap) { + window.zddc.cap.handleForbidden(resp, { + context: 'Add row', + path: location.pathname + }); + } + return { status: 'forbidden' }; + } + console.warn('[tables] createRow returned', resp.status); setRowState(rowId, 'errored'); return { status: 'http-error', code: resp.status };