Compare commits
2 Commits
89b1ad1f08
...
2432d4fc03
| Author | SHA1 | Date | |
|---|---|---|---|
| 2432d4fc03 | |||
| c97383fccb |
|
|
@ -15,11 +15,13 @@
|
|||
['today', 'Continue Today'],
|
||||
['update', 'Resume Updates'],
|
||||
['agenda', 'Open Agenda'],
|
||||
['following', 'Review Following'],
|
||||
['authored', 'Open My PRs'],
|
||||
['filed', 'Review Filed'],
|
||||
['later', 'Start Later'],
|
||||
['draft', 'Open Drafts'],
|
||||
];
|
||||
const activeQueueNames = continuation.map(([name]) => name).concat(['following', 'authored']);
|
||||
const activeQueueNames = continuation.map(([name]) => name);
|
||||
const allQueues = [
|
||||
'today', 'tomorrow', 'week', 'agenda', 'delivery', 'gate', 'attention',
|
||||
'update', 'following', 'filed', 'authored', 'later', 'draft', 'find', 'recaps',
|
||||
|
|
|
|||
|
|
@ -70,9 +70,10 @@
|
|||
const text = {
|
||||
continue:'Continue', resume:'Resume', start:'Start', plan:'Plan', find:'Find',
|
||||
prepare:'Prepare', 'prepare-resume':'Resume prep',
|
||||
delivery:'Delivery', attention:'Attention', update:'Updates', agenda:'Agenda', filed:'Filed', later:'Later', draft:'Drafts',
|
||||
delivery:'Delivery', attention:'Attention', update:'Updates', agenda:'Agenda',
|
||||
following:'Following', authored:'My PRs', filed:'Filed', later:'Later', draft:'Drafts',
|
||||
}[mode] || 'Work';
|
||||
const queue = ['Delivery', 'Attention', 'Updates', 'Agenda', 'Filed', 'Later', 'Drafts'].includes(text);
|
||||
const queue = ['Delivery', 'Attention', 'Updates', 'Agenda', 'Following', 'My PRs', 'Filed', 'Later', 'Drafts'].includes(text);
|
||||
if (options.workLabel) options.workLabel.textContent = text;
|
||||
const actionLabel = mode === 'prepare' ? 'Prepare Today' :
|
||||
mode === 'prepare-resume' ? 'Resume preparation' :
|
||||
|
|
|
|||
|
|
@ -59,3 +59,61 @@ def test_adaptive_queues_put_truthful_next_action_above_the_fold(viewport):
|
|||
expect(page.locator(".mobile-queue-all")).not_to_have_attribute("open", "")
|
||||
assert page.evaluate("document.documentElement.scrollWidth <= window.innerWidth")
|
||||
browser.close()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("viewport", [
|
||||
{"width": 320, "height": 568},
|
||||
{"width": 375, "height": 667},
|
||||
{"width": 430, "height": 932},
|
||||
])
|
||||
@pytest.mark.parametrize(("queue", "count", "label", "destination"), [
|
||||
("following", 3, "Review Following (3)", ["following"]),
|
||||
("authored", 2, "Open My PRs (2)", ["filter:authored", "open:authored"]),
|
||||
])
|
||||
def test_adaptive_queues_open_existing_following_and_authored_work(viewport, queue, count, label, destination):
|
||||
with sync_playwright() as playwright:
|
||||
browser = playwright.chromium.launch(headless=True)
|
||||
page = browser.new_page(viewport=viewport)
|
||||
page.set_content((FRONTEND / "index.html").read_text())
|
||||
page.add_style_tag(path=FRONTEND / "dashboard.css")
|
||||
page.add_script_tag(path=FRONTEND / "mobile-queue-launcher.js")
|
||||
page.evaluate("""({queue, count}) => {
|
||||
const rows = Object.fromEntries(Array.from(document.querySelectorAll('[data-mobile-queue]'))
|
||||
.map(row => [row.dataset.mobileQueue, row]));
|
||||
window.destinations = [];
|
||||
window.adaptiveQueueLauncher = createMobileQueueLauncher({
|
||||
getCounts:() => ({[queue]:count}),
|
||||
rows,
|
||||
nextAction:document.querySelector('#mobile-queue-next-action'),
|
||||
activeList:document.querySelector('#mobile-queue-active-list'),
|
||||
planningList:document.querySelector('#mobile-queue-planning-list'),
|
||||
allList:document.querySelector('#mobile-queue-all-list'),
|
||||
activeSection:document.querySelector('#mobile-queue-active-list').parentElement,
|
||||
openFollowing:() => window.destinations.push('following'),
|
||||
selectFilter:name => window.destinations.push('filter:' + name),
|
||||
firstAction:name => name === 'authored' ? {click:() => window.destinations.push('open:authored')} : null,
|
||||
announce:message => window.destinations.push('announce:' + message),
|
||||
});
|
||||
window.adaptiveQueueLauncher.renderPresentation();
|
||||
document.querySelector('#mobile-queue-next-action').addEventListener(
|
||||
'click', () => window.adaptiveQueueLauncher.continueWork()
|
||||
);
|
||||
document.querySelector('#mobile-queue-sheet').showModal();
|
||||
}""", {"queue": queue, "count": count})
|
||||
|
||||
next_action = page.locator("#mobile-queue-next-action")
|
||||
expect(next_action).to_be_visible()
|
||||
expect(next_action).to_have_text(label)
|
||||
expect(next_action).to_have_attribute("aria-label", "Next up: " + label)
|
||||
bounds = next_action.bounding_box()
|
||||
assert bounds and bounds["height"] >= 44
|
||||
assert bounds["y"] + bounds["height"] <= viewport["height"]
|
||||
assert page.evaluate("document.documentElement.scrollWidth <= window.innerWidth")
|
||||
assert page.locator("#mobile-queue-active-list [data-mobile-queue]").evaluate_all(
|
||||
"rows => rows.map(row => row.dataset.mobileQueue)"
|
||||
) == [queue]
|
||||
|
||||
next_action.focus()
|
||||
next_action.press("Enter")
|
||||
assert page.evaluate("window.destinations") == destination
|
||||
browser.close()
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ const feature=createFollowing({{
|
|||
]
|
||||
|
||||
|
||||
def test_following_opens_explicitly_but_never_becomes_work_recommendation():
|
||||
def test_following_opens_explicitly_and_becomes_work_recommendation():
|
||||
launcher = ROOT / "frontend" / "mobile-queue-launcher.js"
|
||||
script = f"""
|
||||
const createLauncher = require({json.dumps(str(launcher))});
|
||||
|
|
@ -293,7 +293,7 @@ process.stdout.write(JSON.stringify({{opened:feature.open('following'),recommend
|
|||
).stdout)
|
||||
assert result == {
|
||||
"opened": "opened-following",
|
||||
"recommended": {"name": "find", "count": 0, "label": "Find Work"},
|
||||
"recommended": {"name": "following", "count": 7, "label": "Review Following (7)"},
|
||||
"calls": ["following"],
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -797,6 +797,42 @@ process.stdout.write(JSON.stringify({{recommendation, opened, calls}}));
|
|||
}
|
||||
|
||||
|
||||
def test_mobile_work_continues_following_then_authored_before_claiming_new_work():
|
||||
script = f"""
|
||||
const createLauncher = require({json.dumps(str(QUEUE_LAUNCHER))});
|
||||
const calls = [];
|
||||
let counts = {{following:3, authored:2, filed:1, later:4}};
|
||||
const launcher = createLauncher({{
|
||||
getCounts: () => counts,
|
||||
openFollowing: () => {{ calls.push('following'); return 'opened-following'; }},
|
||||
selectFilter: name => calls.push('filter:' + name),
|
||||
firstAction: name => name === 'authored' ? {{click() {{ calls.push('open:authored'); }}}} : null,
|
||||
announce: message => calls.push('announce:' + message),
|
||||
openFindWork: () => calls.push('find'),
|
||||
}});
|
||||
const following = launcher.recommend();
|
||||
const openedFollowing = launcher.continueWork();
|
||||
counts = {{following:0, authored:2, filed:1, later:4}};
|
||||
const authored = launcher.recommend();
|
||||
const openedAuthored = launcher.continueWork();
|
||||
counts = {{following:0, authored:0, filed:0, later:0}};
|
||||
const fallback = launcher.recommend();
|
||||
launcher.continueWork();
|
||||
process.stdout.write(JSON.stringify({{following, openedFollowing, authored, openedAuthored, fallback, calls}}));
|
||||
"""
|
||||
result = subprocess.run(["node", "-e", script], capture_output=True, text=True)
|
||||
|
||||
assert result.returncode == 0, result.stderr
|
||||
assert json.loads(result.stdout) == {
|
||||
"following": {"name": "following", "count": 3, "label": "Review Following (3)"},
|
||||
"openedFollowing": "opened-following",
|
||||
"authored": {"name": "authored", "count": 2, "label": "Open My PRs (2)"},
|
||||
"openedAuthored": "opened",
|
||||
"fallback": {"name": "find", "count": 0, "label": "Find Work"},
|
||||
"calls": ["following", "filter:authored", "open:authored", "find"],
|
||||
}
|
||||
|
||||
|
||||
def test_mobile_queue_launcher_recommends_and_revalidates_cross_queue_continuation():
|
||||
script = f"""
|
||||
const createLauncher = require({json.dumps(str(QUEUE_LAUNCHER))});
|
||||
|
|
@ -973,7 +1009,7 @@ const work = {{attributes: {{}}, setAttribute(name, value) {{ this.attributes[na
|
|||
const workLabel = {{textContent:''}};
|
||||
const dock = createDock({{nav:{{}}, buttons:{{work}}, workLabel}});
|
||||
const labels = {{}};
|
||||
for (const mode of ['delivery','attention','update','agenda','filed','later','draft']) {{
|
||||
for (const mode of ['delivery','attention','update','agenda','following','authored','filed','later','draft']) {{
|
||||
dock.updateWork(mode);
|
||||
labels[mode] = [workLabel.textContent, work.attributes['aria-label']];
|
||||
}}
|
||||
|
|
@ -987,6 +1023,8 @@ process.stdout.write(JSON.stringify(labels));
|
|||
"attention": ["Attention", "Open Attention"],
|
||||
"update": ["Updates", "Resume Updates"],
|
||||
"agenda": ["Agenda", "Open Agenda"],
|
||||
"following": ["Following", "Open Following"],
|
||||
"authored": ["My PRs", "Open My PRs"],
|
||||
"filed": ["Filed", "Open Filed"],
|
||||
"later": ["Later", "Open Later"],
|
||||
"draft": ["Drafts", "Open Drafts"],
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user