feat: file related issues from confirmed receipts (Closes #868)
This commit is contained in:
1 parent
7a31ea5cba
commit
4b88e1a533
8 files changed
+213
-15
No files matched your search
@@ -69,6 +69,26 @@ controller.show({{repository:'stackchain/dashboard',number:867,title:'Unowned fo
|
||||
}
|
||||
|
||||
|
||||
def test_related_action_returns_only_the_confirmed_reusable_plan():
|
||||
script = f"""
|
||||
const createReceipt = require({json.dumps(str(RECEIPT))});
|
||||
const element = () => ({{hidden:true,focusCount:0,focus(){{this.focusCount++;}},addEventListener(name, fn){{this[name]=fn;}}}});
|
||||
const elements = {{root:element(),heading:element(),key:element(),title:element(),ownership:element(),openLink:element(),shareButton:element(),relatedButton:element(),fileAnotherButton:element(),doneButton:element(),status:element()}};
|
||||
const plans=[];
|
||||
const controller=createReceipt({{...elements,onFileRelated:plan=>plans.push(plan)}});
|
||||
const plan={{repository:'stackchain/dashboard',title:'',body:'## Bug',labelIds:[7],templateId:'bug.yml'}};
|
||||
controller.show({{repository:'stackchain/dashboard',number:868,title:'Filed',assignees:[],url:'https://forge.example/issues/868'}},elements.doneButton,plan);
|
||||
elements.relatedButton.click();
|
||||
process.stdout.write(JSON.stringify({{plans,hidden:elements.root.hidden,restored:elements.doneButton.focusCount}}));
|
||||
"""
|
||||
output = run_node(script)
|
||||
|
||||
assert output == {"plans": [{
|
||||
"repository": "stackchain/dashboard", "title": "", "body": "## Bug",
|
||||
"labelIds": [7], "templateId": "bug.yml",
|
||||
}], "hidden": True, "restored": 1}
|
||||
|
||||
|
||||
def test_mobile_shell_wires_confirmed_non_my_work_issues_to_the_receipt():
|
||||
index = INDEX.read_text()
|
||||
css = CSS.read_text()
|
||||
@@ -78,6 +98,7 @@ def test_mobile_shell_wires_confirmed_non_my_work_issues_to_the_receipt():
|
||||
assert 'id="issue-filing-receipt-heading"' in index
|
||||
assert 'id="issue-filing-receipt-open"' in index
|
||||
assert 'id="issue-filing-receipt-share"' in index
|
||||
assert 'id="issue-filing-receipt-related"' in index
|
||||
assert 'id="issue-filing-receipt-another"' in index
|
||||
assert 'id="issue-filing-receipt-done"' in index
|
||||
assert '<script src="static/issue-filing-receipt.js"></script>' in index
|
||||
@@ -86,4 +107,7 @@ def test_mobile_shell_wires_confirmed_non_my_work_issues_to_the_receipt():
|
||||
assert '.issue-filing-receipt-actions' in css
|
||||
assert 'min-height:44px' in css
|
||||
assert 'createIssueFilingReceipt({' in dashboard
|
||||
assert "issueFilingReceipt.show(confirmed, qs('#new-issue'))" in dashboard
|
||||
assert "relatedButton:qs('#issue-filing-receipt-related')" in dashboard
|
||||
assert 'relatedDraft:issueCapture.buildRelatedDraft(durableDraft)' in dashboard
|
||||
assert "issueCapture.saveDraft(plan)" in dashboard
|
||||
assert "issueFilingReceipt.show(confirmed, qs('#new-issue'), filing?.relatedDraft)" in dashboard
|
||||
@@ -44,6 +44,61 @@ confirmedLogin = 'alexander';
|
||||
assert len(output["calls"]) == 1
|
||||
|
||||
|
||||
def test_confirmed_delivery_returns_the_safe_related_plan_without_sending_it_to_gitea():
|
||||
script = f"""
|
||||
const createIssueOutbox = require({json.dumps(str(OUTBOX))});
|
||||
const values=new Map();
|
||||
const storage={{getItem:key=>values.get(key)||null,setItem:(key,value)=>values.set(key,value),removeItem:key=>values.delete(key)}};
|
||||
let sentBody;
|
||||
const outbox=createIssueOutbox({{
|
||||
storage,getOwnerLogin:()=> 'timmy',createOperationId:()=> 'first-operation',
|
||||
fetchJson:async (_url,options)=>{{sentBody=JSON.parse(options.body);return {{repository:'stackchain/dashboard',number:869,title:'Related source',assignees:[]}};}},
|
||||
}});
|
||||
outbox.enqueue({{
|
||||
repository:'stackchain/dashboard',title:'Related source',body:'Filled report',labelIds:[7],
|
||||
relatedDraft:{{repository:'stackchain/dashboard',title:'',body:'## Bug',labelIds:[7],templateId:'bug.yml',templateName:'Bug report',capturedBody:''}},
|
||||
}});
|
||||
outbox.flush('timmy').then(result=>process.stdout.write(JSON.stringify({{result,sentBody}})));
|
||||
"""
|
||||
output = run_node(script)
|
||||
|
||||
assert output["result"]["filings"] == [{
|
||||
"issue": {"repository": "stackchain/dashboard", "number": 869,
|
||||
"title": "Related source", "assignees": []},
|
||||
"relatedDraft": {"repository": "stackchain/dashboard", "title": "",
|
||||
"body": "## Bug", "labelIds": [7], "templateId": "bug.yml",
|
||||
"templateName": "Bug report", "capturedBody": ""},
|
||||
}]
|
||||
assert "relatedDraft" not in output["sentBody"]
|
||||
|
||||
|
||||
def test_editing_a_queued_issue_refreshes_its_related_plan():
|
||||
script = f"""
|
||||
const createIssueOutbox = require({json.dumps(str(OUTBOX))});
|
||||
const values=new Map();
|
||||
const storage={{getItem:key=>values.get(key)||null,setItem:(key,value)=>values.set(key,value),removeItem:key=>values.delete(key)}};
|
||||
let sequence=0;
|
||||
const outbox=createIssueOutbox({{
|
||||
storage,getOwnerLogin:()=> 'timmy',createOperationId:()=> 'operation-' + (++sequence),
|
||||
fetchJson:async ()=>({{repository:'stackchain/dashboard',number:870,title:'Edited',assignees:[]}}),
|
||||
}});
|
||||
const queued=outbox.enqueue({{
|
||||
repository:'stackchain/dashboard',title:'Original',body:'One',
|
||||
relatedDraft:{{repository:'stackchain/dashboard',title:'',body:'Old scaffold',labelIds:[1]}},
|
||||
}});
|
||||
outbox.update(queued.id,{{
|
||||
repository:'stackchain/dashboard',title:'Edited',body:'Two',
|
||||
relatedDraft:{{repository:'stackchain/dashboard',title:'',body:'New scaffold',labelIds:[2]}},
|
||||
}});
|
||||
outbox.flush('timmy').then(result=>process.stdout.write(JSON.stringify(result.filings[0].relatedDraft)));
|
||||
"""
|
||||
|
||||
assert run_node(script) == {
|
||||
"repository": "stackchain/dashboard", "title": "", "body": "New scaffold",
|
||||
"labelIds": [2],
|
||||
}
|
||||
|
||||
|
||||
def test_issue_outbox_queues_multiple_planned_issues_with_stable_operation_ids():
|
||||
script = f"""
|
||||
const createIssueOutbox = require({json.dumps(str(OUTBOX))});
|
||||
@@ -968,7 +1023,7 @@ async def test_mobile_dashboard_queues_offline_captures_and_exposes_outbox_actio
|
||||
|
||||
assert '<script src="static/issue-outbox.js"></script>' in html
|
||||
assert "const issueOutbox = createIssueOutbox({" in html
|
||||
assert "await issueOutbox.enqueueDurably(durableDraft)" in html
|
||||
assert "await issueOutbox.enqueueDurably(deliveryDraft)" in html
|
||||
assert "Saving for background delivery…" in html
|
||||
assert "Saved for next launch; background delivery unavailable." in html
|
||||
assert "throw new Error('Background Sync unavailable')" in html
|
||||
|
||||
@@ -1578,6 +1578,40 @@ Promise.all([first, duplicate]).then(results => process.stdout.write(JSON.string
|
||||
assert output["results"][0]["available"] is True
|
||||
|
||||
|
||||
def test_related_issue_draft_reuses_plan_but_resets_issue_specific_work():
|
||||
script = f"""
|
||||
const createIssueSheet = require({json.dumps(str(CREATE_ISSUE_SHEET))});
|
||||
const related = createIssueSheet.buildRelatedDraft({{
|
||||
repository:'stackchain/dashboard', title:'Completed discovery', body:'Filled private report',
|
||||
labelIds:[7, 7, 9], milestoneId:4, dueDate:'2026-08-20',
|
||||
assignee:'alex', assigneeName:'Alexander', unassigned:false,
|
||||
templateId:'bug.yml', templateName:'Bug report', capturedBody:'Original notes',
|
||||
blockers:[{{repository:'stackchain/api',number:2}}], estimateMinutes:45,
|
||||
completionIntent:'create-and-start', operationId:'already-delivered',
|
||||
attachment:{{name:'secret.png'}}, duplicateAcknowledged:true,
|
||||
}}, {{id:'bug.yml', name:'Bug report', body:'## What happened?\\n\\n## Expected'}});
|
||||
process.stdout.write(JSON.stringify(related));
|
||||
"""
|
||||
result = subprocess.run(["node", "-e", script], capture_output=True, text=True)
|
||||
|
||||
assert result.returncode == 0, result.stderr
|
||||
output = json.loads(result.stdout)
|
||||
|
||||
assert output == {
|
||||
"repository": "stackchain/dashboard",
|
||||
"title": "",
|
||||
"body": "## What happened?\n\n## Expected",
|
||||
"labelIds": [7, 9],
|
||||
"milestoneId": 4,
|
||||
"dueDate": "2026-08-20",
|
||||
"assignee": "alex",
|
||||
"assigneeName": "Alexander",
|
||||
"templateId": "bug.yml",
|
||||
"templateName": "Bug report",
|
||||
"capturedBody": "",
|
||||
}
|
||||
|
||||
|
||||
def test_issue_release_rejects_response_that_still_assigns_current_user():
|
||||
script = f"""
|
||||
const createIssueSheet = require({json.dumps(str(ISSUE_SHEET))});
|
||||
|
||||
Reference in new issue
Block a user