Compare commits
No commits in common. "a0dd044995e266c8a78f90eca1c16f2c5d668466" and "5675ca5d41180528b924c18bb159a37fffc539ca" have entirely different histories.
a0dd044995
...
5675ca5d41
|
|
@ -463,7 +463,6 @@ textarea { resize: vertical; min-height: 120px; }
|
||||||
.find-work-card.selected { border-color:#60a5fa; box-shadow:0 0 0 2px rgba(96,165,250,.25); }
|
.find-work-card.selected { border-color:#60a5fa; box-shadow:0 0 0 2px rgba(96,165,250,.25); }
|
||||||
.find-work-select { display:flex; align-items:center; gap:10px; min-height:44px; }
|
.find-work-select { display:flex; align-items:center; gap:10px; min-height:44px; }
|
||||||
.find-work-select input { width:22px; height:22px; }
|
.find-work-select input { width:22px; height:22px; }
|
||||||
.fill-find-work-today { min-height:44px; width:100%; font-weight:700; }
|
|
||||||
.find-work-batch-actions { position:sticky; bottom:0; z-index:2; display:grid; grid-template-columns:1fr 1fr; gap:8px; padding:12px 0 calc(12px + env(safe-area-inset-bottom)); background:#0b1526; border-top:1px solid #2a496e; }
|
.find-work-batch-actions { position:sticky; bottom:0; z-index:2; display:grid; grid-template-columns:1fr 1fr; gap:8px; padding:12px 0 calc(12px + env(safe-area-inset-bottom)); background:#0b1526; border-top:1px solid #2a496e; }
|
||||||
.find-work-batch-actions[hidden] { display:none; }
|
.find-work-batch-actions[hidden] { display:none; }
|
||||||
.find-work-batch-actions span { grid-column:1 / -1; }
|
.find-work-batch-actions span { grid-column:1 / -1; }
|
||||||
|
|
|
||||||
|
|
@ -4277,14 +4277,6 @@
|
||||||
qs('#find-work').addEventListener('click', openFindWorkSheet);
|
qs('#find-work').addEventListener('click', openFindWorkSheet);
|
||||||
qs('#close-find-work').addEventListener('click', closeFindWorkSheet);
|
qs('#close-find-work').addEventListener('click', closeFindWorkSheet);
|
||||||
qs('#select-find-work').addEventListener('click', () => findWorkController.startSelection());
|
qs('#select-find-work').addEventListener('click', () => findWorkController.startSelection());
|
||||||
qs('#fill-find-work-today').addEventListener('click', () => {
|
|
||||||
const remainingSlots = todayWork.limit - todayWork.read().length;
|
|
||||||
const outcome = findWorkController.fillSelection(remainingSlots);
|
|
||||||
qs('#find-work-status').textContent = remainingSlots < 1 ? 'Today is full.' :
|
|
||||||
outcome.selected ? outcome.selected + ' ranked work selected.' : 'No matching work.';
|
|
||||||
if (outcome.selected && todayWork.planning().capacity_minutes !== null)
|
|
||||||
openFindWorkEstimateReview(findWorkController.selectedItems());
|
|
||||||
});
|
|
||||||
qs('#find-work-search-form').addEventListener('submit', event => event.preventDefault());
|
qs('#find-work-search-form').addEventListener('submit', event => event.preventDefault());
|
||||||
qs('#find-work-search').addEventListener('input', event => {
|
qs('#find-work-search').addEventListener('input', event => {
|
||||||
const value = event.currentTarget.value;
|
const value = event.currentTarget.value;
|
||||||
|
|
|
||||||
|
|
@ -541,8 +541,6 @@
|
||||||
<button id="clear-find-work-search" type="button" hidden>Clear</button></div>
|
<button id="clear-find-work-search" type="button" hidden>Clear</button></div>
|
||||||
<span id="find-work-match-status" class="small" aria-live="polite"></span>
|
<span id="find-work-match-status" class="small" aria-live="polite"></span>
|
||||||
</form>
|
</form>
|
||||||
<button class="fill-find-work-today" id="fill-find-work-today" type="button"
|
|
||||||
aria-describedby="find-work-selection-status">Fill remaining Today slots</button>
|
|
||||||
<div id="find-work-status" class="small" aria-live="assertive">Open Find Work to load available issues.</div>
|
<div id="find-work-status" class="small" aria-live="assertive">Open Find Work to load available issues.</div>
|
||||||
<div class="find-work-list" id="find-work-list"></div>
|
<div class="find-work-list" id="find-work-list"></div>
|
||||||
<button class="find-work-more" id="load-more-available" type="button" hidden>Load more available issues</button>
|
<button class="find-work-more" id="load-more-available" type="button" hidden>Load more available issues</button>
|
||||||
|
|
|
||||||
|
|
@ -101,19 +101,6 @@ function createFindWork({ fetchJson, onItems, onPagination, onStatus, onSelectio
|
||||||
else selected.set(key, item);
|
else selected.set(key, item);
|
||||||
return emitSelection();
|
return emitSelection();
|
||||||
},
|
},
|
||||||
fillSelection(limit) {
|
|
||||||
limit = Math.max(0, Math.floor(Number(limit) || 0));
|
|
||||||
if (!limit) return { selected: selected.size, added: 0, limit };
|
|
||||||
selecting = true;
|
|
||||||
const before = selected.size;
|
|
||||||
available.some(item => {
|
|
||||||
if (selected.size >= limit) return true;
|
|
||||||
selected.set(itemKey(item), item);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
emitSelection();
|
|
||||||
return { selected: selected.size, added: selected.size - before, limit };
|
|
||||||
},
|
|
||||||
isSelected(item) {
|
isSelected(item) {
|
||||||
return selected.has(itemKey(item));
|
return selected.has(itemKey(item));
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -212,66 +212,6 @@ controller.load().then(()=>{{
|
||||||
assert run_node(script) == {"selected": [672], "selecting": True}
|
assert run_node(script) == {"selected": [672], "selecting": True}
|
||||||
|
|
||||||
|
|
||||||
def test_fill_today_selects_ranked_matches_up_to_remaining_capacity():
|
|
||||||
script = f"""
|
|
||||||
const createFindWork=require({json.dumps(str(PICK_WORK))});
|
|
||||||
const states=[];
|
|
||||||
const controller=createFindWork({{
|
|
||||||
fetchJson:()=>Promise.resolve({{items:[
|
|
||||||
{{id:1,repository:'stackchain/dashboard',number:701}},
|
|
||||||
{{id:2,repository:'stackchain/dashboard',number:702}},
|
|
||||||
{{id:3,repository:'stackchain/dashboard',number:703}},
|
|
||||||
{{id:4,repository:'stackchain/dashboard',number:704}},
|
|
||||||
],page:1,total:4,has_more:false}}),
|
|
||||||
onItems:()=>{{}}, onPagination:()=>{{}}, onStatus:()=>{{}},
|
|
||||||
onSelection:state=>states.push(state),
|
|
||||||
}});
|
|
||||||
controller.load().then(()=>{{
|
|
||||||
controller.startSelection();
|
|
||||||
controller.toggleSelection(controller.items()[1]);
|
|
||||||
const outcome=controller.fillSelection(3);
|
|
||||||
process.stdout.write(JSON.stringify({{
|
|
||||||
outcome,
|
|
||||||
selected:controller.selectedItems().map(item=>item.number),
|
|
||||||
lastState:states.at(-1),
|
|
||||||
}}));
|
|
||||||
}});
|
|
||||||
"""
|
|
||||||
|
|
||||||
assert run_node(script) == {
|
|
||||||
"outcome": {"selected": 3, "added": 2, "limit": 3},
|
|
||||||
"selected": [702, 701, 703],
|
|
||||||
"lastState": {
|
|
||||||
"active": True,
|
|
||||||
"count": 3,
|
|
||||||
"ids": [
|
|
||||||
"stackchain/dashboard#702",
|
|
||||||
"stackchain/dashboard#701",
|
|
||||||
"stackchain/dashboard#703",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def test_fill_today_with_no_capacity_does_not_change_selection():
|
|
||||||
script = f"""
|
|
||||||
const createFindWork=require({json.dumps(str(PICK_WORK))});
|
|
||||||
const controller=createFindWork({{
|
|
||||||
fetchJson:()=>Promise.resolve({{items:[{{id:1,repository:'stackchain/dashboard',number:701}}]}}),
|
|
||||||
onItems:()=>{{}}, onPagination:()=>{{}}, onStatus:()=>{{}}, onSelection:()=>{{}},
|
|
||||||
}});
|
|
||||||
controller.load().then(()=>{{
|
|
||||||
const outcome=controller.fillSelection(0);
|
|
||||||
process.stdout.write(JSON.stringify({{outcome,selection:controller.selection()}}));
|
|
||||||
}});
|
|
||||||
"""
|
|
||||||
|
|
||||||
assert run_node(script) == {
|
|
||||||
"outcome": {"selected": 0, "added": 0, "limit": 0},
|
|
||||||
"selection": {"active": False, "count": 0, "ids": []},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def test_mobile_find_work_exposes_accessible_batch_controls_and_offline_asset():
|
def test_mobile_find_work_exposes_accessible_batch_controls_and_offline_asset():
|
||||||
html = HTML.read_text()
|
html = HTML.read_text()
|
||||||
dashboard = DASHBOARD.read_text()
|
dashboard = DASHBOARD.read_text()
|
||||||
|
|
@ -292,18 +232,6 @@ def test_mobile_find_work_exposes_accessible_batch_controls_and_offline_asset():
|
||||||
assert '<script src="static/batch-find-work.js"></script>' in html
|
assert '<script src="static/batch-find-work.js"></script>' in html
|
||||||
|
|
||||||
|
|
||||||
def test_mobile_find_work_exposes_fill_today_action_with_capacity_handoff():
|
|
||||||
html = HTML.read_text()
|
|
||||||
dashboard = DASHBOARD.read_text()
|
|
||||||
css = CSS.read_text()
|
|
||||||
|
|
||||||
assert 'id="fill-find-work-today"' in html
|
|
||||||
assert 'aria-describedby="find-work-selection-status"' in html
|
|
||||||
assert "findWorkController.fillSelection(remainingSlots)" in dashboard
|
|
||||||
assert "openFindWorkEstimateReview(findWorkController.selectedItems())" in dashboard
|
|
||||||
assert ".fill-find-work-today" in css and "min-height:44px" in css
|
|
||||||
|
|
||||||
|
|
||||||
def test_find_work_search_ignores_stale_response_and_preserves_cross_query_selection():
|
def test_find_work_search_ignores_stale_response_and_preserves_cross_query_selection():
|
||||||
script = f"""
|
script = f"""
|
||||||
const createFindWork=require({json.dumps(str(PICK_WORK))});
|
const createFindWork=require({json.dumps(str(PICK_WORK))});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user