codex-overleaf-link 2.5.0 → 2.6.0
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 +155 -392
- package/README.zh-CN.md +154 -393
- package/extension/bootstrap/background.js +52 -9
- package/extension/bootstrap/manifest.template.json +1 -1
- package/extension/bootstrap/popup.html +1 -0
- package/extension/bootstrap/popupFallback.js +55 -0
- package/extension/bootstrap/updateStatus.js +1 -0
- package/extension/src/background.js +283 -55
- package/extension/src/backgroundBootstrapMigration.js +181 -0
- package/extension/src/backgroundSharedSessions.js +129 -16
- package/extension/src/backgroundUpdateCoordinator.js +242 -29
- package/extension/src/backgroundUpdateSafety.js +173 -0
- package/extension/src/content/activeTurnControl.js +171 -8
- package/extension/src/content/applyResultFormatters.js +46 -73
- package/extension/src/content/assetTransferBroker.js +72 -14
- package/extension/src/content/composerAttachments.js +104 -47
- package/extension/src/content/composerPanel.js +110 -12
- package/extension/src/content/contentRuntime.js +1555 -926
- package/extension/src/content/contextTray.js +8 -2
- package/extension/src/content/contextUsageView.js +267 -0
- package/extension/src/content/diagnosticsController.js +122 -96
- package/extension/src/content/diagnosticsExport.js +19 -5
- package/extension/src/content/diagnosticsPanel.js +48 -0
- package/extension/src/content/directoryCleanupRecovery.js +54 -0
- package/extension/src/content/generated/content.bundle.js +11077 -3412
- package/extension/src/content/generated/content.bundle.meta.json +14 -3
- package/extension/src/content/globalPreferencesController.js +1 -1
- package/extension/src/content/legacyGlobalRegistry.js +10 -0
- package/extension/src/content/localSkillsPanel.js +104 -14
- package/extension/src/content/markdownDomRenderer.js +5 -3
- package/extension/src/content/markdownText.js +47 -11
- package/extension/src/content/modelPicker.js +8 -4
- package/extension/src/content/nativeCompatibilityController.js +74 -30
- package/extension/src/content/otWarmMirror.js +5 -6
- package/extension/src/content/otWarmMirrorController.js +17 -20
- package/extension/src/content/pageBridgeClient.js +17 -4
- package/extension/src/content/panelMaintenance.js +46 -14
- package/extension/src/content/panelRenderer.js +57 -27
- package/extension/src/content/pendingInputView.js +1 -1
- package/extension/src/content/projectProviderSelection.js +13 -4
- package/extension/src/content/projectSessionCleanup.js +109 -62
- package/extension/src/content/projectSettingsCoordinator.js +67 -6
- package/extension/src/content/providerSettingsCoordinator.js +46 -8
- package/extension/src/content/providerSettingsDialog.js +73 -14
- package/extension/src/content/recentProjects.js +15 -8
- package/extension/src/content/runActivitySummary.js +160 -18
- package/extension/src/content/runCompletionMeta.js +532 -0
- package/extension/src/content/runController.js +39 -15
- package/extension/src/content/runFailureNotice.js +29 -13
- package/extension/src/content/runGuidanceController.js +72 -27
- package/extension/src/content/runGuidanceView.js +59 -10
- package/extension/src/content/runPresence.js +18 -8
- package/extension/src/content/runQueueScheduler.js +157 -47
- package/extension/src/content/runRecoveryActions.js +147 -0
- package/extension/src/content/runResultActions.js +28 -143
- package/extension/src/content/runReviewController.js +633 -0
- package/extension/src/content/runScrollLayout.js +21 -2
- package/extension/src/content/runTimelineView.js +367 -175
- package/extension/src/content/scopedPersistencePanelState.js +134 -20
- package/extension/src/content/selectionContextView.js +1 -1
- package/extension/src/content/sensitivePreflight.js +153 -0
- package/extension/src/content/sessionForkController.js +80 -17
- package/extension/src/content/sessionManager.js +50 -4
- package/extension/src/content/sessionMenuView.js +54 -18
- package/extension/src/content/sessionPersistence.js +25 -5
- package/extension/src/content/settingsPanel.js +22 -5
- package/extension/src/content/settingsWorkbench.js +132 -89
- package/extension/src/content/sharedSessionViewSync.js +49 -11
- package/extension/src/content/subagentActivityView.js +23 -7
- package/extension/src/content/updateIdle.js +4 -1
- package/extension/src/content/updateNotice.js +118 -12
- package/extension/src/content/updateSafetyReceiver.js +58 -0
- package/extension/src/content/writebackController.js +53 -4
- package/extension/src/content/writebackOrchestrator.js +116 -94
- package/extension/src/content/writingStyleSettings.js +35 -11
- package/extension/src/page/binaryAssetUploader.js +136 -14
- package/extension/src/page/compileBridge.js +193 -180
- package/extension/src/page/fileMover.js +256 -0
- package/extension/src/page/overleafCapabilities.js +4 -1
- package/extension/src/page/ownedDirectoryCleanup.js +94 -0
- package/extension/src/page/referenceProjects.js +1 -0
- package/extension/src/page/reviewContext.js +113 -0
- package/extension/src/page/saveState.js +6 -4
- package/extension/src/page/snapshotRouter.js +84 -39
- package/extension/src/page/textCoordinates.js +17 -1
- package/extension/src/page/textFileCreator.js +114 -26
- package/extension/src/page/trackedChangeCapture.js +12 -2
- package/extension/src/page/trackedChangeOwnership.js +19 -1
- package/extension/src/page/trackedChangeReplay.js +41 -21
- package/extension/src/page/trackedChangesLifecycle.js +217 -199
- package/extension/src/page/treeOperations.js +7 -10
- package/extension/src/page/updateSafetyProbe.js +41 -0
- package/extension/src/page/writebackReceiptJournal.js +2 -0
- package/extension/src/page/writebackRouter.js +103 -155
- package/extension/src/pageBridge.js +126 -69
- package/extension/src/popup.js +62 -10
- package/extension/src/shared/agentTranscript.js +373 -17
- package/extension/src/shared/auditRecords.js +4 -0
- package/extension/src/shared/compatibility.js +22 -6
- package/extension/src/shared/compileAdapter.js +129 -66
- package/extension/src/shared/composerAttachmentDraft.js +156 -0
- package/extension/src/shared/contextUsage.js +125 -0
- package/extension/src/shared/directoryCleanupProof.js +43 -0
- package/extension/src/shared/failureReasons.js +349 -4
- package/extension/src/shared/globalPreferences.js +30 -13
- package/extension/src/shared/governanceRules.js +4 -37
- package/extension/src/shared/i18n.js +590 -24
- package/extension/src/shared/lineReferences.js +38 -31
- package/extension/src/shared/managedUpdateProjection.js +2 -2
- package/extension/src/shared/nativeRequestIdentity.js +1 -0
- package/extension/src/shared/pageRpcContract.js +5 -4
- package/extension/src/shared/panelIcons.js +39 -0
- package/extension/src/shared/projectFiles.js +21 -44
- package/extension/src/shared/providerProfiles.js +5 -3
- package/extension/src/shared/reviewing.js +130 -1
- package/extension/src/shared/runActivityModel.js +70 -4
- package/extension/src/shared/runExecutionSnapshot.js +13 -0
- package/extension/src/shared/runInputQueue.js +48 -5
- package/extension/src/shared/selectionContext.js +12 -3
- package/extension/src/shared/sessionState.js +132 -28
- package/extension/src/shared/sessionTitle.js +14 -1
- package/extension/src/shared/settlementFacts.js +10 -2
- package/extension/src/shared/sharedSessionBridge.js +118 -27
- package/extension/src/shared/sharedSessionTransfer.js +140 -0
- package/extension/src/shared/staleGuard.js +166 -52
- package/extension/src/shared/storageDb.js +90 -26
- package/extension/src/shared/storageMigration.js +78 -112
- package/extension/src/shared/storageRunActions.js +267 -30
- package/extension/src/shared/subagentActivityModel.js +1 -1
- package/extension/src/shared/undoOperations.js +253 -32
- package/extension/src/shared/updateConsent.js +6 -4
- package/extension/src/shared/updateRuntimeIdentity.js +17 -3
- package/extension/src/shared/writebackIntent.js +16 -0
- package/extension/src/shared/writebackOperationEvidence.js +4 -15
- package/extension/src/shared/writebackSettlement.js +58 -40
- package/extension/styles/panel.css +1123 -493
- package/native-host/src/anthropicBridgeRequest.js +4 -2
- package/native-host/src/anthropicBridgeResponse.js +6 -2
- package/native-host/src/anthropicMessagesBridge.js +24 -16
- package/native-host/src/bootstrapMigration.js +296 -0
- package/native-host/src/bootstrapMigrationContract.js +101 -0
- package/native-host/src/bootstrapUpdate.js +269 -0
- package/native-host/src/bootstrapUpdateWatchdog.js +44 -0
- package/native-host/src/chatBridgeRequest.js +60 -6
- package/native-host/src/chatBridgeResponse.js +20 -1
- package/native-host/src/chatCompletionsBridge.js +48 -15
- package/native-host/src/codexConfigPaths.js +106 -0
- package/native-host/src/codexHome.js +66 -73
- package/native-host/src/codexHomeScope.js +124 -0
- package/native-host/src/codexInheritedAuth.js +90 -0
- package/native-host/src/codexLocalSkills.js +301 -0
- package/native-host/src/codexPromptAssembly.js +114 -127
- package/native-host/src/codexProviderTest.js +24 -26
- package/native-host/src/codexSessionRunner.js +234 -198
- package/native-host/src/codexSessionTiming.js +18 -8
- package/native-host/src/codexSkillIsolation.js +170 -0
- package/native-host/src/codexThreadFork.js +19 -3
- package/native-host/src/index.js +19 -7
- package/native-host/src/managedInstall.js +110 -35
- package/native-host/src/managedInstallRecovery.js +140 -0
- package/native-host/src/managedRuntimeEvidence.js +57 -0
- package/native-host/src/mirrorWorkspace.js +92 -22
- package/native-host/src/nativeDoctor.js +15 -0
- package/native-host/src/nativeHelperLifecycle.js +21 -0
- package/native-host/src/nativeHostRegistration.js +33 -0
- package/native-host/src/nativeRunLifecycle.js +71 -0
- package/native-host/src/processStopBarrier.js +42 -7
- package/native-host/src/projectPathPlatform.js +30 -0
- package/native-host/src/providerContextError.js +20 -0
- package/native-host/src/providerHttp.js +80 -0
- package/native-host/src/providerProfile.js +4 -2
- package/native-host/src/providerReasoning.js +2 -7
- package/native-host/src/providerRuntime.js +1 -0
- package/native-host/src/providerStore.js +72 -14
- package/native-host/src/responsesPassthroughBridge.js +266 -52
- package/native-host/src/runtimeInstaller.js +21 -1
- package/native-host/src/selectionScope.js +36 -8
- package/native-host/src/subagentAdmission.js +26 -0
- package/native-host/src/subagentBroker.js +79 -66
- package/native-host/src/subagentTelemetry.js +19 -10
- package/native-host/src/subagentWorkspacePath.js +5 -2
- package/native-host/src/taskRunnerRuntime.js +92 -57
- package/native-host/src/textPatch.js +473 -377
- package/native-host/src/tomlStatements.js +140 -0
- package/native-host/src/updateManager.js +409 -46
- package/native-host/src/writingStyleRuntime.js +57 -29
- package/native-host/src/writingStyleStore.js +73 -0
- package/package.json +5 -8
- package/scripts/install-managed.mjs +1 -0
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
(function initCodexOverleafDiagnosticsController() {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// below moved verbatim (original indentation kept); runtime collaborators are
|
|
7
|
-
// factory-injected so behavior is unchanged. Mutable runtime state (panel
|
|
8
|
-
// state, OT status) is read through injected getters.
|
|
4
|
+
// Check runners own observations; result formatters project those observations
|
|
5
|
+
// into the current UI language. Runtime collaborators are factory-injected.
|
|
9
6
|
function create(deps = {}) {
|
|
10
7
|
const {
|
|
11
8
|
Compatibility: CodexOverleafCompatibility,
|
|
@@ -23,12 +20,12 @@
|
|
|
23
20
|
otWarmMirrorController,
|
|
24
21
|
getActiveFocusFiles,
|
|
25
22
|
getCurrentProjectId,
|
|
23
|
+
getScope,
|
|
26
24
|
isExperimentalOtEnabled,
|
|
27
25
|
readOtBridgeStatus,
|
|
28
26
|
formatOtStatusLabel,
|
|
29
27
|
normalizeOtStatus,
|
|
30
28
|
formatProbeStatusBar,
|
|
31
|
-
getProbeRunReadiness,
|
|
32
29
|
getMirrorFreshness,
|
|
33
30
|
formatProjectSnapshotLog,
|
|
34
31
|
formatProjectSnapshotWarning,
|
|
@@ -38,6 +35,48 @@
|
|
|
38
35
|
RUN_SNAPSHOT_ZIP_TIMEOUT_MS
|
|
39
36
|
} = deps;
|
|
40
37
|
|
|
38
|
+
// All visible checks share one request owner. Aggregate collectOnly calls
|
|
39
|
+
// must not supersede their own parent, and a later single check supersedes
|
|
40
|
+
// an older aggregate just as a later aggregate does.
|
|
41
|
+
let requestGeneration = 0;
|
|
42
|
+
let currentProjection = null;
|
|
43
|
+
const resultProjections = new WeakMap();
|
|
44
|
+
// Preserve the observed status and raw technical evidence across UI refreshes.
|
|
45
|
+
function projectableResult(project) {
|
|
46
|
+
const result = project();
|
|
47
|
+
resultProjections.set(result, () => ({ ...project(), status: result.status, technical: result.technical }));
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
function refreshLocale() {
|
|
51
|
+
return currentProjection && isCurrentDiagnosticsRequest(currentProjection.request)
|
|
52
|
+
? currentProjection.project() : null;
|
|
53
|
+
}
|
|
54
|
+
function captureDiagnosticsScope() {
|
|
55
|
+
const scope = getScope?.() || { projectId: getCurrentProjectId?.() };
|
|
56
|
+
return { accountScopeId: scope.accountScopeId, projectId: scope.projectId, generation: scope.generation };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function beginDiagnostics(title, subtitle) {
|
|
60
|
+
const request = { generation: ++requestGeneration, scope: captureDiagnosticsScope() };
|
|
61
|
+
currentProjection = { request, project: () => ({ title: tr(title), subtitle: tr(subtitle),
|
|
62
|
+
status: 'running', summary: tr('diagnosticsLoadingSummary') }) };
|
|
63
|
+
showDiagnosticsLoading(tr(title), tr(subtitle));
|
|
64
|
+
return request;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function isCurrentDiagnosticsRequest(request) {
|
|
68
|
+
if (!request || request.generation !== requestGeneration) return false;
|
|
69
|
+
const scope = captureDiagnosticsScope();
|
|
70
|
+
return ['accountScopeId', 'projectId', 'generation'].every(key => scope[key] === request.scope[key]);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function showCurrentDiagnosticsResult(request, result) {
|
|
74
|
+
if (isCurrentDiagnosticsRequest(request)) {
|
|
75
|
+
currentProjection = { request, project: resultProjections.get(result) || (() => result) };
|
|
76
|
+
showDiagnosticsResult(result);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
41
80
|
// Reduce a result status to a health bucket. 'completed' is a pass; a hard
|
|
42
81
|
// failure is fail; everything else (warning, partial, info) is attention.
|
|
43
82
|
function diagnosticsHealthBucket(status) {
|
|
@@ -50,12 +89,12 @@
|
|
|
50
89
|
// report (a status row per check) instead of four separate result screens.
|
|
51
90
|
// The overall bucket also updates the trigger dot.
|
|
52
91
|
async function runAllDiagnostics() {
|
|
53
|
-
|
|
92
|
+
const request = beginDiagnostics('diagnosticsHealthTitle', 'diagnosticsRunningAll');
|
|
54
93
|
const specs = [
|
|
55
|
-
{ label:
|
|
56
|
-
{ label:
|
|
57
|
-
{ label:
|
|
58
|
-
{ label:
|
|
94
|
+
{ label: 'diagnosticsNativeShort', run: inspectNativeEnvironment },
|
|
95
|
+
{ label: 'diagnosticsPageShort', run: inspectPageStateDiagnostics },
|
|
96
|
+
{ label: 'diagnosticsSnapshotShort', run: inspectProjectSnapshot },
|
|
97
|
+
{ label: 'diagnosticsOtShort', run: inspectOtWarmMirrorDiagnostics }
|
|
59
98
|
];
|
|
60
99
|
const checks = [];
|
|
61
100
|
let worst = 'ok';
|
|
@@ -64,7 +103,7 @@
|
|
|
64
103
|
try {
|
|
65
104
|
result = await spec.run({ collectOnly: true });
|
|
66
105
|
} catch (error) {
|
|
67
|
-
result = { status: 'failed', summary: tr('diagnosticsCheckErrored'), technical: error?.message || String(error) };
|
|
106
|
+
result = projectableResult(() => ({ status: 'failed', summary: tr('diagnosticsCheckErrored'), technical: error?.message || String(error) }));
|
|
68
107
|
}
|
|
69
108
|
const bucket = diagnosticsHealthBucket(result?.status);
|
|
70
109
|
if (bucket === 'fail') {
|
|
@@ -72,34 +111,32 @@
|
|
|
72
111
|
} else if (bucket === 'warn' && worst !== 'fail') {
|
|
73
112
|
worst = 'warn';
|
|
74
113
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
114
|
+
const project = resultProjections.get(result) || (() => result);
|
|
115
|
+
checks.push(() => {
|
|
116
|
+
const translated = project();
|
|
117
|
+
return {
|
|
118
|
+
status: result?.status || 'info',
|
|
119
|
+
title: tr(spec.label),
|
|
120
|
+
summary: translated?.summary || translated?.subtitle || '',
|
|
121
|
+
nextStep: bucket === 'ok' ? '' : (translated?.nextStep || '')
|
|
122
|
+
};
|
|
80
123
|
});
|
|
81
124
|
}
|
|
82
125
|
const overallSubtitleKey = worst === 'ok'
|
|
83
126
|
? 'diagnosticsHealthOk'
|
|
84
127
|
: worst === 'fail' ? 'diagnosticsHealthFail' : 'diagnosticsHealthWarn';
|
|
85
|
-
|
|
128
|
+
showCurrentDiagnosticsResult(request, projectableResult(() => ({
|
|
86
129
|
title: tr('diagnosticsHealthTitle'),
|
|
87
130
|
subtitle: tr(overallSubtitleKey),
|
|
88
131
|
status: worst === 'ok' ? 'completed' : worst === 'fail' ? 'failed' : 'warning',
|
|
89
|
-
checks
|
|
90
|
-
});
|
|
91
|
-
setDiagnosticsHealth(worst);
|
|
132
|
+
checks: checks.map(project => project())
|
|
133
|
+
})));
|
|
134
|
+
if (isCurrentDiagnosticsRequest(request)) setDiagnosticsHealth(worst);
|
|
92
135
|
}
|
|
93
136
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
137
|
async function inspectProjectSnapshot(options = {}) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
138
|
+
const request = options.collectOnly ? null
|
|
139
|
+
: beginDiagnostics('diagnosticsSnapshotTitle', 'diagnosticsSnapshotLoading');
|
|
103
140
|
let result;
|
|
104
141
|
try {
|
|
105
142
|
const project = await callPageBridge('getProjectSnapshot', {
|
|
@@ -111,36 +148,35 @@
|
|
|
111
148
|
zipOnly: true,
|
|
112
149
|
zipTimeoutMs: RUN_SNAPSHOT_ZIP_TIMEOUT_MS
|
|
113
150
|
});
|
|
114
|
-
result = formatProjectSnapshotDiagnosticsResult(project);
|
|
151
|
+
result = projectableResult(() => formatProjectSnapshotDiagnosticsResult(project));
|
|
115
152
|
} catch (error) {
|
|
116
|
-
result = {
|
|
153
|
+
result = projectableResult(() => ({
|
|
117
154
|
title: tx('Project Read Failed', '项目读取失败'),
|
|
118
155
|
subtitle: tx('The extension did not receive Overleaf project content.', '插件没有拿到 Overleaf 项目内容。'),
|
|
119
156
|
status: 'failed',
|
|
120
157
|
summary: tr('diagnosticsSnapshotErrorSummary'),
|
|
121
158
|
nextStep: tx('Reload Overleaf, wait for the left file tree to finish loading, then retry.', '刷新 Overleaf 页面,等左侧文件树加载完成后重试。'),
|
|
122
159
|
technical: error?.stack || error?.message || String(error)
|
|
123
|
-
};
|
|
160
|
+
}));
|
|
124
161
|
}
|
|
125
162
|
if (options.collectOnly) {
|
|
126
163
|
return result;
|
|
127
164
|
}
|
|
128
|
-
|
|
165
|
+
showCurrentDiagnosticsResult(request, result);
|
|
129
166
|
}
|
|
130
167
|
|
|
131
168
|
async function inspectNativeEnvironment(options = {}) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
169
|
+
const request = options.collectOnly ? null
|
|
170
|
+
: beginDiagnostics('diagnosticsNativeTitle', 'diagnosticsNativeLoading');
|
|
135
171
|
const params = CodexOverleafCompatibility?.buildBridgePingParams
|
|
136
172
|
? CodexOverleafCompatibility.buildBridgePingParams(getExtensionCompatibilityMetadata())
|
|
137
173
|
: {};
|
|
138
174
|
const response = await sendBackgroundNative({ method: 'bridge.ping', params });
|
|
139
|
-
const result = formatNativeEnvironmentResult(response);
|
|
175
|
+
const result = projectableResult(() => formatNativeEnvironmentResult(response));
|
|
140
176
|
if (options.collectOnly) {
|
|
141
177
|
return result;
|
|
142
178
|
}
|
|
143
|
-
|
|
179
|
+
showCurrentDiagnosticsResult(request, result);
|
|
144
180
|
}
|
|
145
181
|
|
|
146
182
|
function formatNativeEnvironmentResult(response) {
|
|
@@ -150,7 +186,6 @@
|
|
|
150
186
|
if (compatibility.status !== 'ok' && compatibility.status !== 'native_unhealthy') {
|
|
151
187
|
return formatNativeCompatibilityResult(compatibility, response);
|
|
152
188
|
}
|
|
153
|
-
|
|
154
189
|
if (!response?.ok) {
|
|
155
190
|
return {
|
|
156
191
|
title: tx('Local Connection Problem', '本机连接异常'),
|
|
@@ -158,11 +193,10 @@
|
|
|
158
193
|
status: 'failed',
|
|
159
194
|
summary: tx('The extension is not connected to the local service, so it cannot run local Codex or sync the local workspace yet.', '插件没有连上本机服务,所以暂时不能调用本地 Codex 或同步本地 workspace。'),
|
|
160
195
|
nextStep: tx('Make sure the native host is installed, reload the Chrome extension, then try again.', '确认 native host 已安装,并重新加载 Chrome 扩展后再试。'),
|
|
161
|
-
installCommand: INSTALL_COMMAND,
|
|
196
|
+
installCommand: compatibility.installCommand ?? INSTALL_COMMAND,
|
|
162
197
|
technical: response?.error?.message || tx('native host did not respond', 'native host 没有响应')
|
|
163
198
|
};
|
|
164
199
|
}
|
|
165
|
-
|
|
166
200
|
const environment = response.result?.environment;
|
|
167
201
|
if (!environment) {
|
|
168
202
|
return {
|
|
@@ -174,7 +208,6 @@
|
|
|
174
208
|
technical: JSON.stringify(response.result || {}, null, 2)
|
|
175
209
|
};
|
|
176
210
|
}
|
|
177
|
-
|
|
178
211
|
const codexOk = environment.codex?.ok === true;
|
|
179
212
|
const latexTools = environment.latex?.available || [];
|
|
180
213
|
const latexOk = latexTools.length > 0;
|
|
@@ -186,7 +219,6 @@
|
|
|
186
219
|
? tx(`LaTeX tools available: ${latexTools.join(', ')}`, `LaTeX 工具可用:${latexTools.join(', ')}`)
|
|
187
220
|
: tx('LaTeX tools were not found: text editing works, but local compile checks are limited.', 'LaTeX 工具没有找到:可以编辑文本,但不能在本地编译验证。')
|
|
188
221
|
];
|
|
189
|
-
|
|
190
222
|
if (codexOk && latexOk) {
|
|
191
223
|
return {
|
|
192
224
|
title: tx('Local Connection OK', '本机连接正常'),
|
|
@@ -197,7 +229,6 @@
|
|
|
197
229
|
technical: JSON.stringify(environment, null, 2)
|
|
198
230
|
};
|
|
199
231
|
}
|
|
200
|
-
|
|
201
232
|
return {
|
|
202
233
|
title: codexOk ? tx('Local Connection Partially Available', '本机连接部分可用') : tx('Codex Unavailable', 'Codex 不可用'),
|
|
203
234
|
subtitle: codexOk ? tx('Codex is available, but compile tools are incomplete.', 'Codex 可用,但编译工具不完整。') : tx('Local Codex was not found.', '没有找到本机 Codex。'),
|
|
@@ -212,7 +243,6 @@
|
|
|
212
243
|
technical: JSON.stringify(environment, null, 2)
|
|
213
244
|
};
|
|
214
245
|
}
|
|
215
|
-
|
|
216
246
|
function fallbackNativeCompatibility(response) {
|
|
217
247
|
return response?.ok
|
|
218
248
|
? { status: 'ok', classification: 'compatible', native: response.result, installCommand: INSTALL_COMMAND }
|
|
@@ -238,12 +268,13 @@
|
|
|
238
268
|
subtitle: tx('The extension could not connect to the local service.', '插件没有连上本机服务。'),
|
|
239
269
|
status: 'failed',
|
|
240
270
|
summary: tx('The extension is not connected to the local service, so it cannot run local Codex or sync the local workspace yet.', '插件没有连上本机服务,所以暂时不能调用本地 Codex 或同步本地 workspace。'),
|
|
241
|
-
nextStep:
|
|
242
|
-
|
|
271
|
+
nextStep: compatibility.installIdentity?.managed && !compatibility.installCommand
|
|
272
|
+
? tx('Repair Managed using the original managed root, browser and extension ID with install-managed.', '请使用原管理根目录、浏览器及扩展 ID,通过 install-managed 修复托管安装。')
|
|
273
|
+
: tx('Make sure the native host is installed, reload the Chrome extension, then try again.', '确认 native host 已安装,并重新加载 Chrome 扩展后再试。'),
|
|
274
|
+
installCommand: compatibility.installCommand ?? INSTALL_COMMAND,
|
|
243
275
|
technical: response?.error?.message || tx('native host did not respond', 'native host 没有响应')
|
|
244
276
|
};
|
|
245
277
|
}
|
|
246
|
-
|
|
247
278
|
const messages = getNativeCompatibilityMessages(statusValue);
|
|
248
279
|
return {
|
|
249
280
|
title: messages.title,
|
|
@@ -256,7 +287,6 @@
|
|
|
256
287
|
technical: formatNativeCompatibilityTechnicalDetails(compatibility, response)
|
|
257
288
|
};
|
|
258
289
|
}
|
|
259
|
-
|
|
260
290
|
function getNativeCompatibilityMessages(statusValue) {
|
|
261
291
|
switch (statusValue) {
|
|
262
292
|
case 'native_too_old':
|
|
@@ -329,62 +359,59 @@
|
|
|
329
359
|
}
|
|
330
360
|
|
|
331
361
|
async function inspectPageStateDiagnostics(options = {}) {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
}
|
|
362
|
+
const request = options.collectOnly ? null
|
|
363
|
+
: beginDiagnostics('diagnosticsPageTitle', 'diagnosticsPageLoading');
|
|
335
364
|
let result;
|
|
336
365
|
try {
|
|
337
366
|
const probe = await callPageBridge('probe', {
|
|
338
367
|
manualOverride: getState()?.requireReviewing === false
|
|
339
368
|
});
|
|
340
|
-
|
|
369
|
+
const mode = getState()?.mode;
|
|
370
|
+
result = projectableResult(() => formatPageStateDiagnosticsResult(probe, mode));
|
|
341
371
|
} catch (error) {
|
|
342
|
-
result = {
|
|
372
|
+
result = projectableResult(() => ({
|
|
343
373
|
title: tx('Overleaf Page Check Failed', 'Overleaf 页面检查失败'),
|
|
344
374
|
subtitle: tx('The extension did not read the current page state.', '插件没有读到当前页面状态。'),
|
|
345
375
|
status: 'failed',
|
|
346
376
|
summary: tx('This usually means Overleaf is still loading, or the page script is temporarily unavailable.', '这通常表示 Overleaf 页面还在加载,或者页面脚本暂时不可用。'),
|
|
347
377
|
nextStep: tx('Reload Overleaf, open the .tex file you want to work on, then try again.', '刷新 Overleaf 页面,点开要处理的 .tex 文件后再试。'),
|
|
348
378
|
technical: error?.stack || error?.message || String(error)
|
|
349
|
-
};
|
|
379
|
+
}));
|
|
350
380
|
}
|
|
351
381
|
if (options.collectOnly) {
|
|
352
382
|
return result;
|
|
353
383
|
}
|
|
354
|
-
|
|
384
|
+
showCurrentDiagnosticsResult(request, result);
|
|
355
385
|
}
|
|
356
386
|
|
|
357
387
|
async function inspectOtWarmMirrorDiagnostics(options = {}) {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
}
|
|
388
|
+
const request = options.collectOnly ? null
|
|
389
|
+
: beginDiagnostics('diagnosticsOtTitle', 'diagnosticsLoading');
|
|
361
390
|
// OT warm mirror is opt-in and off by default. When it is disabled
|
|
362
391
|
// there is nothing live to probe, so report a clean, healthy "disabled"
|
|
363
392
|
// state instead of querying (then warning about) absent OT metadata — or
|
|
364
393
|
// degrading to the generic "could not run" error if a probe throws. A
|
|
365
394
|
// turned-off feature must never read as a failure.
|
|
366
395
|
if (!isExperimentalOtEnabled()) {
|
|
367
|
-
const disabledResult = {
|
|
368
|
-
title: tr('diagnosticsOtTitle'),
|
|
369
|
-
subtitle: tr('diagnosticsOtSubtitle'),
|
|
370
|
-
status: 'completed',
|
|
371
|
-
summary: tr('diagnosticsOtSummaryDisabled'),
|
|
372
|
-
bullets: [],
|
|
373
|
-
nextStep: '',
|
|
374
|
-
technical: ''
|
|
375
|
-
};
|
|
376
396
|
const mirrorState = getOtWarmMirrorState?.() || {};
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
397
|
+
const failure = mirrorState.failureActive && mirrorState.lastFailure ? { ...mirrorState.lastFailure } : null;
|
|
398
|
+
const disabledResult = projectableResult(() => {
|
|
399
|
+
const result = {
|
|
400
|
+
title: tr('diagnosticsOtTitle'), subtitle: tr('diagnosticsOtSubtitle'), status: 'completed',
|
|
401
|
+
summary: tr('diagnosticsOtSummaryDisabled'), bullets: [], nextStep: '', technical: ''
|
|
402
|
+
};
|
|
403
|
+
if (failure) {
|
|
404
|
+
result.status = 'warning';
|
|
405
|
+
result.summary = tr(otWarmMirrorController.getFailureMessageKey(failure.code));
|
|
406
|
+
result.nextStep = tr('otFailureNextStep');
|
|
407
|
+
result.technical = `lastErrorCode: ${failure.code}\nphase: ${failure.phase}\nfailedAt: ${new Date(failure.at).toISOString()}`;
|
|
408
|
+
}
|
|
409
|
+
return result;
|
|
410
|
+
});
|
|
384
411
|
if (options.collectOnly) {
|
|
385
412
|
return disabledResult;
|
|
386
413
|
}
|
|
387
|
-
|
|
414
|
+
showCurrentDiagnosticsResult(request, disabledResult);
|
|
388
415
|
return;
|
|
389
416
|
}
|
|
390
417
|
const projectId = getCurrentProjectId();
|
|
@@ -421,26 +448,30 @@
|
|
|
421
448
|
mirrorStatus = { lastOtErrorCode: 'mirror_status_failed' };
|
|
422
449
|
}
|
|
423
450
|
|
|
424
|
-
const
|
|
425
|
-
|
|
426
|
-
|
|
451
|
+
const context = { enabled: isExperimentalOtEnabled(), status: getCurrentOtStatus(),
|
|
452
|
+
warmMirrorState: { ...(getOtWarmMirrorState() || {}) }, focusFiles: getActiveFocusFiles() };
|
|
453
|
+
context.warmStart = otWarmMirrorController?.canUseOtWarmStart?.({ enabled: context.enabled, focusFiles: context.focusFiles, mirrorStatus }) || { ok: false };
|
|
454
|
+
const result = projectableResult(() => {
|
|
455
|
+
const baseResult = formatOtDiagnosticsResult({ otStatus, mirrorStatus, context });
|
|
456
|
+
return metadataWarning ? {
|
|
427
457
|
...baseResult,
|
|
428
458
|
status: 'warning',
|
|
429
459
|
summary: `${baseResult.summary} ${tx('Some OT diagnostic metadata is unavailable.', '部分 OT 诊断元数据暂时不可用。')}`
|
|
430
460
|
}
|
|
431
|
-
|
|
461
|
+
: baseResult;
|
|
462
|
+
});
|
|
432
463
|
if (options.collectOnly) {
|
|
433
464
|
return result;
|
|
434
465
|
}
|
|
435
|
-
|
|
466
|
+
showCurrentDiagnosticsResult(request, result);
|
|
436
467
|
}
|
|
437
468
|
|
|
438
|
-
function formatOtDiagnosticsResult({ otStatus, mirrorStatus }) {
|
|
439
|
-
const enabled = isExperimentalOtEnabled();
|
|
440
|
-
const statusValue = normalizeOtStatus(otStatus ? readOtBridgeStatus(otStatus) : getCurrentOtStatus());
|
|
469
|
+
function formatOtDiagnosticsResult({ otStatus, mirrorStatus, context = {} }) {
|
|
470
|
+
const enabled = context.enabled ?? isExperimentalOtEnabled();
|
|
471
|
+
const statusValue = normalizeOtStatus(otStatus ? readOtBridgeStatus(otStatus) : context.status ?? getCurrentOtStatus());
|
|
441
472
|
const queuedEventCount = normalizeOtDiagnosticsCount(otStatus?.queuedEventCount);
|
|
442
473
|
const lastEventAt = formatOtDiagnosticValue(otStatus?.lastEventAt, tr('noneValue'));
|
|
443
|
-
const warmMirrorState = getOtWarmMirrorState() || {};
|
|
474
|
+
const warmMirrorState = context.warmMirrorState || getOtWarmMirrorState() || {};
|
|
444
475
|
const failureActive = warmMirrorState.failureActive === true;
|
|
445
476
|
const lastOtPatchAt = formatOtDiagnosticValue(mirrorStatus?.lastOtPatchAt || warmMirrorState.lastPatchAt, tr('noneValue'));
|
|
446
477
|
const lastOtErrorCode = formatOtDiagnosticValue(mirrorStatus?.lastOtErrorCode || warmMirrorState.lastErrorCode, tr('noneValue'));
|
|
@@ -451,10 +482,9 @@
|
|
|
451
482
|
Array.isArray(mirrorStatus?.otFreshFiles) ? mirrorStatus.otFreshFiles.length : 0
|
|
452
483
|
);
|
|
453
484
|
const bridgeFailed = otStatus?.ok === false;
|
|
454
|
-
const focusFiles = getActiveFocusFiles();
|
|
455
|
-
const otWarmStart = otWarmMirrorController?.canUseOtWarmStart?.({ enabled, focusFiles, mirrorStatus }) || { ok: false };
|
|
485
|
+
const focusFiles = context.focusFiles || getActiveFocusFiles();
|
|
486
|
+
const otWarmStart = context.warmStart || otWarmMirrorController?.canUseOtWarmStart?.({ enabled, focusFiles, mirrorStatus }) || { ok: false };
|
|
456
487
|
const fallback = !enabled || failureActive || statusValue !== 'observing' || bridgeFailed || otWarmStart?.ok !== true;
|
|
457
|
-
|
|
458
488
|
return {
|
|
459
489
|
title: tr('diagnosticsOtTitle'),
|
|
460
490
|
subtitle: tr('diagnosticsOtSubtitle'),
|
|
@@ -478,7 +508,6 @@
|
|
|
478
508
|
})
|
|
479
509
|
};
|
|
480
510
|
}
|
|
481
|
-
|
|
482
511
|
function formatOtDiagnosticsTechnicalDetails(metadata = {}) {
|
|
483
512
|
const lines = [
|
|
484
513
|
`strategy: ${metadata.strategy || 'unknown'}`,
|
|
@@ -530,8 +559,7 @@
|
|
|
530
559
|
return text.length > 160 ? `${text.slice(0, 157)}...` : text;
|
|
531
560
|
}
|
|
532
561
|
|
|
533
|
-
function formatPageStateDiagnosticsResult(probe) {
|
|
534
|
-
const readiness = getProbeRunReadiness(probe || {});
|
|
562
|
+
function formatPageStateDiagnosticsResult(probe, mode = getState()?.mode) {
|
|
535
563
|
const reviewingOk = probe?.reviewing?.ok === true;
|
|
536
564
|
const writable = probe?.capabilities?.editor?.write !== false;
|
|
537
565
|
const readable = probe?.editor?.ok === true;
|
|
@@ -545,10 +573,10 @@
|
|
|
545
573
|
return {
|
|
546
574
|
title: tx('Overleaf Page Ready', 'Overleaf 页面可用'),
|
|
547
575
|
subtitle: formatProbeStatusBar(probe),
|
|
548
|
-
status: reviewingOk ||
|
|
576
|
+
status: reviewingOk || mode === 'ask' ? 'completed' : 'warning',
|
|
549
577
|
summary: tx('The current Overleaf file can be read and written. The extension still verifies before writing to avoid overwriting new user or collaborator edits.', '当前 Overleaf 文件可以读取和写入。写入前插件仍会再次验证,避免覆盖用户或协作者的新改动。'),
|
|
550
578
|
bullets,
|
|
551
|
-
nextStep: reviewingOk ||
|
|
579
|
+
nextStep: reviewingOk || mode === 'ask' ? '' : tx('If you need tracked writes, turn on Overleaf Reviewing/Track Changes first.', '如果需要留痕写入,请先在 Overleaf 开启 Reviewing/Track Changes。'),
|
|
552
580
|
technical: formatPageDiagnosticsTechnicalDetails(probe)
|
|
553
581
|
};
|
|
554
582
|
}
|
|
@@ -579,7 +607,6 @@
|
|
|
579
607
|
tx(`Asset files: ${binaryCount}`, `资源文件:${binaryCount} 个`),
|
|
580
608
|
project?.activePath ? tx(`Current file: ${project.activePath}`, `当前文件:${project.activePath}`) : tx('Current file: not detected', '当前文件:未识别')
|
|
581
609
|
];
|
|
582
|
-
|
|
583
610
|
if (fullProject && files.length) {
|
|
584
611
|
return {
|
|
585
612
|
title: tx('Project Read OK', '项目读取正常'),
|
|
@@ -593,7 +620,6 @@
|
|
|
593
620
|
technical: formatProjectSnapshotLog(project)
|
|
594
621
|
};
|
|
595
622
|
}
|
|
596
|
-
|
|
597
623
|
return {
|
|
598
624
|
title: files.length ? tx('Full Project Not Read', '没有读到完整项目') : tx('No Project Files Read', '没有读到项目文件'),
|
|
599
625
|
subtitle: tx(`Read source: ${source}`, `读取来源:${source}`),
|
|
@@ -609,7 +635,6 @@
|
|
|
609
635
|
technical: formatProjectSnapshotLog(project)
|
|
610
636
|
};
|
|
611
637
|
}
|
|
612
|
-
|
|
613
638
|
function formatPageDiagnosticsTechnicalDetails(probe) {
|
|
614
639
|
const lines = [];
|
|
615
640
|
lines.push(tx(`Status: ${formatProbeStatusBar(probe || {})}`, `状态:${formatProbeStatusBar(probe || {})}`));
|
|
@@ -656,6 +681,7 @@
|
|
|
656
681
|
|
|
657
682
|
|
|
658
683
|
return {
|
|
684
|
+
refreshLocale,
|
|
659
685
|
runAllDiagnostics,
|
|
660
686
|
inspectProjectSnapshot,
|
|
661
687
|
inspectNativeEnvironment,
|
|
@@ -136,16 +136,26 @@
|
|
|
136
136
|
throw new Error('Audit diagnostics helper is unavailable');
|
|
137
137
|
}
|
|
138
138
|
const projectId = getCurrentProjectId();
|
|
139
|
+
const accountScopeId = deps.getAccountScopeId?.() || '';
|
|
140
|
+
if (!accountScopeId) throw new Error('Account identity is unavailable; reopen the project before exporting diagnostics.');
|
|
139
141
|
const currentRunView = getCurrentRunView();
|
|
140
142
|
const activeRecord = currentRunView && findRunRecord(currentRunView.recordId, currentRunView.sessionId);
|
|
141
|
-
const
|
|
143
|
+
const panelState = getState();
|
|
144
|
+
const sessionScope = panelState.sessions?.find(session => session.id === panelState.activeSessionId)?.accountScopeId;
|
|
145
|
+
// Older normalized runs lack owner fields; they still rely on the view's
|
|
146
|
+
// hydration boundary. Explicit ownership, when present, must agree.
|
|
147
|
+
const matchesAccount = (record, ...owners) => [record?.runAccountScopeId, record?.accountScopeId, ...owners]
|
|
148
|
+
.filter(Boolean).every(owner => owner === accountScopeId);
|
|
149
|
+
const recentRuns = (panelState.runs || []).filter(run => run && (!run.runProjectId || run.runProjectId === projectId)
|
|
150
|
+
&& matchesAccount(run, sessionScope, panelState.accountScopeId))
|
|
142
151
|
.slice().reverse().sort((a, b) => (Date.parse(b.startedAt) || 0) - (Date.parse(a.startedAt) || 0)).slice(0, 8);
|
|
143
152
|
const [auditLogs, mirror, nativeDiagnostics] = await Promise.all([
|
|
144
|
-
getRecentAuditLogsForCurrentProject(),
|
|
153
|
+
getRecentAuditLogsForCurrentProject({ projectId, accountScopeId }),
|
|
145
154
|
getMirrorFreshness().catch(error => ({ status: 'unavailable', errorCode: error.message })),
|
|
146
155
|
getNativeDiagnosticsSummaryForBundle()
|
|
147
156
|
]);
|
|
148
157
|
if (getCurrentProjectId() !== projectId) throw new Error('Project changed during diagnostics export; export again.');
|
|
158
|
+
if (deps.getAccountScopeId?.() !== accountScopeId) throw new Error('Account changed during diagnostics export; export again.');
|
|
149
159
|
const bundle = AuditRecords.buildDiagnosticBundle({
|
|
150
160
|
excludeContent: true,
|
|
151
161
|
compatibility: {
|
|
@@ -156,7 +166,8 @@
|
|
|
156
166
|
nativeEnvironment: nativeDiagnostics.nativeEnvironment,
|
|
157
167
|
mirror,
|
|
158
168
|
auditLogs,
|
|
159
|
-
run: activeRecord?.runProjectId === projectId
|
|
169
|
+
run: activeRecord?.runProjectId === projectId && matchesAccount(activeRecord, currentRunView?.runAccountScopeId)
|
|
170
|
+
? activeRecord : recentRuns[0] || {},
|
|
160
171
|
recentRuns,
|
|
161
172
|
governance: getGovernanceRulesForCurrentProject(),
|
|
162
173
|
projectId
|
|
@@ -204,12 +215,15 @@
|
|
|
204
215
|
}
|
|
205
216
|
}
|
|
206
217
|
|
|
207
|
-
async function getRecentAuditLogsForCurrentProject(limit = 12) {
|
|
218
|
+
async function getRecentAuditLogsForCurrentProject(scope, limit = 12) {
|
|
208
219
|
if (!StorageDb?.getAllByIndex) {
|
|
209
220
|
return [];
|
|
210
221
|
}
|
|
211
|
-
const records = await StorageDb.getAllByIndex('auditLogs', 'projectId',
|
|
222
|
+
const records = await StorageDb.getAllByIndex('auditLogs', 'projectId', scope.projectId);
|
|
212
223
|
return (records || [])
|
|
224
|
+
// Legacy unowned audits remain stored but cannot be assigned to whichever
|
|
225
|
+
// account happens to export next, even when a session ID looks familiar.
|
|
226
|
+
.filter(record => record?.projectId === scope.projectId && record.accountScopeId === scope.accountScopeId)
|
|
213
227
|
.slice()
|
|
214
228
|
.sort((left, right) => String(right.createdAt || '').localeCompare(String(left.createdAt || '')))
|
|
215
229
|
.slice(0, limit);
|
|
@@ -19,9 +19,14 @@
|
|
|
19
19
|
<div class="codex-diagnostics-wrap">
|
|
20
20
|
<button type="button" class="codex-diagnostics-trigger" data-diagnostics-menu title="Diagnostics" aria-label="Diagnostics" aria-expanded="false">
|
|
21
21
|
<span class="codex-diagnostics-dot" data-diagnostics-health-dot data-health="unknown"></span>
|
|
22
|
+
<span class="codex-diagnostics-label" data-diagnostics-health-label></span>
|
|
22
23
|
</button>
|
|
23
24
|
<div class="codex-diagnostics-menu" data-diagnostics-popover hidden>
|
|
24
25
|
<div class="codex-diagnostics-hint" data-i18n="diagnosticsHint">Use when Codex cannot run, write, or read files</div>
|
|
26
|
+
<button type="button" data-refresh>
|
|
27
|
+
<span class="codex-diagnostics-refresh-title">${options.icons?.svg?.('refresh') || ''}<span data-i18n="refreshProbeTitle">Refresh file status</span></span>
|
|
28
|
+
<small data-i18n="refreshProbeSubtitle">Re-reads Overleaf state; does not sync or modify files</small>
|
|
29
|
+
</button>
|
|
25
30
|
<button type="button" class="codex-diagnostics-runall" data-diagnostics-run-all>
|
|
26
31
|
<span data-i18n="diagnosticsRunAllTitle">Run all checks</span>
|
|
27
32
|
<small data-i18n="diagnosticsRunAllSubtitle">Connection, write access, project read, OT mirror</small>
|
|
@@ -81,6 +86,10 @@
|
|
|
81
86
|
|
|
82
87
|
function bindStaticActions(instance) {
|
|
83
88
|
const root = instance.container;
|
|
89
|
+
root.querySelector('[data-refresh]')?.addEventListener('click', () => {
|
|
90
|
+
closeMenu(instance);
|
|
91
|
+
instance.callbacks.onRefresh?.();
|
|
92
|
+
});
|
|
84
93
|
root.querySelector('[data-diagnostics-menu]')?.addEventListener('click', () => toggleMenu(instance));
|
|
85
94
|
root.querySelector('[data-diagnostics-run-all]')?.addEventListener('click', () => instance.callbacks.onRunAll?.());
|
|
86
95
|
root.querySelector('[data-diagnostics-native-env]')?.addEventListener('click', () => instance.callbacks.onNativeEnvironment?.());
|
|
@@ -153,6 +162,35 @@
|
|
|
153
162
|
});
|
|
154
163
|
}
|
|
155
164
|
|
|
165
|
+
// Repaint an already-visible observation without rerunning checks or
|
|
166
|
+
// reopening a dismissed result. User disclosure and scroll choices survive.
|
|
167
|
+
function refreshLocale(target, result) {
|
|
168
|
+
const instance = target?._instance || target;
|
|
169
|
+
if (!instance?.container) return;
|
|
170
|
+
for (const node of instance.container.querySelectorAll('[data-i18n]')) {
|
|
171
|
+
node.textContent = t(instance, node.getAttribute('data-i18n'));
|
|
172
|
+
}
|
|
173
|
+
const close = instance.container.querySelector('[data-diagnostics-result-close]');
|
|
174
|
+
if (close) {
|
|
175
|
+
close.title = t(instance, 'close');
|
|
176
|
+
close.setAttribute('aria-label', t(instance, 'closeDiagnostics'));
|
|
177
|
+
}
|
|
178
|
+
const health = instance.container.querySelector('[data-diagnostics-health-dot]')?.dataset.health;
|
|
179
|
+
updateStatus(instance, { health });
|
|
180
|
+
const root = instance.container.querySelector('[data-diagnostics-result]');
|
|
181
|
+
if (!result || !root || root.hidden || instance.resultDismissed) return;
|
|
182
|
+
const details = root.querySelector('[data-diagnostics-result-details]');
|
|
183
|
+
const scroll = root.querySelector('.codex-diagnostics-result-scroll');
|
|
184
|
+
const open = details?.open, scrollTop = scroll?.scrollTop;
|
|
185
|
+
const checks = Array.from(root.querySelectorAll('.codex-diagnostics-check'), node => node.open);
|
|
186
|
+
showResult(instance, result);
|
|
187
|
+
if (details) details.open = open;
|
|
188
|
+
root.querySelectorAll('.codex-diagnostics-check').forEach((node, index) => {
|
|
189
|
+
if (index < checks.length) node.open = checks[index];
|
|
190
|
+
});
|
|
191
|
+
if (scroll) scroll.scrollTop = scrollTop;
|
|
192
|
+
}
|
|
193
|
+
|
|
156
194
|
function showResult(target, result = {}) {
|
|
157
195
|
const instance = target?._instance || target;
|
|
158
196
|
if (instance?.resultDismissed) return;
|
|
@@ -459,6 +497,15 @@
|
|
|
459
497
|
const tooltip = t(instance, tooltipKey);
|
|
460
498
|
trigger.title = tooltip;
|
|
461
499
|
trigger.setAttribute('aria-label', tooltip);
|
|
500
|
+
trigger.dataset.health = health;
|
|
501
|
+
}
|
|
502
|
+
const label = instance?.container?.querySelector('[data-diagnostics-health-label]');
|
|
503
|
+
if (label) {
|
|
504
|
+
label.textContent = t(instance, {
|
|
505
|
+
ok: 'diagnosticsPillOk',
|
|
506
|
+
warn: 'diagnosticsPillWarn',
|
|
507
|
+
fail: 'diagnosticsPillFail'
|
|
508
|
+
}[health] || 'diagnosticsPillUnknown');
|
|
462
509
|
}
|
|
463
510
|
}
|
|
464
511
|
|
|
@@ -621,6 +668,7 @@
|
|
|
621
668
|
closeResult,
|
|
622
669
|
showLoading,
|
|
623
670
|
showResult,
|
|
671
|
+
refreshLocale,
|
|
624
672
|
uniqueContentSignatures
|
|
625
673
|
};
|
|
626
674
|
})();
|