fix: restore Today break after sync recovery (Closes #1204)
This commit is contained in:
parent
e3c7df25c8
commit
e5ccfb0c5e
|
|
@ -5480,7 +5480,7 @@
|
||||||
activeFlushLogin = contextIdentityFresh ? String(snapshot.context.user?.login || '').trim() : '';
|
activeFlushLogin = contextIdentityFresh ? String(snapshot.context.user?.login || '').trim() : '';
|
||||||
if (activeFlushLogin) {
|
if (activeFlushLogin) {
|
||||||
confirmedOwnerLogin = activeFlushLogin;
|
confirmedOwnerLogin = activeFlushLogin;
|
||||||
timerView.render();
|
timerView.restore(todaySync.flush());
|
||||||
restoreReleaseReceipt();
|
restoreReleaseReceipt();
|
||||||
updateDeliveryReceiptControls();
|
updateDeliveryReceiptControls();
|
||||||
interruptionPrompt.restore();
|
interruptionPrompt.restore();
|
||||||
|
|
|
||||||
|
|
@ -542,6 +542,10 @@ function createTodayTimerView({ timer, isActive, queryAll, formatEstimate, getRu
|
||||||
},
|
},
|
||||||
finishCapture() { return captureView.finish(); },
|
finishCapture() { return captureView.finish(); },
|
||||||
transferCapture() { return captureView.transfer(); },
|
transferCapture() { return captureView.transfer(); },
|
||||||
|
restore(recovery) {
|
||||||
|
render();
|
||||||
|
return Promise.resolve(recovery).catch(() => false).then(() => { render(); return !!timer.breakSnapshot?.(); });
|
||||||
|
},
|
||||||
render,
|
render,
|
||||||
};
|
};
|
||||||
queryAll('#new-issue').forEach(button => button.addEventListener('click', () => {
|
queryAll('#new-issue').forEach(button => button.addEventListener('click', () => {
|
||||||
|
|
|
||||||
|
|
@ -185,12 +185,86 @@ process.stdout.write(JSON.stringify({{opened,cancelled,started,expired,final:{{c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_confirming_the_account_renders_a_persisted_break_immediately():
|
def test_identity_ready_restore_renders_break_again_after_sync_recovery_settles():
|
||||||
dashboard = (ROOT / "frontend" / "dashboard.js").read_text()
|
script = f"""
|
||||||
confirmation = dashboard.split("if (activeFlushLogin) {", 1)[1].split("}", 1)[0]
|
const createBreak = require({json.dumps(str(BREAK))});
|
||||||
|
global.createTodayBreak = createBreak;
|
||||||
|
global.setInterval = () => 1;
|
||||||
|
global.clearInterval = () => {{}};
|
||||||
|
Date.now = () => 100000;
|
||||||
|
const createTimer = require({json.dumps(str(TIMER))});
|
||||||
|
const createSync = require({json.dumps(str(ROOT / "frontend" / "today-sync.js"))});
|
||||||
|
const values = new Map();
|
||||||
|
const storage = {{
|
||||||
|
get length(){{return values.size;}},
|
||||||
|
key:index=>Array.from(values.keys())[index]??null,
|
||||||
|
getItem:key=>values.get(key)||null,
|
||||||
|
setItem:(key,value)=>values.set(key,value),
|
||||||
|
removeItem:key=>values.delete(key),
|
||||||
|
}};
|
||||||
|
let login = '';
|
||||||
|
values.set('stackchain.today-timer.v1.timmy', JSON.stringify({{
|
||||||
|
version:1, active_identity:'issue:r:42:',
|
||||||
|
entries:{{'issue:r:42:':{{elapsed_ms:12000,started_at:null,running:false}}}},
|
||||||
|
away_at:null,pending_interruption:null,attention_interruption:null,capture_interruption:null,
|
||||||
|
search_interruption:null,detour_interruption:null,
|
||||||
|
timed_break:{{identity:'issue:r:42:',deadline_at:400000}},
|
||||||
|
}}));
|
||||||
|
const status = {{hidden:false,textContent:''}}, resume = {{hidden:false,addEventListener(){{}}}};
|
||||||
|
const opener = {{hidden:false,addEventListener(){{}}}};
|
||||||
|
const elements = {{'#today-break-status':[status],'#resume-today-break':[resume],'[data-today-break-open]':[opener]}};
|
||||||
|
const timer = createTimer({{storage,getLogin:()=>login,now:()=>100000}});
|
||||||
|
const view = createTimer.createView({{
|
||||||
|
timer,isActive:()=>true,queryAll:selector=>elements[selector]||[],
|
||||||
|
formatEstimate:value=>String(value),getItem:()=>({{title:'Ship mobile capture'}}),
|
||||||
|
}});
|
||||||
|
login = 'timmy';
|
||||||
|
values.set('stackchain.today-sync.v1.timmy.operation.broken', '{{not-json');
|
||||||
|
const statuses = [];
|
||||||
|
const sync = createSync({{
|
||||||
|
storage,getLogin:()=>login,now:()=>100000,
|
||||||
|
fetchJson:async()=>({{revision:1,ids:['issue:r:42:'],capacity_minutes:null,estimates:{{}}}}),
|
||||||
|
onStatus:(state,detail)=>statuses.push([state,detail.discarded||0]),
|
||||||
|
}});
|
||||||
|
const recovery = sync.flush();
|
||||||
|
const restoring = view.restore(recovery);
|
||||||
|
const immediate = {{hidden:status.hidden,text:status.textContent,openerHidden:opener.hidden}};
|
||||||
|
status.hidden = true; status.textContent = ''; opener.hidden = false;
|
||||||
|
restoring.then(result => {{
|
||||||
|
const settled = {{hidden:status.hidden,text:status.textContent,openerHidden:opener.hidden}};
|
||||||
|
status.hidden = true; status.textContent = ''; opener.hidden = false;
|
||||||
|
return view.restore(Promise.reject(new Error('coordinator unavailable'))).then(rejected =>
|
||||||
|
process.stdout.write(JSON.stringify({{
|
||||||
|
immediate, settled, rejectedSettled:{{hidden:status.hidden,text:status.textContent,openerHidden:opener.hidden}},
|
||||||
|
result,rejected,statuses,
|
||||||
|
}}))
|
||||||
|
);
|
||||||
|
}});
|
||||||
|
"""
|
||||||
|
|
||||||
assert "confirmedOwnerLogin = activeFlushLogin;" in confirmation
|
assert run_node(script) == {
|
||||||
assert "timerView.render();" in confirmation
|
"immediate": {
|
||||||
|
"hidden": False,
|
||||||
|
"text": "On break · resume in 5:00",
|
||||||
|
"openerHidden": True,
|
||||||
|
},
|
||||||
|
"settled": {
|
||||||
|
"hidden": False,
|
||||||
|
"text": "On break · resume in 5:00",
|
||||||
|
"openerHidden": True,
|
||||||
|
},
|
||||||
|
"rejectedSettled": {
|
||||||
|
"hidden": False,
|
||||||
|
"text": "On break · resume in 5:00",
|
||||||
|
"openerHidden": True,
|
||||||
|
},
|
||||||
|
"result": True,
|
||||||
|
"rejected": True,
|
||||||
|
"statuses": [["recovered", 1]],
|
||||||
|
}
|
||||||
|
|
||||||
|
dashboard = (ROOT / "frontend" / "dashboard.js").read_text()
|
||||||
|
assert "timerView.restore(todaySync.flush());" in dashboard
|
||||||
|
|
||||||
|
|
||||||
def test_timed_break_is_packaged_as_an_accessible_mobile_flow():
|
def test_timed_break_is_packaged_as_an_accessible_mobile_flow():
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user