perf: lazy-load pull request workspace (Closes #541)
This commit is contained in:
parent
3605c42651
commit
7d4ff1f095
|
|
@ -269,11 +269,8 @@
|
|||
}
|
||||
return payload;
|
||||
}
|
||||
const reviewController = createReviewController({ fetchJson: fetchReviewJson, storage: localStorage });
|
||||
const wrapPreference = createReviewController.createWrapPreference({
|
||||
storage: localStorage,
|
||||
mobile: window.matchMedia('(max-width: 600px)').matches,
|
||||
});
|
||||
let reviewController = null;
|
||||
let wrapPreference = null;
|
||||
const issueController = createIssueSheet({ fetchJson: fetchReviewJson, storage: localStorage });
|
||||
const issueAttachmentController = issueAttachment.mount({
|
||||
input: qs('#issue-attachment'),
|
||||
|
|
@ -438,7 +435,27 @@
|
|||
});
|
||||
}
|
||||
if (Object.values(sharedLaunch).some(Boolean)) await ensureIssueCapture();
|
||||
const pullController = createPullSheet({ fetchJson: fetchReviewJson, storage: localStorage });
|
||||
const pullWorkflowFeatures = createFeatureLoader({
|
||||
document,
|
||||
urls: {
|
||||
'pull-workflow': document.querySelector('meta[name="stackchain-feature-pull-workflow"]')?.content || '',
|
||||
},
|
||||
});
|
||||
let pullController = null;
|
||||
async function ensurePullWorkflow(trigger = null) {
|
||||
return await pullWorkflowFeatures.run('pull-workflow', {
|
||||
trigger, status: qs('#my-work-action-status'), retryLabel:'Tap the work card to retry.',
|
||||
}, () => {
|
||||
if (!pullController) pullController = createPullSheet({ fetchJson: fetchReviewJson, storage: localStorage });
|
||||
if (!reviewController) reviewController = createReviewController({ fetchJson: fetchReviewJson, storage: localStorage });
|
||||
if (!wrapPreference) {
|
||||
wrapPreference = createReviewController.createWrapPreference({
|
||||
storage: localStorage,
|
||||
mobile: window.matchMedia('(max-width: 600px)').matches,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
const draftInbox = createDraftInbox({ storage: localStorage, getCurrentLogin: () => activeFlushLogin });
|
||||
outboxCoordinator.subscribe(() => refreshMyWorkView());
|
||||
const offlineWorkStore = createOfflineWorkStore({ storage: localStorage, indexedDB:window.indexedDB });
|
||||
|
|
@ -456,8 +473,13 @@
|
|||
retry.hidden = status.failed === 0;
|
||||
}
|
||||
const offlineToday = createOfflineToday({
|
||||
loadDetail: item => item.is_review ? reviewController.load(item) :
|
||||
item.kind === 'pull' ? pullController.load(item) : issueController.load(item),
|
||||
loadDetail: async item => {
|
||||
if (item.is_review || item.kind === 'pull') {
|
||||
if (!await ensurePullWorkflow()) throw new Error('Pull workspace is unavailable.');
|
||||
return item.is_review ? reviewController.load(item) : pullController.load(item);
|
||||
}
|
||||
return issueController.load(item);
|
||||
},
|
||||
loadSavedDetail: (login, item) => offlineWorkStore.loadDetail(login, item),
|
||||
saveDetail: (login, item, detail) => offlineWorkStore.saveDetail(login, item, detail),
|
||||
onStatus: renderOfflineTodayStatus,
|
||||
|
|
@ -2588,6 +2610,7 @@
|
|||
|
||||
async function openPullSheet(item, trigger, offlineDetail = null) {
|
||||
if (!item) return;
|
||||
if (!await ensurePullWorkflow(trigger)) return;
|
||||
if (!sameWorkTarget(selectedPull, item)) pullAttachmentController.clear();
|
||||
qs('#pull-review').inert = false;
|
||||
selectedPull = item;
|
||||
|
|
@ -3144,6 +3167,7 @@
|
|||
}
|
||||
|
||||
async function openReviewSheet(item, trigger, cachedDetail = null) {
|
||||
if (!item || !await ensurePullWorkflow(trigger)) return;
|
||||
selectedReview = item;
|
||||
reviewTrigger = trigger;
|
||||
offlineReview = Boolean(cachedDetail);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ function createFeatureLoader({ document, urls, timeoutMs = 10000 }) {
|
|||
async function run(name, elements, callback) {
|
||||
const trigger = elements?.trigger;
|
||||
const status = elements?.status;
|
||||
const retryLabel = elements?.retryLabel || 'Tap New issue to retry.';
|
||||
if (trigger) trigger.disabled = true;
|
||||
if (status) status.textContent = 'Loading ' + name.replace(/-/g, ' ') + '…';
|
||||
try {
|
||||
|
|
@ -45,8 +46,9 @@ function createFeatureLoader({ document, urls, timeoutMs = 10000 }) {
|
|||
return true;
|
||||
} catch (_error) {
|
||||
if (status) {
|
||||
const label = name === 'issue-capture' ? 'Issue capture' : name.replace(/-/g, ' ');
|
||||
status.textContent = label + ' could not load. Tap New issue to retry.';
|
||||
const label = name === 'issue-capture' ? 'Issue capture' :
|
||||
name === 'pull-workflow' ? 'Pull workspace' : name.replace(/-/g, ' ');
|
||||
status.textContent = label + ' could not load. ' + retryLabel;
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,10 @@ import rjsmin
|
|||
|
||||
SCRIPT_TAG = re.compile(r'^<script src="(static/[^"?]+\.js)"></script>$', re.MULTILINE)
|
||||
WORKER_RUNTIME_SOURCE = "static/background-issue-sync.js"
|
||||
FEATURE_SOURCES = {"issue-capture": ("static/create-issue-sheet.js",)}
|
||||
FEATURE_SOURCES = {
|
||||
"issue-capture": ("static/create-issue-sheet.js",),
|
||||
"pull-workflow": ("static/pull-sheet.js", "static/review-sheet.js"),
|
||||
}
|
||||
CACHE_DECLARATION = re.compile(
|
||||
r"const CACHE = 'stackchain-dashboard-shell-(?:v\d+|[0-9a-f]{16})';"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -68,4 +68,24 @@ console.log(JSON.stringify({loading,failedState,first,second,opened,finalStatus:
|
|||
"second": True,
|
||||
"opened": 1,
|
||||
"finalStatus": "",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def test_pull_workspace_failure_is_accessible_and_retryable_from_same_card():
|
||||
result = run_loader("""
|
||||
const trigger={disabled:false}; const status={textContent:''}; let opened=0;
|
||||
const loader=createFeatureLoader({document, urls:{'pull-workflow':'feature-pull.js'}, timeoutMs:100});
|
||||
const failed=loader.run('pull-workflow',{trigger,status,retryLabel:'Tap the work card to retry.'},()=>{opened++;});
|
||||
state.node.onerror(); const first=await failed;
|
||||
const failedStatus=status.textContent;
|
||||
const retry=loader.run('pull-workflow',{trigger,status,retryLabel:'Tap the work card to retry.'},()=>{opened++;});
|
||||
state.node.onload(); const second=await retry;
|
||||
console.log(JSON.stringify({first,second,failedStatus,opened,appends:state.appends}));
|
||||
""")
|
||||
assert result == {
|
||||
"first": False,
|
||||
"second": True,
|
||||
"failedStatus": "Pull workspace could not load. Tap the work card to retry.",
|
||||
"opened": 1,
|
||||
"appends": 2,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,15 +42,23 @@ def test_page_runtime_is_one_deterministic_content_addressed_bundle(tmp_path):
|
|||
assert changed.runtime_bytes != first.runtime_bytes
|
||||
|
||||
|
||||
def test_issue_capture_is_a_stable_lazy_feature_chunk(tmp_path):
|
||||
def test_product_workflows_are_stable_lazy_feature_chunks(tmp_path):
|
||||
first = build_frontend(FRONTEND)
|
||||
|
||||
assert set(first.feature_bundles) == {"issue-capture"}
|
||||
assert set(first.feature_bundles) == {"issue-capture", "pull-workflow"}
|
||||
capture = first.feature_bundles["issue-capture"]
|
||||
pull_workflow = first.feature_bundles["pull-workflow"]
|
||||
assert b"function createIssueCapture" not in first.runtime_bytes
|
||||
assert b"function createIssueCapture" in capture.runtime_bytes
|
||||
assert b"function createPullSheet" not in first.runtime_bytes
|
||||
assert b"function createReviewController" not in first.runtime_bytes
|
||||
assert b"function createPullSheet" in pull_workflow.runtime_bytes
|
||||
assert b"function createReviewController" in pull_workflow.runtime_bytes
|
||||
assert len(first.runtime_gzip_bytes) <= 95 * 1024
|
||||
assert f'name="stackchain-feature-issue-capture" content="{capture.runtime_name}"' in first.dashboard_html
|
||||
assert f'name="stackchain-feature-pull-workflow" content="{pull_workflow.runtime_name}"' in first.dashboard_html
|
||||
assert f"BASE + '{capture.runtime_name}'" in first.service_worker_source
|
||||
assert f"BASE + '{pull_workflow.runtime_name}'" in first.service_worker_source
|
||||
|
||||
changed_frontend = tmp_path / "frontend"
|
||||
shutil.copytree(FRONTEND, changed_frontend)
|
||||
|
|
@ -61,6 +69,12 @@ def test_issue_capture_is_a_stable_lazy_feature_chunk(tmp_path):
|
|||
assert changed.runtime_name == first.runtime_name
|
||||
assert changed.feature_bundles["issue-capture"].runtime_name != capture.runtime_name
|
||||
|
||||
pull_source = changed_frontend / "pull-sheet.js"
|
||||
pull_source.write_text(pull_source.read_text() + "\n// pull-workflow-only change\n")
|
||||
pull_changed = build_frontend(changed_frontend)
|
||||
assert pull_changed.runtime_name == first.runtime_name
|
||||
assert pull_changed.feature_bundles["pull-workflow"].runtime_name != pull_workflow.runtime_name
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_feature_chunk_is_immutable_and_rejects_unknown_revision():
|
||||
|
|
|
|||
|
|
@ -4279,7 +4279,10 @@ async def test_assigned_pulls_open_accessible_mobile_completion_sheet():
|
|||
assert "pullConversation.append(comment)" in html
|
||||
assert 'id="pull-comment"' in html and 'maxlength="10000"' in html
|
||||
assert 'id="merge-pull"' in html and 'id="open-pull-gitea"' in html
|
||||
assert '<script src="static/pull-sheet.js"></script>' in html
|
||||
assert 'stackchain-feature-pull-workflow' in html
|
||||
assert "pullWorkflowFeatures.run('pull-workflow'" in html
|
||||
assert "let pullController = null" in html
|
||||
assert "let reviewController = null" in html
|
||||
assert "pullController.load(item)" in html
|
||||
assert "createPullSheet.renderFile" in html
|
||||
assert "pullController.toggleReviewed" in html
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user