acdev 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/public/app.js +113 -36
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -108,6 +108,10 @@ let reviewSearch = loadReviewSearch();
|
|
|
108
108
|
let activeInlineCommentKey = null;
|
|
109
109
|
/** @type {string | null} id of line comment currently being edited */
|
|
110
110
|
let editingCommentId = null;
|
|
111
|
+
/** @type {'inline' | 'pending' | null} where the edit form should render */
|
|
112
|
+
let editingCommentSurface = null;
|
|
113
|
+
/** Original body when edit started — restored on Cancel after live sync. */
|
|
114
|
+
let editingCommentOriginalBody = null;
|
|
111
115
|
/** @type {Record<string, {
|
|
112
116
|
* generalComment: string,
|
|
113
117
|
* lineComments: Array<{ id: string, path: string, line: number, side: 'LEFT' | 'RIGHT', body: string }>,
|
|
@@ -447,6 +451,8 @@ function clearReviewDraft(jobId) {
|
|
|
447
451
|
delete reviewDrafts[jobId];
|
|
448
452
|
activeInlineCommentKey = null;
|
|
449
453
|
editingCommentId = null;
|
|
454
|
+
editingCommentSurface = null;
|
|
455
|
+
editingCommentOriginalBody = null;
|
|
450
456
|
try {
|
|
451
457
|
sessionStorage.removeItem(reviewDraftStorageKey(jobId));
|
|
452
458
|
} catch {
|
|
@@ -454,6 +460,86 @@ function clearReviewDraft(jobId) {
|
|
|
454
460
|
}
|
|
455
461
|
}
|
|
456
462
|
|
|
463
|
+
/** Clear in-progress line-comment edit state. */
|
|
464
|
+
function clearCommentEditState() {
|
|
465
|
+
editingCommentId = null;
|
|
466
|
+
editingCommentSurface = null;
|
|
467
|
+
editingCommentOriginalBody = null;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* @param {string} jobId
|
|
472
|
+
* @param {string} commentId
|
|
473
|
+
* @param {string} body
|
|
474
|
+
*/
|
|
475
|
+
function updateLineCommentBody(jobId, commentId, body) {
|
|
476
|
+
const d = loadReviewDraft(jobId);
|
|
477
|
+
const target = d.lineComments.find((x) => x.id === commentId);
|
|
478
|
+
if (!target) return;
|
|
479
|
+
target.body = body;
|
|
480
|
+
saveReviewDraft(jobId);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Refresh the non-active edit surface so both views stay in sync.
|
|
485
|
+
* @param {string} jobId
|
|
486
|
+
*/
|
|
487
|
+
function mirrorCommentEditToOtherSurface(jobId) {
|
|
488
|
+
if (editingCommentSurface === 'inline') {
|
|
489
|
+
renderPendingCommentList(jobId);
|
|
490
|
+
syncSubmitReviewButton(jobId);
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
if (editingCommentSurface === 'pending') {
|
|
494
|
+
const job = jobsById[jobId];
|
|
495
|
+
if (job) {
|
|
496
|
+
const diff =
|
|
497
|
+
job.status === 'awaiting_review'
|
|
498
|
+
? filterDiffForReviewJob(job)
|
|
499
|
+
: job.diff || '';
|
|
500
|
+
renderDiff(diff, {
|
|
501
|
+
interactive: job.status === 'awaiting_review',
|
|
502
|
+
jobId,
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
syncSubmitReviewButton(jobId);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Commit or discard an in-progress comment edit.
|
|
511
|
+
* @param {string} jobId
|
|
512
|
+
* @param {string} commentId
|
|
513
|
+
* @param {string | null} nextBody null = cancel / restore original
|
|
514
|
+
*/
|
|
515
|
+
function finishCommentEdit(jobId, commentId, nextBody) {
|
|
516
|
+
if (nextBody == null) {
|
|
517
|
+
if (editingCommentOriginalBody != null) {
|
|
518
|
+
updateLineCommentBody(jobId, commentId, editingCommentOriginalBody);
|
|
519
|
+
}
|
|
520
|
+
} else {
|
|
521
|
+
updateLineCommentBody(jobId, commentId, nextBody);
|
|
522
|
+
}
|
|
523
|
+
clearCommentEditState();
|
|
524
|
+
refreshReviewCommentUi(jobId);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Start editing a pending line comment on a specific surface.
|
|
529
|
+
* @param {string} commentId
|
|
530
|
+
* @param {'inline' | 'pending'} surface
|
|
531
|
+
* @param {string} jobId
|
|
532
|
+
*/
|
|
533
|
+
function startCommentEdit(commentId, surface, jobId) {
|
|
534
|
+
const draft = loadReviewDraft(jobId);
|
|
535
|
+
const target = draft.lineComments.find((x) => x.id === commentId);
|
|
536
|
+
editingCommentId = commentId;
|
|
537
|
+
editingCommentSurface = surface;
|
|
538
|
+
editingCommentOriginalBody = target ? target.body : '';
|
|
539
|
+
activeInlineCommentKey = null;
|
|
540
|
+
refreshReviewCommentUi(jobId);
|
|
541
|
+
}
|
|
542
|
+
|
|
457
543
|
/**
|
|
458
544
|
* Re-render diff + pending list after draft mutation.
|
|
459
545
|
* @param {string} jobId
|
|
@@ -480,6 +566,7 @@ function refreshReviewCommentUi(jobId) {
|
|
|
480
566
|
* saveLabel?: string,
|
|
481
567
|
* onSave: (body: string) => void,
|
|
482
568
|
* onCancel: () => void,
|
|
569
|
+
* onInput?: (body: string) => void,
|
|
483
570
|
* }} opts
|
|
484
571
|
*/
|
|
485
572
|
function buildCommentEditForm(opts) {
|
|
@@ -490,6 +577,9 @@ function buildCommentEditForm(opts) {
|
|
|
490
577
|
ta.rows = 3;
|
|
491
578
|
ta.value = opts.initialBody;
|
|
492
579
|
ta.placeholder = 'Edit comment…';
|
|
580
|
+
if (opts.onInput) {
|
|
581
|
+
ta.addEventListener('input', () => opts.onInput(ta.value));
|
|
582
|
+
}
|
|
493
583
|
const actions = document.createElement('div');
|
|
494
584
|
actions.className = 'diff-inline-actions';
|
|
495
585
|
const save = document.createElement('button');
|
|
@@ -514,6 +604,7 @@ function buildCommentEditForm(opts) {
|
|
|
514
604
|
ta.focus();
|
|
515
605
|
const len = ta.value.length;
|
|
516
606
|
ta.setSelectionRange(len, len);
|
|
607
|
+
ta.scrollIntoView({ block: 'nearest', inline: 'nearest' });
|
|
517
608
|
});
|
|
518
609
|
return form;
|
|
519
610
|
}
|
|
@@ -1317,7 +1408,7 @@ function renderDiff(diff, opts = {}) {
|
|
|
1317
1408
|
plus.addEventListener('click', (e) => {
|
|
1318
1409
|
e.stopPropagation();
|
|
1319
1410
|
activeInlineCommentKey = lineCommentKey(path, line, side);
|
|
1320
|
-
|
|
1411
|
+
clearCommentEditState();
|
|
1321
1412
|
renderDiff(diff, opts);
|
|
1322
1413
|
renderPendingCommentList(jobId);
|
|
1323
1414
|
syncSubmitReviewButton(jobId);
|
|
@@ -1327,7 +1418,7 @@ function renderDiff(diff, opts = {}) {
|
|
|
1327
1418
|
cell.addEventListener('click', (e) => {
|
|
1328
1419
|
if (e.target.closest('button, textarea, a')) return;
|
|
1329
1420
|
activeInlineCommentKey = lineCommentKey(path, line, side);
|
|
1330
|
-
|
|
1421
|
+
clearCommentEditState();
|
|
1331
1422
|
renderDiff(diff, opts);
|
|
1332
1423
|
renderPendingCommentList(jobId);
|
|
1333
1424
|
syncSubmitReviewButton(jobId);
|
|
@@ -1382,22 +1473,16 @@ function renderDiff(diff, opts = {}) {
|
|
|
1382
1473
|
thread.appendChild(meta);
|
|
1383
1474
|
|
|
1384
1475
|
for (const c of existing) {
|
|
1385
|
-
if (editingCommentId === c.id) {
|
|
1476
|
+
if (editingCommentId === c.id && editingCommentSurface === 'inline') {
|
|
1386
1477
|
thread.appendChild(
|
|
1387
1478
|
buildCommentEditForm({
|
|
1388
1479
|
initialBody: c.body,
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
if (target) target.body = body;
|
|
1393
|
-
saveReviewDraft(jobId);
|
|
1394
|
-
editingCommentId = null;
|
|
1395
|
-
refreshReviewCommentUi(jobId);
|
|
1396
|
-
},
|
|
1397
|
-
onCancel: () => {
|
|
1398
|
-
editingCommentId = null;
|
|
1399
|
-
refreshReviewCommentUi(jobId);
|
|
1480
|
+
onInput: (body) => {
|
|
1481
|
+
updateLineCommentBody(jobId, c.id, body);
|
|
1482
|
+
mirrorCommentEditToOtherSurface(jobId);
|
|
1400
1483
|
},
|
|
1484
|
+
onSave: (body) => finishCommentEdit(jobId, c.id, body),
|
|
1485
|
+
onCancel: () => finishCommentEdit(jobId, c.id, null),
|
|
1401
1486
|
})
|
|
1402
1487
|
);
|
|
1403
1488
|
continue;
|
|
@@ -1415,9 +1500,7 @@ function renderDiff(diff, opts = {}) {
|
|
|
1415
1500
|
edit.className = 'btn btn-muted-text btn-sm';
|
|
1416
1501
|
edit.textContent = 'Edit';
|
|
1417
1502
|
edit.addEventListener('click', () => {
|
|
1418
|
-
|
|
1419
|
-
activeInlineCommentKey = null;
|
|
1420
|
-
refreshReviewCommentUi(jobId);
|
|
1503
|
+
startCommentEdit(c.id, 'inline', jobId);
|
|
1421
1504
|
});
|
|
1422
1505
|
const remove = document.createElement('button');
|
|
1423
1506
|
remove.type = 'button';
|
|
@@ -1427,7 +1510,7 @@ function renderDiff(diff, opts = {}) {
|
|
|
1427
1510
|
const d = loadReviewDraft(jobId);
|
|
1428
1511
|
d.lineComments = d.lineComments.filter((x) => x.id !== c.id);
|
|
1429
1512
|
saveReviewDraft(jobId);
|
|
1430
|
-
if (editingCommentId === c.id)
|
|
1513
|
+
if (editingCommentId === c.id) clearCommentEditState();
|
|
1431
1514
|
refreshReviewCommentUi(jobId);
|
|
1432
1515
|
});
|
|
1433
1516
|
actions.appendChild(edit);
|
|
@@ -1684,22 +1767,16 @@ function renderPendingCommentList(jobId) {
|
|
|
1684
1767
|
loc.textContent = `${c.path}:${c.line} (${c.side})`;
|
|
1685
1768
|
main.appendChild(loc);
|
|
1686
1769
|
|
|
1687
|
-
if (editingCommentId === c.id) {
|
|
1770
|
+
if (editingCommentId === c.id && editingCommentSurface === 'pending') {
|
|
1688
1771
|
main.appendChild(
|
|
1689
1772
|
buildCommentEditForm({
|
|
1690
1773
|
initialBody: c.body,
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
if (target) target.body = body;
|
|
1695
|
-
saveReviewDraft(jobId);
|
|
1696
|
-
editingCommentId = null;
|
|
1697
|
-
refreshReviewCommentUi(jobId);
|
|
1698
|
-
},
|
|
1699
|
-
onCancel: () => {
|
|
1700
|
-
editingCommentId = null;
|
|
1701
|
-
refreshReviewCommentUi(jobId);
|
|
1774
|
+
onInput: (body) => {
|
|
1775
|
+
updateLineCommentBody(jobId, c.id, body);
|
|
1776
|
+
mirrorCommentEditToOtherSurface(jobId);
|
|
1702
1777
|
},
|
|
1778
|
+
onSave: (body) => finishCommentEdit(jobId, c.id, body),
|
|
1779
|
+
onCancel: () => finishCommentEdit(jobId, c.id, null),
|
|
1703
1780
|
})
|
|
1704
1781
|
);
|
|
1705
1782
|
item.appendChild(main);
|
|
@@ -1718,9 +1795,7 @@ function renderPendingCommentList(jobId) {
|
|
|
1718
1795
|
edit.className = 'btn btn-muted-text btn-sm';
|
|
1719
1796
|
edit.textContent = 'Edit';
|
|
1720
1797
|
edit.addEventListener('click', () => {
|
|
1721
|
-
|
|
1722
|
-
activeInlineCommentKey = null;
|
|
1723
|
-
refreshReviewCommentUi(jobId);
|
|
1798
|
+
startCommentEdit(c.id, 'pending', jobId);
|
|
1724
1799
|
});
|
|
1725
1800
|
const remove = document.createElement('button');
|
|
1726
1801
|
remove.type = 'button';
|
|
@@ -1730,7 +1805,7 @@ function renderPendingCommentList(jobId) {
|
|
|
1730
1805
|
const d = loadReviewDraft(jobId);
|
|
1731
1806
|
d.lineComments = d.lineComments.filter((x) => x.id !== c.id);
|
|
1732
1807
|
saveReviewDraft(jobId);
|
|
1733
|
-
if (editingCommentId === c.id)
|
|
1808
|
+
if (editingCommentId === c.id) clearCommentEditState();
|
|
1734
1809
|
refreshReviewCommentUi(jobId);
|
|
1735
1810
|
});
|
|
1736
1811
|
actions.appendChild(edit);
|
|
@@ -2321,7 +2396,7 @@ function renderReview(jobs) {
|
|
|
2321
2396
|
const focusInPending = Boolean(
|
|
2322
2397
|
els.reviewPendingList?.contains(document.activeElement)
|
|
2323
2398
|
);
|
|
2324
|
-
if (!(editingCommentId && focusInPending)) {
|
|
2399
|
+
if (!(editingCommentId && editingCommentSurface === 'pending' && focusInPending)) {
|
|
2325
2400
|
renderPendingCommentList(job.id);
|
|
2326
2401
|
}
|
|
2327
2402
|
syncSubmitReviewButton(job.id);
|
|
@@ -2353,7 +2428,9 @@ function renderReview(jobs) {
|
|
|
2353
2428
|
|
|
2354
2429
|
const focusInDiff = els.diffViewer?.contains(document.activeElement);
|
|
2355
2430
|
const preservingDiffCompose =
|
|
2356
|
-
(activeInlineCommentKey ||
|
|
2431
|
+
(Boolean(activeInlineCommentKey) ||
|
|
2432
|
+
(editingCommentId && editingCommentSurface === 'inline')) &&
|
|
2433
|
+
focusInDiff;
|
|
2357
2434
|
if (!preservingDiffCompose) {
|
|
2358
2435
|
renderDiff(displayDiff, { interactive: editable, jobId: job.id });
|
|
2359
2436
|
}
|