feat: release 2.4.2 with batch human review badges
This commit is contained in:
1 parent
ac3d8cf54a
commit
b53ca18595
14 files changed
+192
-14
No files matched your search
@@ -30,6 +30,9 @@ npm run build
|
||||
|
||||
## Local Conventions
|
||||
|
||||
- 发版遵守根指南的 Release Gates。前端应用版本只改 package.json 顶层 `version` 和 package-lock.json 顶层及 `packages[""].version`;禁止把相同数字的第三方依赖一并替换。
|
||||
- Node 支持范围以锁定的 Angular CLI/构建依赖实际 `engines` 为准,核对启动脚本的主、次、补丁版本边界和提示;不要只判断“Node 22/24/26”。
|
||||
- 安装或依赖变更需在隔离目录、独立空 npm 缓存下运行 `npm ci`,再运行上述测试和构建;国内入口同时核验镜像安装。不得以关闭完整性校验、强制安装或删除锁文件掩盖不一致,也不得用已装依赖的构建结果宣称全新安装通过。
|
||||
- 页面组件在 src/app/components,服务在 src/app/services;先复用已有组件、样式及 API 服务。
|
||||
- 保持现有简体中文文案、颜色、间距和控件样式,菜单、弹窗和表单必须清晰可读。
|
||||
- 修改任务或配置交互时覆盖加载、保存、失败和空状态;不要将执行中误标成录屏中或把完成误标成验证通过。
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "artemis-showcase-ui",
|
||||
"version": "2.4.1",
|
||||
"version": "2.4.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "artemis-showcase-ui",
|
||||
"version": "2.4.1",
|
||||
"version": "2.4.2",
|
||||
"dependencies": {
|
||||
"@angular/cdk": "^22.2.4",
|
||||
"@angular/common": "^22.2.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "artemis-showcase-ui",
|
||||
"version": "2.4.1",
|
||||
"version": "2.4.2",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve --proxy-config proxy.conf.json",
|
||||
|
||||
+14
-1
@@ -108,6 +108,19 @@
|
||||
</div>
|
||||
}
|
||||
@if(b.report_error){<p class="error">报告生成失败:{{b.report_error}}</p>}
|
||||
@for(j of b.jobs; track j.session_id){<div class="job" [class.selected]="agent.currentSessionId() === j.session_id"><app-favorite-button [sourceId]="j.session_id" /><button (click)="openBatchTask(j.session_id)" [title]="j.case.goal" [attr.aria-pressed]="agent.currentSessionId() === j.session_id">{{j.case.case_id ? j.case.case_id + ' ' : ''}}{{j.case.name}}@if(j.repeat_count > 1){ · 第 {{j.iteration}} / {{j.repeat_count}} 轮}</button><span>{{label(j.status)}}</span><app-test-result-badge [result]="j.test_result" [executionStatus]="j.status" [compact]="true" />@if(j.error){<small>{{j.error}}</small>}</div>}
|
||||
@for(j of b.jobs; track j.session_id){
|
||||
<div class="job" [class.selected]="agent.currentSessionId() === j.session_id">
|
||||
<div class="job-heading">
|
||||
<app-favorite-button [sourceId]="j.session_id" />
|
||||
<button (click)="openBatchTask(j.session_id)" [title]="j.case.goal" [attr.aria-pressed]="agent.currentSessionId() === j.session_id">{{j.case.case_id ? j.case.case_id + ' ' : ''}}{{j.case.name}}@if(j.repeat_count > 1){ · 第 {{j.iteration}} / {{j.repeat_count}} 轮}</button>
|
||||
</div>
|
||||
<div class="job-statuses">
|
||||
<span>{{label(j.status)}}</span>
|
||||
<app-test-result-badge [result]="j.test_result" [executionStatus]="j.status" [compact]="true" />
|
||||
@if(j.human_reviewed){<span class="human-review-badge" title="人工评审已有保存内容,不代表测试通过">人工已审</span>}
|
||||
</div>
|
||||
@if(j.error){<small>{{j.error}}</small>}
|
||||
</div>
|
||||
}
|
||||
</section>}
|
||||
}
|
||||
+11
-1
@@ -37,7 +37,15 @@ input[type=checkbox]{width:15px;height:15px;accent-color:var(--app-primary-text,
|
||||
@keyframes archive-spin{to{transform:rotate(360deg);}}
|
||||
.code{font-family:Consolas,monospace;font-size:12px;line-height:1.6;resize:vertical;background:var(--app-surface-soft, #f8fafc);}.table-wrap{max-height:260px;overflow:auto;border:1px solid var(--app-border, #e2e8f0);border-radius:8px;margin-bottom:14px;}table{width:100%;border-collapse:collapse;}th,td{padding:9px 10px;border-bottom:1px solid var(--app-border, #e2e8f0);text-align:left;overflow-wrap:anywhere;}th{background:var(--app-surface-soft, #f8fafc);color:var(--app-text-secondary, #475569);font-weight:500;}
|
||||
.preview{white-space:pre-wrap;max-height:400px;overflow:auto;font:inherit;color:var(--app-text-control, #334155);background:var(--app-surface-soft, #f8fafc);border-radius:8px;padding:12px;border:1px solid var(--app-border, #e2e8f0);}
|
||||
.job{display:flex;flex-wrap:wrap;gap:8px;align-items:center;padding:10px 0;border-bottom:1px solid var(--app-border, #f1f5f9);}.job:last-child{border-bottom:0;}.job button{flex:1;justify-content:flex-start;text-align:left;min-width:150px;}.job span{font-size:12px;background:var(--app-surface-soft, #f1f5f9);color:var(--app-text-secondary, #475569);border-radius:5px;padding:3px 7px;}.job small{width:100%;}details{margin:14px 0;}summary{color:var(--app-text-secondary, #475569);cursor:pointer;padding:8px 0;}
|
||||
.job{display:flex;flex-direction:column;gap:8px;padding:12px 0;border-bottom:1px solid var(--app-border, #f1f5f9);}
|
||||
.job:last-child{border-bottom:0;}
|
||||
.job-heading{position:relative;min-width:0;}
|
||||
.job-heading>app-favorite-button{position:absolute;left:6px;top:4px;z-index:1;}
|
||||
.job-heading>button{box-sizing:border-box;width:100%;min-width:0;padding-left:40px;justify-content:flex-start;text-align:left;overflow-wrap:anywhere;}
|
||||
.job-statuses{display:flex;flex-wrap:wrap;align-items:center;gap:8px;}
|
||||
.job-statuses>span{display:inline-flex;align-items:center;box-sizing:border-box;height:20px;padding:0 6px;border:1px solid transparent;border-radius:5px;font-size:11px;line-height:14px;background:var(--app-surface-soft, #f1f5f9);color:var(--app-text-secondary, #475569);white-space:nowrap;}
|
||||
.job small{overflow-wrap:anywhere;}
|
||||
details{margin:14px 0;}summary{color:var(--app-text-secondary, #475569);cursor:pointer;padding:8px 0;}
|
||||
.task-guidance{margin-top:16px;padding:14px;border:1px solid var(--app-primary-border, #bfdbfe);border-radius:10px;background:var(--app-primary-soft, #f8fbff);}
|
||||
.task-guidance label{margin:8px 0 4px;}
|
||||
.report-overview{padding:14px;border:1px solid var(--app-primary-border, #dbeafe);border-radius:10px;background:var(--app-primary-soft, #f8fbff);}
|
||||
@@ -58,3 +66,5 @@ input[type=checkbox]{width:15px;height:15px;accent-color:var(--app-primary-text,
|
||||
table{width:100%;border-collapse:collapse;font-size:12px;}th,td{padding:7px 9px;border:1px solid var(--app-border, #e2e8f0);vertical-align:top;}th{background:var(--app-primary-soft, #eff6ff);color:var(--app-primary-text, #1e3a8a);}
|
||||
.md-para-gap{height:8px;}
|
||||
}
|
||||
|
||||
.job .human-review-badge{white-space:nowrap;border:1px solid var(--app-primary-border, #bfdbfe);background:var(--app-primary-soft, #eff6ff);color:var(--app-primary-text, #1d4ed8);font-weight:500;}
|
||||
+25
-1
@@ -90,6 +90,30 @@ describe('AutomationPanelComponent batch deletion', () => {
|
||||
expect(http.post).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('shows only saved human review badges and removes them on a batch refresh', async () => {
|
||||
const fixture = TestBed.createComponent(AutomationPanelComponent);
|
||||
const component = fixture.componentInstance;
|
||||
await new Promise<void>(resolve => setTimeout(resolve, 0));
|
||||
component.tab.set('batches');
|
||||
const batch = { id: 'review-batch', name: '评审批次', status: 'completed', jobs: [
|
||||
{ session_id: 'reviewed', status: 'completed', human_reviewed: true, case: { name: '已评用例' } },
|
||||
{ session_id: 'empty', status: 'completed', human_reviewed: false, case: { name: '空白用例' } },
|
||||
{ session_id: 'legacy', status: 'completed', case: { name: '旧版任务' } }
|
||||
] };
|
||||
component.batch.set(batch);
|
||||
fixture.detectChanges();
|
||||
const rows = fixture.nativeElement.querySelectorAll('.job');
|
||||
expect(rows[0].querySelector('.human-review-badge').textContent).toBe('人工已审');
|
||||
expect(rows[1].querySelector('.human-review-badge')).toBeNull();
|
||||
expect(rows[2].querySelector('.human-review-badge')).toBeNull();
|
||||
expect(fixture.nativeElement.textContent).not.toContain('人工未审');
|
||||
(http.get.and as any).callFake((url: string) => of(url.endsWith('/review-batch')
|
||||
? { ...batch, jobs: batch.jobs.map(job => ({ ...job, human_reviewed: false })) } : []));
|
||||
await component.refresh();
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('.human-review-badge')).toBeNull();
|
||||
});
|
||||
|
||||
it('confirms deletion and removes the batch from the visible list', async () => {
|
||||
const fixture = TestBed.createComponent(AutomationPanelComponent);
|
||||
fixture.componentInstance.tab.set('batches');
|
||||
@@ -129,7 +153,7 @@ describe('AutomationPanelComponent batch deletion', () => {
|
||||
{session_id:'task-b',status:'completed',case:{name:'用例 B',goal:'观察主页'}}
|
||||
]});
|
||||
fixture.detectChanges();
|
||||
const jobs: HTMLButtonElement[] = [...fixture.nativeElement.querySelectorAll('.job > button')];
|
||||
const jobs: HTMLButtonElement[] = [...fixture.nativeElement.querySelectorAll('.job-heading > button')];
|
||||
jobs[0].click(); jobs[1].click();
|
||||
expect(agent.selectSession.calls.allArgs()).toEqual([['task-a',true],['task-b',true]]);
|
||||
expect(component.tab()).toBe('batches');
|
||||
|
||||
Reference in new issue
Block a user