Simplify daily review UI and compact header cards
This commit is contained in:
1 parent
6d1a98743f
commit
64f4a0d3de
13 files changed
+185
-133
No files matched your search
@@ -318,21 +318,23 @@ test('pending date labels have Chinese, English and Thai translations',()=>{
|
||||
assert.equal(catalog['arr_download.pending_price'][0],'待复核价格');
|
||||
});
|
||||
|
||||
test('cancelled source rows need no fields and the exclusion stays visible before continuation',async()=>{
|
||||
test('cancelled source exclusions need no fields or summary and still permit continuation',async()=>{
|
||||
const h=harness(()=>response(200,{...review([]),excluded_cancelled_count:6}));
|
||||
await h.acceptARRDownloadTask(task,{sync:false});
|
||||
assert.equal(h.element('#arr-data-review-body').innerHTML,'');
|
||||
assert.match(h.element('#arr-data-review-progress').textContent,/data_review\.excluded_cancelled/);
|
||||
assert.equal(h.element('#arr-data-review-progress').textContent,'');
|
||||
assert.equal(h.state.arrDataReview.excluded_cancelled_count,6);
|
||||
assert.equal(h.element('#arr-data-review-finalize').disabled,false);
|
||||
assert.equal(h.calls.every(call=>call.method==='GET'),true);
|
||||
});
|
||||
|
||||
test('PM exclusions stay visible without requiring field completion',async()=>{
|
||||
test('PM exclusions retain their original state without displaying a summary or requiring fields',async()=>{
|
||||
const h=harness(()=>response(200,{...review([]),excluded_cancelled_count:6,excluded_pm_count:19}));
|
||||
await h.acceptARRDownloadTask(task,{sync:false});
|
||||
const progress=h.element('#arr-data-review-progress').textContent;
|
||||
assert.match(progress,/data_review\.excluded_cancelled/);
|
||||
assert.match(progress,/data_review\.excluded_pm/);
|
||||
assert.equal(progress,'');
|
||||
assert.equal(h.state.arrDataReview.excluded_cancelled_count,6);
|
||||
assert.equal(h.state.arrDataReview.excluded_pm_count,19);
|
||||
assert.equal(h.element('#arr-data-review-body').innerHTML,'');
|
||||
assert.equal(h.element('#arr-data-review-finalize').disabled,false);
|
||||
assert.equal(h.calls.every(call=>call.method==='GET'),true);
|
||||
@@ -383,39 +385,41 @@ for (const fixture of [
|
||||
{name:'confirmed decisions show the saved confirmation instead of the original problem',
|
||||
source_state:'failed', reason_code:'http_failure', confirmed:true, value:'VERIFIED', expected:'confirmed_value'},
|
||||
]) {
|
||||
test(`field review explanation: ${fixture.name}`,async()=>{
|
||||
test(`compact field review preserves decisions without explanatory metadata: ${fixture.name}`,async()=>{
|
||||
const source=item(fixture);
|
||||
const original=plain(source);
|
||||
const h=harness(()=>response(200,review([source])));
|
||||
await h.acceptARRDownloadTask(task,{sync:false});
|
||||
const markup=h.element('#arr-data-review-body').innerHTML;
|
||||
assert.match(markup,new RegExp(`data_review\\.${fixture.expected}\\b`));
|
||||
assert.match(markup,new RegExp(`data_review\\.${source.can_be_empty?'optional':'required'}_field_rule\\b`));
|
||||
assert.doesNotMatch(markup,/<small>|data_review\.(?:optional_field_rule|required_field_rule|source_row|room_missing_in_scope|source_unconfirmed|fetch_failed|conflict_value|invalid_value|confirmed_value)/);
|
||||
assert.match(markup,new RegExp(`<label[^>]+>${source.field_label}</label>`));
|
||||
assert.match(markup,/<strong>SYNTHETIC-001<\/strong>/);
|
||||
assert.doesNotMatch(markup,/Synthetic Company|SYNTHETIC-ROOM|<small>/);
|
||||
assert.equal((markup.match(/<td /g)||[]).length,4);
|
||||
assert.match(markup,/data-arr-data-review-value/);
|
||||
assert.match(markup,/data-arr-data-review-save/);
|
||||
assert.match(markup,new RegExp(source.confirmed?'data_review.confirmed':'data_review.pending'));
|
||||
assert.equal(markup.includes('data_review.missing_value'),false);
|
||||
assert.equal(markup.includes('data-arr-data-review-empty'),source.can_be_empty);
|
||||
assert.deepEqual(plain(source),original,'rendering explanations never changes a source or confirmation');
|
||||
assert.deepEqual(plain(source),original,'a compact display never changes source metadata or confirmation');
|
||||
assert.equal(h.calls.every(call=>call.method==='GET'),true);
|
||||
});
|
||||
}
|
||||
|
||||
test('review explanations have distinct Chinese, English and Thai copy for required, optional and failed reads',()=>{
|
||||
test('compact review controls and validation messages remain available in Chinese, English and Thai',()=>{
|
||||
const context=vm.createContext({window:{},document:{readyState:'loading',addEventListener(){}}});
|
||||
vm.runInContext(fs.readFileSync(path.resolve(__dirname,'../../arr_web/static/i18n.js'),'utf8'),context);
|
||||
const catalog=context.window.ARRI18n.CATALOG;
|
||||
const keys=['required_field_rule','optional_field_rule','required_value_missing','room_missing_in_scope','source_unconfirmed',
|
||||
'fetch_failed','conflict_value','invalid_value'];
|
||||
const keys=['save','confirm_empty','confirmed','pending','field_block_code','field_disp_room_no','use_empty',
|
||||
'complete_first','conflict','disconnected','invalid','required','integer_required'];
|
||||
for(const key of keys) {
|
||||
const translations=catalog[`data_review.${key}`];
|
||||
assert.equal(translations.length,3);
|
||||
translations.forEach(text=>assert.equal(typeof text==='string' && text.length>0,true));
|
||||
}
|
||||
assert.match(catalog['data_review.required_field_rule'][0],/原处理规则必填/);
|
||||
assert.match(catalog['data_review.optional_field_rule'][0],/允许为空/);
|
||||
assert.match(catalog['data_review.room_missing_in_scope'][0],/费率在处理范围内/);
|
||||
assert.match(catalog['data_review.source_unconfirmed'][0],/确认无此信息/);
|
||||
assert.match(catalog['data_review.fetch_failed'][0],/不能直接认定没有此信息/);
|
||||
assert.equal(catalog['data_review.fetch_failed'][0].includes('刷新'),false,
|
||||
'refreshing the review must not imply a retry of Oracle acquisition');
|
||||
assert.equal(catalog['arr_acquisition.label'][0],'状态');
|
||||
assert.equal(catalog['arr_acquisition.label'][1],'Status');
|
||||
assert.equal(catalog['arr_download.date_independent'],undefined);
|
||||
});
|
||||
|
||||
test('source review opens before a job exists and another date can start its own download',async()=>{
|
||||
@@ -423,7 +427,8 @@ test('source review opens before a job exists and another date can start its own
|
||||
? response(202,{...JSON.parse(options.body),status:'queued',job_id:null,can_retry:false})
|
||||
: response(200,review([item()])));
|
||||
await h.acceptARRDownloadTask(task,{sync:false});
|
||||
assert.equal(h.element('#arr-download-data-review').hidden,false);
|
||||
assert.equal(h.element('#arr-download-button').textContent,'arr_download.complete_data');
|
||||
assert.equal(h.element('#arr-download-help').hidden,true);
|
||||
assert.equal(h.element('#arr-data-review-panel').hidden,false);
|
||||
assert.equal(h.element('#arr-download-review').hidden,true);
|
||||
assert.equal(h.element('#arr-data-review-finalize').disabled,true);
|
||||
@@ -586,7 +591,7 @@ test('revision conflict reloads the current revision before any next save',async
|
||||
|
||||
test('unconfirmed source values are never prefilled and all labels and stored values are escaped',async()=>{
|
||||
const h=harness(()=>response(200,review([
|
||||
item({company_name:'<img src=x onerror=alert(1)>',value:'GUESSED-BLOCK'}),
|
||||
item({company_name:'<img src=x onerror=alert(1)>',confirmation_no:'<img src=x onerror=alert(1)>',value:'GUESSED-BLOCK'}),
|
||||
item({item_id:'2:RES_COMMENT',field:'RES_COMMENT',confirmed:true,value:'</textarea><script>bad()</script>'}),
|
||||
])));
|
||||
await h.acceptARRDownloadTask(task,{sync:false});
|
||||
|
||||
@@ -74,7 +74,7 @@ test('completed retrieval remains distinct from pending field and price review',
|
||||
assert.equal(h.element('#arr-acquisition-status').textContent,'已完成');
|
||||
assert.equal(h.element('#arr-acquisition-percent').textContent,'100%');
|
||||
assert.equal(h.element('#arr-acquisition-detail').textContent,'已获取 85 / 85 笔');
|
||||
if(status==='needs_data_review') assert.equal(h.element('#arr-download-data-review').hidden,false);
|
||||
if(status==='needs_data_review') assert.equal(h.element('#arr-download-button').textContent,'完善报表字段');
|
||||
if(status==='needs_review') assert.equal(h.element('#arr-download-review').hidden,false);
|
||||
assert.doesNotMatch(h.element('#arr-acquisition-detail').textContent,/生成|报表已完成/);
|
||||
}
|
||||
|
||||
@@ -19,8 +19,16 @@ test('zero is a valid explicit price while blank and negative prices remain inva
|
||||
|
||||
test('zero is rendered as a saved value and permits continuation when all items are saved',()=>{
|
||||
const h=harness(()=>{throw new Error('unexpected request');});
|
||||
h.renderDailyPriceReview(fixture(0));
|
||||
const review=fixture(0);
|
||||
review.items[0].candidate_prices=[{effective_rate_amount:888888,real_price:999999}];
|
||||
review.items[0].affected_records=333333;
|
||||
h.renderDailyPriceReview(review);
|
||||
const html=h.element('#daily-price-review-body').innerHTML;
|
||||
assert.equal((html.match(/<td /g)||[]).length,5);
|
||||
assert.match(html,/Fixture Company|FIXTURE/);
|
||||
assert.match(html,/>100<\/td>/);
|
||||
assert.doesNotMatch(html,/888888|999999|333333|daily-price-review-candidates/);
|
||||
assert.match(html,/aria-describedby="daily-price-review-message"/);
|
||||
assert.match(html,/value="0"/);
|
||||
assert.match(html,/daily-price-review-row is-complete/);
|
||||
assert.match(html,/daily_review.saved/);
|
||||
|
||||
@@ -62,6 +62,19 @@ test('a successful replacement displays only the accepted new report for the sam
|
||||
assert.doesNotMatch(h.element('#jobs-body').innerHTML,/job_id=old/);
|
||||
});
|
||||
|
||||
test('history access appears only when the date has historical versions while current download and delete remain available',()=>{
|
||||
const h=setup();
|
||||
for(const count of [0,undefined,1,2]) {
|
||||
h.state.dailyReports=[day(job('current'),undefined,{history_count:count})];
|
||||
h.renderJobs();
|
||||
const html=h.element('#jobs-body').innerHTML;
|
||||
assert.equal(html.includes(`data-daily-history="${date}"`),Number(count)>0);
|
||||
assert.match(html,/job_id=current/);
|
||||
assert.match(html,/data-daily-delete="current"/);
|
||||
}
|
||||
assert.equal(h.calls.length,0);
|
||||
});
|
||||
|
||||
test('a failed replacement never removes the valid old report',()=>{
|
||||
const h=setup();
|
||||
h.state.dailyReports=[day(job('old'),job('new',{status:'failed',is_current:false,daily_report_sha256:null}))];
|
||||
|
||||
Reference in new issue
Block a user