codex-overleaf-link 1.9.5 → 1.9.7
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/README.md +23 -23
- package/extension/bootstrap/background.js +4 -0
- package/extension/bootstrap/manifest.template.json +1 -1
- package/extension/bootstrap/popup.css +169 -19
- package/extension/bootstrap/popup.html +5 -5
- package/extension/bootstrap/update.css +366 -0
- package/extension/bootstrap/update.html +55 -0
- package/extension/bootstrap/update.js +334 -0
- package/extension/src/backgroundUpdateCoordinator.js +68 -7
- package/extension/src/popup.js +135 -7
- package/extension/src/shared/compatibility.js +1 -1
- package/package.json +1 -1
package/extension/src/popup.js
CHANGED
|
@@ -303,12 +303,32 @@
|
|
|
303
303
|
return section;
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
-
|
|
307
|
-
|
|
306
|
+
function openUpdateCenter(action = '') {
|
|
307
|
+
const url = new URL(chrome.runtime.getURL('bootstrap/update.html'));
|
|
308
|
+
if (action) url.searchParams.set('action', action);
|
|
309
|
+
const opened = window.open(
|
|
310
|
+
url.href,
|
|
311
|
+
'codex-overleaf-update-center',
|
|
312
|
+
'popup,width=420,height=540,resizable=yes,scrollbars=yes'
|
|
313
|
+
);
|
|
314
|
+
if (opened) {
|
|
315
|
+
opened.focus();
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
window.location.assign(url.href);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
async function sendConsentAction(action) {
|
|
322
|
+
if (action === 'install' || action === 'retry' || action === 'center') {
|
|
323
|
+
openUpdateCenter(action === 'center' ? '' : action);
|
|
324
|
+
action = 'get';
|
|
325
|
+
}
|
|
326
|
+
const type = {
|
|
308
327
|
get: 'codex-overleaf/consent-update-get-state',
|
|
309
328
|
check: 'codex-overleaf/consent-update-check',
|
|
310
329
|
install: 'codex-overleaf/consent-update-install',
|
|
311
330
|
later: 'codex-overleaf/consent-update-later',
|
|
331
|
+
dismiss: 'codex-overleaf/consent-update-dismiss',
|
|
312
332
|
retry: 'codex-overleaf/consent-update-check'
|
|
313
333
|
}[action];
|
|
314
334
|
const response = await chrome.runtime.sendMessage({ type });
|
|
@@ -339,8 +359,19 @@
|
|
|
339
359
|
const state = view?.state || { state: 'idle' };
|
|
340
360
|
const progress = view?.progress || { value: 0, determinate: true, phase: 'idle' };
|
|
341
361
|
const copy = getUpdateCopy(state, view);
|
|
362
|
+
const stateName = state.state || 'idle';
|
|
363
|
+
const focusMode = Boolean(
|
|
364
|
+
options.busyAction === 'install' ||
|
|
365
|
+
view.execution ||
|
|
366
|
+
['committed', 'rolled_back', 'failed'].includes(stateName)
|
|
367
|
+
);
|
|
368
|
+
section.classList.toggle('is-quiet', stateName === 'idle');
|
|
369
|
+
section.classList.toggle('is-offer', stateName === 'update_available');
|
|
370
|
+
section.classList.toggle('is-focus', focusMode);
|
|
371
|
+
section.classList.toggle('is-result', ['committed', 'rolled_back', 'failed'].includes(stateName));
|
|
372
|
+
document.body.classList.toggle('consent-update-focus', focusMode);
|
|
342
373
|
const card = document.createElement('div');
|
|
343
|
-
card.className = 'consent-update-card state-' +
|
|
374
|
+
card.className = 'consent-update-card state-' + stateName;
|
|
344
375
|
|
|
345
376
|
const head = document.createElement('div');
|
|
346
377
|
head.className = 'consent-update-head';
|
|
@@ -350,6 +381,14 @@
|
|
|
350
381
|
version.textContent = copy.version;
|
|
351
382
|
head.append(title, version);
|
|
352
383
|
|
|
384
|
+
const route = document.createElement('div');
|
|
385
|
+
route.className = 'consent-update-route';
|
|
386
|
+
const currentVersion = state.currentVersion ? 'v' + state.currentVersion : '';
|
|
387
|
+
const latestVersion = state.latestVersion ? 'v' + state.latestVersion : '';
|
|
388
|
+
route.textContent = currentVersion && latestVersion && currentVersion !== latestVersion
|
|
389
|
+
? currentVersion + ' → ' + latestVersion
|
|
390
|
+
: latestVersion || currentVersion;
|
|
391
|
+
|
|
353
392
|
const detail = document.createElement('p');
|
|
354
393
|
detail.className = 'consent-update-detail';
|
|
355
394
|
detail.textContent = copy.detail;
|
|
@@ -369,6 +408,9 @@
|
|
|
369
408
|
const phase = document.createElement('div');
|
|
370
409
|
phase.className = 'consent-update-phase';
|
|
371
410
|
phase.textContent = copy.phase;
|
|
411
|
+
const showPhaseText = Boolean(copy.phase && copy.phase !== copy.detail);
|
|
412
|
+
const steps = createUpdateSteps(stateName);
|
|
413
|
+
const footnote = createUpdateFootnote(stateName);
|
|
372
414
|
|
|
373
415
|
const actions = document.createElement('div');
|
|
374
416
|
actions.className = 'consent-update-actions';
|
|
@@ -387,10 +429,15 @@
|
|
|
387
429
|
live.setAttribute('aria-live', 'polite');
|
|
388
430
|
live.textContent = ['committed', 'rolled_back', 'failed'].includes(state.state) ? copy.phase : '';
|
|
389
431
|
|
|
390
|
-
card.append(head
|
|
432
|
+
card.append(head);
|
|
433
|
+
if ((focusMode || stateName === 'update_available') && route.textContent) card.append(route);
|
|
434
|
+
card.append(detail);
|
|
391
435
|
if (!['idle', 'update_available'].includes(state.state) || options.busyAction === 'check') {
|
|
392
|
-
card.append(progressEl
|
|
436
|
+
card.append(progressEl);
|
|
437
|
+
if (showPhaseText) card.append(phase);
|
|
393
438
|
}
|
|
439
|
+
if (steps) card.append(steps);
|
|
440
|
+
if (footnote) card.append(footnote);
|
|
394
441
|
card.append(actions, live);
|
|
395
442
|
if (state.state === 'failed' && (state.code || state.message)) {
|
|
396
443
|
const details = document.createElement('details');
|
|
@@ -407,6 +454,57 @@
|
|
|
407
454
|
}
|
|
408
455
|
}
|
|
409
456
|
|
|
457
|
+
function createUpdateSteps(state) {
|
|
458
|
+
const activeIndex = {
|
|
459
|
+
downloading: 0,
|
|
460
|
+
staged: 1,
|
|
461
|
+
waiting_for_idle: 1,
|
|
462
|
+
applying: 2,
|
|
463
|
+
awaiting_health: 2,
|
|
464
|
+
committed: 3,
|
|
465
|
+
rolled_back: 2
|
|
466
|
+
}[state];
|
|
467
|
+
if (!Number.isInteger(activeIndex)) return null;
|
|
468
|
+
const labels = [
|
|
469
|
+
utx('Download and verify', '下载并验证'),
|
|
470
|
+
utx('Wait for a safe point', '等待安全时机'),
|
|
471
|
+
utx('Restart and health check', '重启并健康检查')
|
|
472
|
+
];
|
|
473
|
+
const list = document.createElement('ol');
|
|
474
|
+
list.className = 'consent-update-steps';
|
|
475
|
+
labels.forEach((label, index) => {
|
|
476
|
+
const item = document.createElement('li');
|
|
477
|
+
const status = state === 'committed'
|
|
478
|
+
? 'done'
|
|
479
|
+
: state === 'rolled_back' && index === 2
|
|
480
|
+
? 'error'
|
|
481
|
+
: index < activeIndex
|
|
482
|
+
? 'done'
|
|
483
|
+
: index === activeIndex
|
|
484
|
+
? 'active'
|
|
485
|
+
: 'pending';
|
|
486
|
+
item.className = 'is-' + status;
|
|
487
|
+
const marker = document.createElement('span');
|
|
488
|
+
marker.className = 'consent-update-step-marker';
|
|
489
|
+
marker.textContent = String(index + 1);
|
|
490
|
+
const text = document.createElement('span');
|
|
491
|
+
text.textContent = label;
|
|
492
|
+
item.append(marker, text);
|
|
493
|
+
list.append(item);
|
|
494
|
+
});
|
|
495
|
+
return list;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function createUpdateFootnote(state) {
|
|
499
|
+
if (!['downloading', 'staged', 'waiting_for_idle', 'applying', 'awaiting_health'].includes(state)) return null;
|
|
500
|
+
const note = document.createElement('p');
|
|
501
|
+
note.className = 'consent-update-footnote';
|
|
502
|
+
note.textContent = ['applying', 'awaiting_health'].includes(state)
|
|
503
|
+
? utx('This popup may close briefly while the extension restarts.', '扩展重启时此窗口可能会短暂关闭。')
|
|
504
|
+
: utx('You can close this popup. The update continues in the background.', '可以关闭此窗口,更新会在后台继续。');
|
|
505
|
+
return note;
|
|
506
|
+
}
|
|
507
|
+
|
|
410
508
|
function getVisibleActions(view = {}, busyAction = '') {
|
|
411
509
|
const state = view.state?.state || 'idle';
|
|
412
510
|
if (busyAction) {
|
|
@@ -422,6 +520,9 @@
|
|
|
422
520
|
return [{ id: 'later', label: utx('Later', '稍后提醒'), primary: false }];
|
|
423
521
|
}
|
|
424
522
|
if (['downloading', 'applying', 'awaiting_health', 'checking'].includes(state)) return [];
|
|
523
|
+
if (state === 'committed') {
|
|
524
|
+
return [{ id: 'dismiss', label: utx('Done', '完成'), primary: true }];
|
|
525
|
+
}
|
|
425
526
|
if (['failed', 'rolled_back'].includes(state)) {
|
|
426
527
|
return [{ id: 'retry', label: utx('Retry', '重试'), primary: true }];
|
|
427
528
|
}
|
|
@@ -434,6 +535,7 @@
|
|
|
434
535
|
retry: utx('Checking...', '正在检查...'),
|
|
435
536
|
install: utx('Starting update...', '正在启动更新...'),
|
|
436
537
|
later: utx('Saving...', '正在保存...')
|
|
538
|
+
, dismiss: utx('Closing...', '正在关闭...')
|
|
437
539
|
}[action] || utx('Working...', '处理中...');
|
|
438
540
|
}
|
|
439
541
|
|
|
@@ -442,7 +544,7 @@
|
|
|
442
544
|
const latest = state.latestVersion ? 'v' + state.latestVersion : '';
|
|
443
545
|
const blocker = formatBlocker(state.blocker);
|
|
444
546
|
const map = {
|
|
445
|
-
idle: [utx('
|
|
547
|
+
idle: [utx('Updates', '更新'), utx('Up to date', '已是最新版'), utx('Signed stable channel.', '签名稳定版通道。')],
|
|
446
548
|
checking: [utx('Checking for updates', '正在检查更新'), '', utx('Checking the latest signed stable release', '正在检查最新签名稳定版本')],
|
|
447
549
|
update_available: [utx('Update available', '发现新版本'), latest, view.snoozed ? utx('Reminder paused. Update remains ready here.', '提醒已暂停,仍可随时从这里更新。') : utx('Signed stable update for the extension and Native Host.', '扩展与 Native Host 的签名稳定更新。')],
|
|
448
550
|
downloading: [utx('Downloading update', '正在下载更新'), latest, utx('Downloading and verifying the coordinated update', '正在下载并验证协调更新')],
|
|
@@ -450,7 +552,7 @@
|
|
|
450
552
|
waiting_for_idle: [utx('Waiting for a safe point', '正在等待安全时机'), latest, blocker],
|
|
451
553
|
applying: [utx('Installing update', '正在安装更新'), latest, utx('Installing extension and Native Host', '正在安装扩展与 Native Host')],
|
|
452
554
|
awaiting_health: [utx('Checking updated components', '正在检查更新后的组件'), latest, utx('Restarting and checking both components', '正在重启并检查两个组件')],
|
|
453
|
-
committed: [utx('Update complete', '更新完成'), latest || current, utx('Extension and Native Host
|
|
555
|
+
committed: [utx('Update complete', '更新完成'), latest || current, utx('Extension and Native Host are healthy.', '扩展与 Native Host 均运行正常。')],
|
|
454
556
|
rolled_back: [utx('Previous version restored', '已恢复上一版本'), current, utx('Health check failed, so the previous coordinated pair was restored.', '健康检查失败,已恢复上一组协调版本。')],
|
|
455
557
|
failed: [utx('Update could not continue', '更新无法继续'), latest, state.message || utx('Check the details and retry.', '请查看详情后重试。')]
|
|
456
558
|
};
|
|
@@ -482,6 +584,7 @@
|
|
|
482
584
|
const style = document.createElement('style');
|
|
483
585
|
style.id = 'codex-overleaf-consent-update-styles';
|
|
484
586
|
style.textContent = [
|
|
587
|
+
'html { overflow:hidden; background:#171918; }',
|
|
485
588
|
'body { width:344px; padding:16px; background:#171918; color:#eceeec; font-family:"Avenir Next","Segoe UI",sans-serif; }',
|
|
486
589
|
'h1 { font-size:16px; letter-spacing:-.01em; }',
|
|
487
590
|
'.version-status { color:#a8ada9; }',
|
|
@@ -504,6 +607,31 @@
|
|
|
504
607
|
'.consent-update-actions button:focus-visible { outline:2px solid #79b8f2; outline-offset:2px; }',
|
|
505
608
|
'.consent-update-live { position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); }',
|
|
506
609
|
'.consent-update-card details { margin-top:10px; color:#a9aea9; font-size:11px; } .consent-update-card details code { background:#202320; color:#c9ceca; }',
|
|
610
|
+
'body .consent-updates { margin-top:16px; padding:13px 0 0; border:0; border-top:1px solid #303733; border-radius:0; background:transparent; }',
|
|
611
|
+
'body .consent-update-card { border:0; padding:0; background:transparent; box-shadow:none; }',
|
|
612
|
+
'body .consent-updates.is-quiet .consent-update-card { display:grid; grid-template-columns:minmax(0,1fr) auto; align-items:center; gap:6px 12px; }',
|
|
613
|
+
'body .consent-updates.is-quiet .consent-update-detail { display:none; }',
|
|
614
|
+
'body .consent-updates.is-quiet .consent-update-actions { grid-column:2; grid-row:1; margin:0; }',
|
|
615
|
+
'body .consent-updates.is-quiet .consent-update-actions button { width:auto; min-width:0; padding:5px 9px; border-color:transparent; background:transparent; color:#aeb7b1; }',
|
|
616
|
+
'body .consent-updates.is-offer, body .consent-updates.is-focus { padding-top:0; border-top:0; }',
|
|
617
|
+
'body .consent-updates.is-offer .consent-update-card { padding:15px; border:1px solid #34433b; border-radius:12px; background:linear-gradient(145deg,#202622,#1b201d); box-shadow:0 12px 32px rgba(0,0,0,.16); }',
|
|
618
|
+
'body.consent-update-focus { width:340px; min-height:340px; padding:20px; }',
|
|
619
|
+
'body.consent-update-focus > .version-status, body.consent-update-focus > #open-panel, body.consent-update-focus > #status, body.consent-update-focus > .install { display:none !important; }',
|
|
620
|
+
'body.consent-update-focus > h1 { margin-bottom:18px; }',
|
|
621
|
+
'body.consent-update-focus .consent-updates { margin-top:0; padding:0; border:0; }',
|
|
622
|
+
'body.consent-update-focus .consent-update-card { min-height:274px; padding:18px; border:1px solid #35443d; border-radius:14px; background:radial-gradient(circle at 95% 0,rgba(79,158,232,.12),transparent 42%),linear-gradient(150deg,#202522,#1a1e1c); box-shadow:0 18px 42px rgba(0,0,0,.24); }',
|
|
623
|
+
'.consent-update-route { margin:9px 0 0; color:#d9e6dd; font:600 13px/1.2 ui-monospace,SFMono-Regular,Menlo,monospace; letter-spacing:-.02em; }',
|
|
624
|
+
'.consent-update-steps { display:grid; gap:10px; margin:16px 0 0; padding:0; list-style:none; }',
|
|
625
|
+
'.consent-update-steps li { display:grid; grid-template-columns:24px minmax(0,1fr); align-items:center; gap:9px; color:#8f9892; font-size:12px; }',
|
|
626
|
+
'.consent-update-step-marker { display:inline-flex; width:22px; height:22px; align-items:center; justify-content:center; border:1px solid #3a413d; border-radius:999px; color:#89918c; font:700 10px/1 ui-monospace,monospace; }',
|
|
627
|
+
'.consent-update-steps li.is-done { color:#aeb9b2; }',
|
|
628
|
+
'.consent-update-steps li.is-done .consent-update-step-marker { border-color:#42694f; color:#8bd79e; background:#21392a; }',
|
|
629
|
+
'.consent-update-steps li.is-active { color:#edf2ef; }',
|
|
630
|
+
'.consent-update-steps li.is-active .consent-update-step-marker { border-color:#68a8e2; color:#eef7ff; background:#2d669a; box-shadow:0 0 0 3px rgba(98,168,232,.12); }',
|
|
631
|
+
'.consent-update-steps li.is-error .consent-update-step-marker { border-color:#9d554f; color:#ffd9d5; background:#542b28; }',
|
|
632
|
+
'.consent-update-footnote { margin:15px 0 0; padding-top:12px; border-top:1px solid #303733; color:#929b95; font-size:11px; }',
|
|
633
|
+
'body .consent-updates.is-result .consent-update-progress { margin-top:18px; }',
|
|
634
|
+
'body .consent-updates.is-focus .consent-update-actions { margin-top:18px; }',
|
|
507
635
|
'@keyframes consent-progress { 0% { transform:translateX(-110%); } 100% { transform:translateX(240%); } }',
|
|
508
636
|
'@media (prefers-reduced-motion:reduce) { .consent-update-progress.is-indeterminate span { animation:none; width:65% !important; } }'
|
|
509
637
|
].join('\n');
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
const MIN_NATIVE_VERSION = '1.0.0';
|
|
13
13
|
const MIN_COMPATIBLE_NATIVE_VERSION = '1.0.0';
|
|
14
14
|
const MIN_COMPATIBLE_EXTENSION_VERSION = '1.0.0';
|
|
15
|
-
const BUILD_TARGET_VERSION = '1.9.
|
|
15
|
+
const BUILD_TARGET_VERSION = '1.9.7';
|
|
16
16
|
const DEFAULT_CHROME_EXTENSION_ID = 'illdpneeeopfffmiepaejglgmhpmdhdc';
|
|
17
17
|
const REQUIRED_CAPABILITIES = Object.freeze([
|
|
18
18
|
'bridgePing',
|