Compare commits
No commits in common. "7421a8f62d3db937bd985740b677606fa2ad793b" and "3e7d6f7111bb79eddbf5885fcc29fa6aa7316489" have entirely different histories.
7421a8f62d
...
3e7d6f7111
|
|
@ -5563,7 +5563,11 @@
|
||||||
qs('#active-work-queue').textContent = button.firstChild.textContent.trim() + ' (' + selectedCount + ')';
|
qs('#active-work-queue').textContent = button.firstChild.textContent.trim() + ' (' + selectedCount + ')';
|
||||||
renderMyWork();
|
renderMyWork();
|
||||||
updateWorkPaginationControls();
|
updateWorkPaginationControls();
|
||||||
if (!preserveRoute) workRoute.queue(filter);
|
if (!preserveRoute && filter === 'update' && window.location.hash !== '#/my-work/updates') {
|
||||||
|
window.history.pushState({ workQueue:'update' }, '', '#/my-work/updates');
|
||||||
|
} else if (!preserveRoute && filter !== 'update' && window.location.hash === '#/my-work/updates') {
|
||||||
|
window.history.replaceState(null, '', window.location.pathname + window.location.search);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
function openWorkQueueRoute(filter) {
|
function openWorkQueueRoute(filter) {
|
||||||
|
|
@ -5571,6 +5575,14 @@
|
||||||
qs('#my-work').scrollIntoView({block:'start'});
|
qs('#my-work').scrollIntoView({block:'start'});
|
||||||
qs('#my-work').focus();
|
qs('#my-work').focus();
|
||||||
}
|
}
|
||||||
|
function openDeliveryReceiptRoute() {
|
||||||
|
if (window.location.hash !== '#/my-work/drafts') return;
|
||||||
|
qs('[data-work-filter="draft"]').click();
|
||||||
|
qs('#my-work').scrollIntoView({block:'start'});
|
||||||
|
qs('#my-work').focus();
|
||||||
|
}
|
||||||
|
window.addEventListener('hashchange', openDeliveryReceiptRoute);
|
||||||
|
openDeliveryReceiptRoute();
|
||||||
qs('#work-milestone-filter').addEventListener('change', event => {
|
qs('#work-milestone-filter').addEventListener('change', event => {
|
||||||
selectedWorkMilestone = event.target.value;
|
selectedWorkMilestone = event.target.value;
|
||||||
try { sessionStorage.setItem(WORK_MILESTONE_KEY, selectedWorkMilestone); }
|
try { sessionStorage.setItem(WORK_MILESTONE_KEY, selectedWorkMilestone); }
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const repositoryPart = /^[A-Za-z0-9_.-]+$/;
|
const repositoryPart = /^[A-Za-z0-9_.-]+$/;
|
||||||
const queueFilters = ['today', 'attention', 'update', 'later', 'draft'];
|
|
||||||
|
|
||||||
function positiveInteger(value) {
|
function positiveInteger(value) {
|
||||||
const number = Number(value);
|
const number = Number(value);
|
||||||
|
|
@ -16,9 +15,8 @@
|
||||||
function parse(fragment) {
|
function parse(fragment) {
|
||||||
const parts = String(fragment || '').split('/');
|
const parts = String(fragment || '').split('/');
|
||||||
if (parts[0] !== '#' || parts[1] !== 'my-work') return null;
|
if (parts[0] !== '#' || parts[1] !== 'my-work') return null;
|
||||||
const queue = parts[2]?.replace(/s$/, '');
|
if (parts[2] === 'updates' && parts.length === 3) {
|
||||||
if (queueFilters.includes(queue) && parts.length === 3) {
|
return { kind: 'queue', filter: 'update' };
|
||||||
return { kind: 'queue', filter: queue };
|
|
||||||
}
|
}
|
||||||
if (parts[2] === 'update' && parts.length === 4) {
|
if (parts[2] === 'update' && parts.length === 4) {
|
||||||
const notificationId = positiveInteger(parts[3]);
|
const notificationId = positiveInteger(parts[3]);
|
||||||
|
|
@ -151,15 +149,6 @@
|
||||||
onOpen(item);
|
onOpen(item);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
queue(filter) {
|
|
||||||
if (!queueFilters.includes(filter)) return false;
|
|
||||||
const name = filter + (['update', 'draft'].includes(filter) ? 's' : '');
|
|
||||||
const fragment = '#/my-work/' + name;
|
|
||||||
if (location.hash !== fragment) history.pushState(null, '', fragment);
|
|
||||||
active = fragment;
|
|
||||||
onQueue(filter);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
close() {
|
close() {
|
||||||
if (parse(location.hash)) history.back();
|
if (parse(location.hash)) history.back();
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -1420,6 +1420,5 @@ async def test_dashboard_offers_explicit_account_bound_delivery_receipt_opt_in()
|
||||||
assert "await Notification.requestPermission()" in html
|
assert "await Notification.requestPermission()" in html
|
||||||
assert "backgroundIssueSync.setReceiptPreference(confirmedOwnerLogin, enabled)" in html
|
assert "backgroundIssueSync.setReceiptPreference(confirmedOwnerLogin, enabled)" in html
|
||||||
assert "await backgroundIssueSync.getReceiptPreference(confirmedOwnerLogin)" in html
|
assert "await backgroundIssueSync.getReceiptPreference(confirmedOwnerLogin)" in html
|
||||||
assert "onQueue: openWorkQueueRoute" in html
|
assert "window.addEventListener('hashchange', openDeliveryReceiptRoute);" in html
|
||||||
assert "workRoute.queue(filter)" in html
|
assert "if (window.location.hash !== '#/my-work/drafts') return;" in html
|
||||||
assert "openDeliveryReceiptRoute" not in html
|
|
||||||
|
|
|
||||||
|
|
@ -439,74 +439,6 @@ process.stdout.write(JSON.stringify({{calls, hash:location.hash, parsed:routes.p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_every_mobile_queue_route_survives_hydration_and_detail_back_navigation():
|
|
||||||
script = f"""
|
|
||||||
const routes = require({json.dumps(str(WORK_ROUTE))});
|
|
||||||
const canonical = ['today', 'attention', 'updates', 'later', 'drafts'];
|
|
||||||
const parsed = canonical.map(name => [name, routes.parse('#/my-work/' + name)]);
|
|
||||||
const listeners = {{}};
|
|
||||||
const location = {{hash:'#/my-work/later'}};
|
|
||||||
const calls = [];
|
|
||||||
const stack = ['#/my-work/later'];
|
|
||||||
let cursor = 0;
|
|
||||||
const history = {{
|
|
||||||
pushState(state, _, hash) {{ stack.splice(cursor + 1); stack.push(hash); cursor += 1; location.hash = hash; }},
|
|
||||||
replaceState(state, _, hash) {{ stack[cursor] = hash; location.hash = hash; }},
|
|
||||||
back() {{ cursor -= 1; location.hash = stack[cursor]; listeners.popstate(); }},
|
|
||||||
}};
|
|
||||||
const controller = routes.createController({{
|
|
||||||
location, history,
|
|
||||||
eventTarget: {{addEventListener(name, fn) {{ listeners[name] = fn; }}}},
|
|
||||||
onQueue: queue => calls.push(['queue', queue]),
|
|
||||||
onOpen: item => calls.push(['open', item.number]),
|
|
||||||
onClose: () => calls.push(['close']),
|
|
||||||
onInvalid: () => calls.push(['invalid']),
|
|
||||||
}});
|
|
||||||
controller.start();
|
|
||||||
controller.setItems([{{kind:'issue', repository:'stackchain/dashboard', number:42}}]);
|
|
||||||
controller.open({{kind:'issue', repository:'stackchain/dashboard', number:42}});
|
|
||||||
controller.close();
|
|
||||||
controller.queue('draft');
|
|
||||||
process.stdout.write(JSON.stringify({{parsed, calls, hash:location.hash}}));
|
|
||||||
"""
|
|
||||||
result = subprocess.run(
|
|
||||||
["node", "-e", script], check=True, capture_output=True, text=True
|
|
||||||
)
|
|
||||||
|
|
||||||
assert json.loads(result.stdout) == {
|
|
||||||
"parsed": [
|
|
||||||
["today", {"kind": "queue", "filter": "today"}],
|
|
||||||
["attention", {"kind": "queue", "filter": "attention"}],
|
|
||||||
["updates", {"kind": "queue", "filter": "update"}],
|
|
||||||
["later", {"kind": "queue", "filter": "later"}],
|
|
||||||
["drafts", {"kind": "queue", "filter": "draft"}],
|
|
||||||
],
|
|
||||||
"calls": [
|
|
||||||
["queue", "later"],
|
|
||||||
["open", 42],
|
|
||||||
["close"],
|
|
||||||
["queue", "later"],
|
|
||||||
["queue", "draft"],
|
|
||||||
],
|
|
||||||
"hash": "#/my-work/drafts",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def test_mobile_queue_routes_reject_unknown_or_nested_fragments():
|
|
||||||
script = f"""
|
|
||||||
const routes = require({json.dumps(str(WORK_ROUTE))});
|
|
||||||
process.stdout.write(JSON.stringify([
|
|
||||||
routes.parse('#/my-work/tomorrow'),
|
|
||||||
routes.parse('#/my-work/today/extra'),
|
|
||||||
routes.parse('#/my-work/drafts/1'),
|
|
||||||
]));
|
|
||||||
"""
|
|
||||||
result = subprocess.run(
|
|
||||||
["node", "-e", script], check=True, capture_output=True, text=True
|
|
||||||
)
|
|
||||||
assert json.loads(result.stdout) == [None, None, None]
|
|
||||||
|
|
||||||
|
|
||||||
def test_work_route_controller_resolves_cold_routes_without_erasing_the_fragment():
|
def test_work_route_controller_resolves_cold_routes_without_erasing_the_fragment():
|
||||||
script = f"""
|
script = f"""
|
||||||
const routes = require({json.dumps(str(WORK_ROUTE))});
|
const routes = require({json.dumps(str(WORK_ROUTE))});
|
||||||
|
|
@ -621,8 +553,8 @@ async def test_dashboard_wires_addressable_work_sheets_back_navigation_and_share
|
||||||
assert 'Route unavailable · this item is no longer in My Work.' in html
|
assert 'Route unavailable · this item is no longer in My Work.' in html
|
||||||
assert "onQueue: openWorkQueueRoute" in html
|
assert "onQueue: openWorkQueueRoute" in html
|
||||||
assert "selectWorkQueue(filter, { preserveRoute:true })" in html
|
assert "selectWorkQueue(filter, { preserveRoute:true })" in html
|
||||||
assert "workRoute.queue(filter)" in html
|
assert "filter === 'update' && window.location.hash !== '#/my-work/updates'" in html
|
||||||
assert "openDeliveryReceiptRoute" not in html
|
assert "window.history.pushState({ workQueue:'update' }, '', '#/my-work/updates')" in html
|
||||||
|
|
||||||
|
|
||||||
def test_my_work_queue_prioritizes_labels_then_reviews_and_keeps_repo_identity():
|
def test_my_work_queue_prioritizes_labels_then_reviews_and_keeps_repo_identity():
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user