fix: make update decisions transaction-safe (Closes #771)
This commit is contained in:
1 parent
80042ce561
commit
2e0d64907b
9 files changed
+131
-22
No files matched your search
+16
-16
@@ -940,6 +940,13 @@
|
||||
event.currentTarget.setAttribute('aria-expanded', String(more.open));
|
||||
if (more.open) more.scrollIntoView({ behavior:'smooth', block:'end' });
|
||||
});
|
||||
const updateDecision = createUpdateDecisionTransaction({
|
||||
controls: [
|
||||
qs('#keep-update-unread'), qs('#mark-update-read-next'),
|
||||
qs('#focus-update-reply'), qs('#toggle-update-more'),
|
||||
],
|
||||
status: qs('#update-gesture-status'),
|
||||
});
|
||||
const notificationReader = createNotificationReader({
|
||||
load: fetchNotificationDetail,
|
||||
getScope: () => confirmedOwnerLogin,
|
||||
@@ -5554,13 +5561,17 @@
|
||||
button.focus();
|
||||
}
|
||||
});
|
||||
qs('#keep-update-unread').addEventListener('click', () => {
|
||||
if (updateTriage.active()) updateTriage.keepUnreadAndNext();
|
||||
else closeUpdateSheet(true);
|
||||
const updateDecisionActions = createUpdateDecisionActions({
|
||||
transaction:updateDecision, triage:updateTriage, close:()=>closeUpdateSheet(true),
|
||||
reader:notificationReader, items:()=>lastMyWork, undo:notificationUndo,
|
||||
keepControl:qs('#keep-update-unread'), readControl:qs('#mark-update-read-next'),
|
||||
});
|
||||
const keepUpdateUnread = () => updateDecisionActions.keepUnread();
|
||||
const markUpdateRead = () => updateDecisionActions.markRead();
|
||||
qs('#keep-update-unread').addEventListener('click', keepUpdateUnread);
|
||||
createUpdateTriageGesture({
|
||||
surface: qs('#update-sheet .update-sheet-panel'), enabled: () => selectedUpdateDetail,
|
||||
keepUnread: () => qs('#keep-update-unread').click(), markRead: () => qs('#mark-update-read-next').click(),
|
||||
keepUnread: keepUpdateUnread, markRead: markUpdateRead,
|
||||
});
|
||||
qs('#update-ownership-action').addEventListener('click', () => updateOwnership.act());
|
||||
qs('#update-ownership-start').addEventListener('click', () => updateOwnership.start());
|
||||
@@ -5647,18 +5658,7 @@
|
||||
updateReplyAttachmentController.setBusy(false);
|
||||
}
|
||||
});
|
||||
qs('#mark-update-read-next').addEventListener('click', async () => {
|
||||
qs('#mark-update-read-next').disabled = true;
|
||||
try {
|
||||
const result = await notificationReader.markReadAndNext(lastMyWork);
|
||||
if (result) {
|
||||
notificationUndo.offer(result.item, result.items);
|
||||
if (updateTriage.active()) updateTriage.acceptCompleted();
|
||||
}
|
||||
} finally {
|
||||
qs('#mark-update-read-next').disabled = false;
|
||||
}
|
||||
});
|
||||
qs('#mark-update-read-next').addEventListener('click', markUpdateRead);
|
||||
qs('#acknowledge-update-next').addEventListener('click', async () => {
|
||||
const button = qs('#acknowledge-update-next');
|
||||
button.disabled = true;
|
||||
|
||||
@@ -1091,6 +1091,7 @@
|
||||
<script src="static/update-read-position.js"></script>
|
||||
<script src="static/update-triage-launcher.js"></script>
|
||||
<script src="static/update-triage-gesture.js"></script>
|
||||
<script src="static/update-decision-transaction.js"></script>
|
||||
<script src="static/agenda-session-launcher.js"></script>
|
||||
<script src="static/mobile-launch.js"></script>
|
||||
<script src="static/mobile-app-shortcuts.js"></script>
|
||||
|
||||
@@ -80,6 +80,7 @@ const SHELL = [
|
||||
BASE + 'static/update-read-position.js',
|
||||
BASE + 'static/update-triage-launcher.js',
|
||||
BASE + 'static/update-triage-gesture.js',
|
||||
BASE + 'static/update-decision-transaction.js',
|
||||
BASE + 'static/agenda-session-launcher.js',
|
||||
BASE + 'static/mobile-launch.js',
|
||||
BASE + 'static/mobile-app-shortcuts.js',
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
(function(r){
|
||||
function transaction({controls=[],status}) {
|
||||
let busy=false, disabled=[];
|
||||
async function run(message, action, {origin,failure}={}) {
|
||||
if (busy) return false;
|
||||
busy=true;
|
||||
disabled=controls.map(control=>control.disabled);
|
||||
controls.forEach(control=>{ control.disabled=true; });
|
||||
status.textContent=message;
|
||||
let completed=false;
|
||||
try { completed=Boolean(await action()); }
|
||||
catch (error) { failure=failure || error.message || 'Could not complete decision. Retry.'; }
|
||||
if (!completed && failure) status.textContent=failure;
|
||||
busy=false;
|
||||
controls.forEach((control,index)=>{ control.disabled=disabled[index]; });
|
||||
if (!completed) origin?.focus?.();
|
||||
return completed;
|
||||
}
|
||||
return {run,busy:()=>busy};
|
||||
}
|
||||
function actions(o) {
|
||||
return {
|
||||
keepUnread:()=>o.transaction.run('Keeping unread…',()=>{
|
||||
if(o.triage.active()) o.triage.keepUnreadAndNext(); else o.close();
|
||||
return true;
|
||||
},{origin:o.keepControl,failure:'Could not keep this update unread. Retry.'}),
|
||||
markRead:()=>o.transaction.run('Marking read…',async()=>{
|
||||
const result=await o.reader.markReadAndNext(o.items());
|
||||
if(!result) return false;
|
||||
o.undo.offer(result.item,result.items);
|
||||
if(o.triage.active()) o.triage.acceptCompleted();
|
||||
return true;
|
||||
},{origin:o.readControl,failure:'Could not mark update read. Retry.'}),
|
||||
};
|
||||
}
|
||||
if(typeof module==='object'&&module.exports){module.exports=transaction;module.exports.createActions=actions;}
|
||||
else {r.createUpdateDecisionTransaction=transaction;r.createUpdateDecisionActions=actions;}
|
||||
})(typeof self!=='undefined'?self:this);
|
||||
Reference in new issue
Block a user