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
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
getPanel,
|
|
12
12
|
getSessionDisplayTitle,
|
|
13
13
|
getState,
|
|
14
|
+
icons = null,
|
|
14
15
|
isDisplayableSession,
|
|
15
16
|
isSessionRunning,
|
|
16
17
|
startNewSession,
|
|
@@ -20,19 +21,20 @@
|
|
|
20
21
|
|
|
21
22
|
function applySessionLabel() {
|
|
22
23
|
const trigger = getPanel().querySelector('[data-session-menu-trigger]');
|
|
23
|
-
if (trigger) {
|
|
24
|
-
trigger.title = tr('sessionMenuOpen');
|
|
25
|
-
trigger.setAttribute('aria-label', tr('sessionMenuOpen'));
|
|
26
|
-
}
|
|
27
24
|
const textNode = getPanel().querySelector('[data-session-label-text]');
|
|
28
25
|
const deleteButton = getPanel().querySelector('[data-session-delete]');
|
|
29
26
|
const renameButton = getPanel().querySelector('[data-session-rename]');
|
|
30
27
|
const renameInput = getPanel().querySelector('[data-session-rename-input]');
|
|
31
28
|
const active = getActiveSession(getState());
|
|
29
|
+
const label = active && isDisplayableSession(active)
|
|
30
|
+
? getSessionDisplayTitle(active)
|
|
31
|
+
: tr('newSessionFallback');
|
|
32
32
|
if (textNode) {
|
|
33
|
-
textNode.textContent =
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
textNode.textContent = label;
|
|
34
|
+
}
|
|
35
|
+
if (trigger) {
|
|
36
|
+
trigger.title = `${label} · ${tr('sessionMenuOpen')}`;
|
|
37
|
+
trigger.setAttribute('aria-label', `${tr('sessionMenuOpen')}: ${label}`);
|
|
36
38
|
}
|
|
37
39
|
if (deleteButton) {
|
|
38
40
|
const running = active ? isSessionRunning(active) : false;
|
|
@@ -111,11 +113,15 @@
|
|
|
111
113
|
.slice()
|
|
112
114
|
.sort((a, b) => String(b.updatedAt || b.createdAt || '').localeCompare(String(a.updatedAt || a.createdAt || '')));
|
|
113
115
|
for (const session of sessions) {
|
|
114
|
-
const row = document.createElement('
|
|
115
|
-
row.type = 'button';
|
|
116
|
+
const row = document.createElement('div');
|
|
116
117
|
row.className = 'codex-session-menu-item';
|
|
118
|
+
row.setAttribute('role', 'none');
|
|
117
119
|
row.dataset.active = session.id === state?.activeSessionId ? 'true' : 'false';
|
|
118
120
|
row.dataset.running = isSessionRunning(session) ? 'true' : 'false';
|
|
121
|
+
const switchButton = document.createElement('button');
|
|
122
|
+
switchButton.type = 'button';
|
|
123
|
+
switchButton.className = 'codex-session-menu-switch';
|
|
124
|
+
switchButton.setAttribute('role', 'menuitem');
|
|
119
125
|
const title = document.createElement('span');
|
|
120
126
|
title.className = 'codex-session-menu-item-title';
|
|
121
127
|
title.textContent = getSessionDisplayTitle(session);
|
|
@@ -127,26 +133,56 @@
|
|
|
127
133
|
if (absoluteTs) {
|
|
128
134
|
time.title = new Date(absoluteTs).toLocaleString();
|
|
129
135
|
}
|
|
130
|
-
|
|
131
|
-
|
|
136
|
+
switchButton.append(title, time);
|
|
137
|
+
switchButton.addEventListener('click', event => {
|
|
132
138
|
event.stopPropagation();
|
|
133
139
|
closeSessionMenu();
|
|
134
140
|
if (session.id !== getState()?.activeSessionId) {
|
|
135
141
|
switchSession(session.id);
|
|
136
142
|
}
|
|
137
143
|
});
|
|
144
|
+
const deleteButton = menuAction('codex-session-menu-item-delete', 'close', '',
|
|
145
|
+
row.dataset.running === 'true' ? tr('deleteRunningSession') : tr('deleteSession'),
|
|
146
|
+
() => deleteSessionWithConfirm(session.id));
|
|
147
|
+
deleteButton.setAttribute('role', 'menuitem');
|
|
148
|
+
deleteButton.disabled = row.dataset.running === 'true';
|
|
149
|
+
row.append(switchButton, deleteButton);
|
|
138
150
|
menu.append(row);
|
|
139
151
|
}
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
152
|
+
const footer = document.createElement('div');
|
|
153
|
+
footer.className = 'codex-session-menu-footer';
|
|
154
|
+
const active = getActiveSession(state);
|
|
155
|
+
const running = active ? isSessionRunning(active) : false;
|
|
156
|
+
const soleEmpty = Boolean(active) && !isDisplayableSession(active) && (state?.sessions || []).length <= 1;
|
|
157
|
+
const createButton = menuAction('codex-session-menu-new', 'plus', tr('sessionMenuNewShort'), tr('newSession'), () => startNewSession());
|
|
158
|
+
const renameButton = menuAction('codex-session-menu-rename', 'pencil', tr('sessionMenuRenameShort'), tr('renameSession'), () => beginActiveSessionRename());
|
|
159
|
+
renameButton.disabled = !active;
|
|
160
|
+
const deleteButton = menuAction('codex-session-menu-delete', 'close', tr('sessionMenuDeleteShort'),
|
|
161
|
+
running ? tr('deleteRunningSession') : tr('deleteSession'), () => {
|
|
162
|
+
if (getState()?.activeSessionId) deleteSessionWithConfirm(getState().activeSessionId);
|
|
163
|
+
});
|
|
164
|
+
deleteButton.disabled = !active || running || soleEmpty;
|
|
165
|
+
footer.append(createButton, renameButton, deleteButton);
|
|
166
|
+
menu.append(footer);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function menuAction(className, iconName, label, description, onSelect) {
|
|
170
|
+
const button = document.createElement('button');
|
|
171
|
+
button.type = 'button';
|
|
172
|
+
button.className = className;
|
|
173
|
+
button.title = description;
|
|
174
|
+
button.setAttribute('aria-label', description);
|
|
175
|
+
const glyph = icons?.svg?.(iconName);
|
|
176
|
+
if (glyph) button.insertAdjacentHTML('beforeend', glyph);
|
|
177
|
+
const text = document.createElement('span');
|
|
178
|
+
text.textContent = label;
|
|
179
|
+
button.append(text);
|
|
180
|
+
button.addEventListener('click', event => {
|
|
145
181
|
event.stopPropagation();
|
|
146
182
|
closeSessionMenu();
|
|
147
|
-
|
|
183
|
+
onSelect();
|
|
148
184
|
});
|
|
149
|
-
|
|
185
|
+
return button;
|
|
150
186
|
}
|
|
151
187
|
|
|
152
188
|
function beginActiveSessionRename() {
|
|
@@ -74,20 +74,40 @@
|
|
|
74
74
|
.filter(record => !deleted.has(record.id))
|
|
75
75
|
.map(record => [record.id, record]));
|
|
76
76
|
const mergedRecords = sessionRecords.map(record => StorageDb.mergeSessionReviewState?.(
|
|
77
|
-
record, existingById.get(record.id), options.reviewRunIds
|
|
77
|
+
record, existingById.get(record.id), options.reviewRunIds, { shared: StorageDb.sharedSessionsEnabled?.() === true }
|
|
78
78
|
) || record);
|
|
79
|
+
const reviewRunIds = new Set(options.reviewRunIds || []);
|
|
80
|
+
// Shared storage merges local edits and explicitly requested Undo markers
|
|
81
|
+
// against the page baseline. Legacy and ordinary stale saves keep the age guard.
|
|
79
82
|
const writable = mergedRecords.filter(record => {
|
|
80
83
|
const existing = existingById.get(record.id);
|
|
81
84
|
if (!existing) return true;
|
|
82
|
-
return (Date.parse(record.updatedAt || '') || 0) >= (Date.parse(existing.updatedAt || '') || 0)
|
|
85
|
+
return (Date.parse(record.updatedAt || '') || 0) >= (Date.parse(existing.updatedAt || '') || 0)
|
|
86
|
+
|| (StorageDb.sharedSessionsEnabled?.() === true
|
|
87
|
+
&& (StorageDb.hasUnpersistedSharedSession?.(record) === true
|
|
88
|
+
|| (record.runs || []).some(run => reviewRunIds.has(run.id) && run.undoOwnerProtocol === 1)));
|
|
83
89
|
});
|
|
84
90
|
const cleanedExisting = existingSessions.filter((record, index) =>
|
|
85
91
|
record !== rawExistingSessions[index] && !writable.some(item => item.id === record.id)
|
|
86
92
|
);
|
|
87
93
|
if (cleanedExisting.length || writable.length) {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
94
|
+
const reviewReceipts = [];
|
|
95
|
+
if (StorageDb.sharedSessionsEnabled?.() === true && reviewRunIds.size) {
|
|
96
|
+
for (const record of writable) {
|
|
97
|
+
const ids = (record.runs || []).filter(run => reviewRunIds.has(run.id)).map(run => run.id);
|
|
98
|
+
if (ids.length) reviewReceipts.push(await StorageDb.putSessionReviewState(record, ids));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
let written;
|
|
102
|
+
try {
|
|
103
|
+
written = await StorageDb.putRecords('sessions', [...cleanedExisting, ...writable], {
|
|
104
|
+
reviewRunIds: options.reviewRunIds, reviewReceipts
|
|
105
|
+
});
|
|
106
|
+
} catch (error) {
|
|
107
|
+
if (error.code === 'shared_session_conflict' && reviewReceipts.length)
|
|
108
|
+
Object.defineProperty(error, 'reviewReceipts', { value: reviewReceipts, configurable: true });
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
91
111
|
// Check the actual durable result, including a decision already saved
|
|
92
112
|
// from another origin, instead of acknowledging only the proposed view.
|
|
93
113
|
return written.filter(record => writable.some(candidate => candidate.id === record.id));
|
|
@@ -9,8 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
function codexIcon(name) {
|
|
11
11
|
const icons = {
|
|
12
|
+
archive: '<rect x="2.5" y="3" width="11" height="3.2" rx=".8"/><path d="M3.5 6.2v6.3a1 1 0 0 0 1 1h7a1 1 0 0 0 1-1V6.2"/><path d="M6.5 9h3"/>',
|
|
12
13
|
appearance: '<path d="M8 2.2v1.1"/><path d="M8 12.7v1.1"/><path d="M2.2 8h1.1"/><path d="M12.7 8h1.1"/><path d="m3.9 3.9.8.8"/><path d="m11.3 11.3.8.8"/><path d="m12.1 3.9-.8.8"/><path d="m4.7 11.3-.8.8"/><circle cx="8" cy="8" r="2.4"/>',
|
|
13
14
|
bolt: '<path d="M8.9 1.8 3.8 8.8h3.3l-.5 5.4 5.5-7.5H8.8z"/>',
|
|
15
|
+
close: '<path d="m4.6 4.6 6.8 6.8M11.4 4.6l-6.8 6.8"/>',
|
|
14
16
|
database: '<ellipse cx="8" cy="4" rx="4.5" ry="1.9"/><path d="M3.5 4v4c0 1 2 1.9 4.5 1.9s4.5-.9 4.5-1.9V4"/><path d="M3.5 8v4c0 1 2 1.9 4.5 1.9s4.5-.9 4.5-1.9V8"/>',
|
|
15
17
|
flask: '<path d="M6 2.5h4"/><path d="M7 2.5v4.1l-3.4 5.3A1.4 1.4 0 0 0 4.8 14h6.4a1.4 1.4 0 0 0 1.2-2.1L9 6.6V2.5"/><path d="M5.3 10.5h5.4"/>',
|
|
16
18
|
history: '<path d="M4.2 3.4h7.6"/><path d="M4.2 8h7.6"/><path d="M4.2 12.6h4.6"/><path d="M2.2 3.4h.1"/><path d="M2.2 8h.1"/><path d="M2.2 12.6h.1"/>',
|
|
@@ -36,7 +38,9 @@
|
|
|
36
38
|
container,
|
|
37
39
|
callbacks: options.callbacks || {},
|
|
38
40
|
i18n: options.i18n || null,
|
|
39
|
-
button: options.button || null
|
|
41
|
+
button: options.button || null,
|
|
42
|
+
// Names the open project in project-page scope lines; may return ''.
|
|
43
|
+
getProjectName: typeof options.getProjectName === 'function' ? options.getProjectName : null
|
|
40
44
|
};
|
|
41
45
|
|
|
42
46
|
container.innerHTML = `
|
|
@@ -211,6 +215,7 @@
|
|
|
211
215
|
<p class="codex-set-row-help" data-update-settings-summary data-i18n="softwareUpdatesHelp">Automatically checks signed stable releases for the Extension and Native Host.</p>
|
|
212
216
|
<p class="codex-set-note" data-update-settings-state aria-live="polite" hidden></p>
|
|
213
217
|
<button type="button" class="codex-set-btn" data-check-updates data-i18n="checkForUpdates">Check for updates</button>
|
|
218
|
+
<button type="button" class="codex-set-btn" data-restore-previous-version hidden>Restore previous version</button>
|
|
214
219
|
</div>
|
|
215
220
|
</div>
|
|
216
221
|
</details>
|
|
@@ -242,7 +247,7 @@
|
|
|
242
247
|
</label>
|
|
243
248
|
<p class="codex-set-row-help" data-i18n="loadCodexLocalSkillsHelp">Pull skills from your local Codex installation.</p>
|
|
244
249
|
<button type="button" class="codex-skills-entry" data-skills-entry>
|
|
245
|
-
<span class="codex-skills-entry-label" data-i18n="
|
|
250
|
+
<span class="codex-skills-entry-label" data-i18n="skillsManageEntry">Manage skills</span>
|
|
246
251
|
<span class="codex-skills-entry-summary" data-skills-entry-summary></span>
|
|
247
252
|
<span class="codex-skills-entry-chevron" aria-hidden="true">›</span>
|
|
248
253
|
</button>
|
|
@@ -252,9 +257,9 @@
|
|
|
252
257
|
</section>
|
|
253
258
|
<section class="codex-custom-instructions-panel codex-skills-panel" data-skills-screen>
|
|
254
259
|
<div class="codex-custom-instructions-head">
|
|
255
|
-
<button type="button" data-skills-back title="Back" aria-label="Back">‹</button>
|
|
260
|
+
<button type="button" data-skills-back data-i18n-title="settingsBack" data-i18n-aria-label="settingsBack" title="Back" aria-label="Back">‹</button>
|
|
256
261
|
<div>
|
|
257
|
-
<div class="codex-custom-instructions-title" data-i18n="
|
|
262
|
+
<div class="codex-custom-instructions-title" data-i18n="localSkillsTitle">Skills</div>
|
|
258
263
|
</div>
|
|
259
264
|
<span class="codex-set-saved" data-set-saved hidden><svg class="codex-glyph" viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="m3.5 8 3 3 6-6"/></svg><span data-i18n="settingsSaved">Saved</span></span>
|
|
260
265
|
</div>
|
|
@@ -266,6 +271,9 @@
|
|
|
266
271
|
</div>
|
|
267
272
|
<div class="codex-skills-divider"></div>
|
|
268
273
|
<div class="codex-local-skill-list" data-local-skill-list></div>
|
|
274
|
+
<div class="codex-skills-divider"></div>
|
|
275
|
+
<div class="codex-wb-skills-list-title codex-wb-skills-caption" data-i18n="codexLocalSkillsTitle">Local Codex skills</div>
|
|
276
|
+
<div class="codex-local-skill-list" data-codex-local-skill-list></div>
|
|
269
277
|
</section>
|
|
270
278
|
`;
|
|
271
279
|
|
|
@@ -331,6 +339,7 @@
|
|
|
331
339
|
return host || null;
|
|
332
340
|
},
|
|
333
341
|
setProviderCloseGuard: guard => instance.workbench?.setProviderCloseGuard(guard),
|
|
342
|
+
revealGroup: key => instance.workbench?.revealGroup(key) || null,
|
|
334
343
|
loadState: state => loadState(instance, state),
|
|
335
344
|
readState: () => readState(instance),
|
|
336
345
|
setStatus: (text, status) => setStatus(instance, text, status),
|
|
@@ -338,6 +347,7 @@
|
|
|
338
347
|
setSkillsSummary: text => setSkillsSummary(instance, text),
|
|
339
348
|
setProviderSummary: summary => setProviderSummary(instance, summary),
|
|
340
349
|
refreshNotes: () => updateGovernanceNotes(instance),
|
|
350
|
+
refreshLocale: () => instance.workbench?.refresh(),
|
|
341
351
|
destroy: () => destroy(instance),
|
|
342
352
|
_instance: instance
|
|
343
353
|
};
|
|
@@ -460,7 +470,9 @@
|
|
|
460
470
|
};
|
|
461
471
|
}
|
|
462
472
|
|
|
463
|
-
|
|
473
|
+
// options.page names the workbench page a message belongs to; the workbench
|
|
474
|
+
// shows it only while that page is active. Untagged messages show everywhere.
|
|
475
|
+
function setStatus(target, text, status = 'info', options = {}) {
|
|
464
476
|
const instance = target?._instance || target;
|
|
465
477
|
const element = instance?.container?.querySelector('[data-project-settings-status]');
|
|
466
478
|
if (!element) {
|
|
@@ -468,6 +480,9 @@
|
|
|
468
480
|
}
|
|
469
481
|
element.textContent = text || '';
|
|
470
482
|
element.dataset.status = status;
|
|
483
|
+
if (options.page) element.dataset.statusPage = options.page;
|
|
484
|
+
else delete element.dataset.statusPage;
|
|
485
|
+
instance.workbench?.refresh();
|
|
471
486
|
}
|
|
472
487
|
|
|
473
488
|
function clearStatus(target) {
|
|
@@ -478,6 +493,8 @@
|
|
|
478
493
|
}
|
|
479
494
|
element.textContent = '';
|
|
480
495
|
delete element.dataset.status;
|
|
496
|
+
delete element.dataset.statusPage;
|
|
497
|
+
instance.workbench?.refresh();
|
|
481
498
|
}
|
|
482
499
|
|
|
483
500
|
function setSkillsSummary(target, text) {
|
|
@@ -4,21 +4,32 @@
|
|
|
4
4
|
})(typeof globalThis !== 'undefined' ? globalThis : this, function () {
|
|
5
5
|
'use strict';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
['
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
// The sidebar is split by scope; a page's section decides whether its groups
|
|
8
|
+
// need an open project. Pages: [id, label key, icon].
|
|
9
|
+
const SECTIONS = [
|
|
10
|
+
['project', 'settingsScopeProjectTitle', [
|
|
11
|
+
['writing', 'settingsWorkbenchWriting', 'pen'],
|
|
12
|
+
['protection', 'settingsWorkbenchProtection', 'shield'],
|
|
13
|
+
['cache', 'otSettingsTitle', 'flask'],
|
|
14
|
+
['history', 'settingsWorkbenchChanges', 'history']
|
|
15
|
+
]],
|
|
16
|
+
['global', 'settingsScopeGlobalTitle', [
|
|
17
|
+
['appearance', 'appearanceTitle', 'appearance'],
|
|
18
|
+
['providers', 'settingsWorkbenchModels', 'bolt'],
|
|
19
|
+
['context', 'settingsWorkbenchContextSkills', 'database'],
|
|
20
|
+
['storage', 'storageTitle', 'archive'],
|
|
21
|
+
['updates', 'softwareUpdatesTitle', 'software']
|
|
22
|
+
]]
|
|
15
23
|
];
|
|
16
24
|
const GROUP_PAGES = {
|
|
17
|
-
|
|
18
|
-
experimental: '
|
|
19
|
-
|
|
25
|
+
'writing-style': 'writing', personalization: 'writing', protection: 'protection', privacy: 'protection',
|
|
26
|
+
experimental: 'cache', history: 'history', appearance: 'appearance', providers: 'providers',
|
|
27
|
+
'context-loading': 'context', skills: 'context', storage: 'storage', updates: 'updates'
|
|
20
28
|
};
|
|
21
|
-
|
|
29
|
+
// Groups without a mapping keep their original scope.
|
|
30
|
+
const FALLBACK_PAGES = { project: 'writing', global: 'context' };
|
|
31
|
+
// The skills list opens in place of the page that holds the Skills group.
|
|
32
|
+
const SKILLS_PAGE = 'context';
|
|
22
33
|
|
|
23
34
|
function mount(instance, options = {}) {
|
|
24
35
|
const container = instance.container, doc = container.ownerDocument;
|
|
@@ -50,93 +61,94 @@
|
|
|
50
61
|
const status = settings.querySelector('[data-project-settings-status]');
|
|
51
62
|
const dialog = make('dialog', 'codex-settings-workbench');
|
|
52
63
|
dialog.setAttribute('aria-labelledby', 'codex-settings-workbench-title');
|
|
53
|
-
const
|
|
54
|
-
const heading = make('div', 'codex-wb-heading');
|
|
55
|
-
const title = make('h2', '', 'settingsWorkbenchTitle');
|
|
64
|
+
const title = make('h2', 'codex-wb-title', 'settingsWorkbenchTitle');
|
|
56
65
|
title.id = 'codex-settings-workbench-title';
|
|
57
|
-
heading.append(title, make('p', '', 'settingsWorkbenchSubtitle'));
|
|
58
66
|
closeButton.classList.add('codex-wb-close');
|
|
59
|
-
closeButton.
|
|
60
|
-
|
|
67
|
+
if (options.icon) closeButton.innerHTML = options.icon('close'); // Static, repository-owned icon path.
|
|
68
|
+
else closeButton.textContent = '\u00d7';
|
|
61
69
|
originalHead?.remove();
|
|
62
70
|
|
|
63
71
|
const layout = make('div', 'codex-wb-layout');
|
|
64
72
|
const sidebar = make('aside', 'codex-wb-sidebar');
|
|
65
|
-
const filters = make('div', 'codex-wb-filters');
|
|
66
|
-
filters.setAttribute('role', 'group');
|
|
67
|
-
const allFilter = button('', 'settingsWorkbenchAll');
|
|
68
|
-
const projectFilter = button('', 'settingsScopeProjectTitle');
|
|
69
|
-
filters.append(allFilter, projectFilter);
|
|
70
73
|
const nav = make('nav', 'codex-wb-nav');
|
|
71
74
|
nav.setAttribute('role', 'tablist');
|
|
72
75
|
nav.setAttribute('aria-orientation', 'vertical');
|
|
73
|
-
|
|
74
|
-
brand.textContent = 'Codex Overleaf Link';
|
|
75
|
-
sidebar.append(filters, nav, brand);
|
|
76
|
+
sidebar.append(title, nav);
|
|
76
77
|
const main = make('div', 'codex-wb-main');
|
|
77
78
|
const body = make('div', 'codex-wb-body');
|
|
78
79
|
const footer = make('footer', 'codex-wb-footer');
|
|
79
80
|
if (status) { status.setAttribute('aria-live', 'polite'); footer.append(status); }
|
|
80
81
|
main.append(body, footer);
|
|
81
82
|
layout.append(sidebar, main);
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
// The close button floats over the content's top-right corner.
|
|
84
|
+
dialog.append(layout, closeButton);
|
|
85
|
+
const pages = new Map(), navButtons = new Map(), pageScopes = new Map(), sectionLabels = new Map(), groups = [];
|
|
86
|
+
let active = 'writing', returnFocus = null, destroyed = false;
|
|
85
87
|
let providerRequested = false, providerCloseGuard = null, closing = null;
|
|
86
88
|
|
|
87
|
-
for (const [
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
89
|
+
for (const [scope, sectionKey, items] of SECTIONS) {
|
|
90
|
+
// Visual section heading; each tab references it as its description.
|
|
91
|
+
const label = make('div', 'codex-wb-nav-section', sectionKey);
|
|
92
|
+
label.id = 'codex-settings-nav-section-' + scope;
|
|
93
|
+
label.setAttribute('aria-hidden', 'true');
|
|
94
|
+
nav.append(label);
|
|
95
|
+
sectionLabels.set(scope, label);
|
|
96
|
+
for (const [id, key, icon] of items) {
|
|
97
|
+
const page = make('section', 'codex-wb-page');
|
|
98
|
+
page.id = 'codex-settings-page-' + id;
|
|
99
|
+
page.dataset.workbenchPage = id;
|
|
100
|
+
page.setAttribute('role', 'tabpanel');
|
|
101
|
+
page.setAttribute('aria-labelledby', 'codex-settings-nav-' + id);
|
|
102
|
+
page.hidden = true;
|
|
103
|
+
page.append(make('h3', 'codex-wb-page-title', key), make('p', 'codex-wb-page-scope'));
|
|
104
|
+
pages.set(id, page);
|
|
105
|
+
pageScopes.set(id, scope);
|
|
106
|
+
const tab = button('codex-wb-nav-button');
|
|
107
|
+
tab.id = 'codex-settings-nav-' + id;
|
|
108
|
+
tab.setAttribute('role', 'tab');
|
|
109
|
+
tab.setAttribute('aria-controls', page.id);
|
|
110
|
+
tab.setAttribute('aria-describedby', label.id);
|
|
111
|
+
if (options.icon) {
|
|
112
|
+
const glyph = make('span', 'codex-wb-nav-icon');
|
|
113
|
+
glyph.innerHTML = options.icon(icon); // Static, repository-owned icon paths only.
|
|
114
|
+
tab.append(glyph);
|
|
115
|
+
}
|
|
116
|
+
tab.append(make('span', '', key));
|
|
117
|
+
listen(tab, 'click', () => select(id));
|
|
118
|
+
nav.append(tab);
|
|
119
|
+
navButtons.set(id, tab);
|
|
104
120
|
}
|
|
105
|
-
tab.append(make('span', '', key));
|
|
106
|
-
listen(tab, 'click', () => select(id));
|
|
107
|
-
nav.append(tab);
|
|
108
|
-
navButtons.set(id, tab);
|
|
109
121
|
}
|
|
110
|
-
function addGroup(node, category
|
|
122
|
+
function addGroup(node, category) {
|
|
123
|
+
const projectOnly = pageScopes.get(category) === 'project';
|
|
111
124
|
node.hidden = true;
|
|
112
125
|
node.dataset.workbenchScope = projectOnly ? 'project' : 'global';
|
|
113
126
|
const summary = node.querySelector('summary');
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
127
|
+
if (summary) {
|
|
128
|
+
// Groups are plain sections: always open while their page is shown.
|
|
129
|
+
summary.tabIndex = -1;
|
|
130
|
+
listen(summary, 'click', event => event.preventDefault());
|
|
131
|
+
}
|
|
117
132
|
pages.get(category).append(node);
|
|
118
|
-
groups.push({ node, category, projectOnly
|
|
133
|
+
groups.push({ node, category, projectOnly });
|
|
119
134
|
}
|
|
135
|
+
const fallbackPage = scope => FALLBACK_PAGES[
|
|
136
|
+
scope && !scope.classList.contains('codex-project-settings-scope--global') ? 'project' : 'global'];
|
|
120
137
|
// Move existing controls rather than copying them. Their listeners, unsaved
|
|
121
138
|
// values, identity, validation and persistence callbacks remain attached.
|
|
122
139
|
for (const group of Array.from(settings.querySelectorAll('[data-set-group]'))) {
|
|
123
140
|
const key = group.dataset.setGroup;
|
|
124
|
-
|
|
125
|
-
const projectOnly = PROJECT_GROUPS.has(key)
|
|
126
|
-
|| (!GROUP_PAGES[key] && originalScope && !originalScope.classList.contains('codex-project-settings-scope--global'));
|
|
127
|
-
addGroup(group, GROUP_PAGES[key] || 'instructions', Boolean(projectOnly));
|
|
141
|
+
addGroup(group, GROUP_PAGES[key] || fallbackPage(group.closest('.codex-project-settings-scope')));
|
|
128
142
|
}
|
|
129
|
-
// Preserve non-card controls
|
|
130
|
-
// Scope headings are replaced by labels on the actual groups.
|
|
143
|
+
// Preserve non-card controls. The sidebar sections replace the scope headings.
|
|
131
144
|
for (const scope of Array.from(settings.querySelectorAll('.codex-project-settings-scope'))) {
|
|
132
145
|
scope.querySelectorAll('.codex-project-settings-scope-title').forEach(node => node.remove());
|
|
133
|
-
if (scope.children.length)
|
|
134
|
-
|
|
135
|
-
} else scope.remove();
|
|
146
|
+
if (scope.children.length) addGroup(scope, fallbackPage(scope));
|
|
147
|
+
else scope.remove();
|
|
136
148
|
}
|
|
137
149
|
for (const node of Array.from(settings.children)) {
|
|
138
150
|
if (node === status) continue;
|
|
139
|
-
addGroup(node,
|
|
151
|
+
addGroup(node, FALLBACK_PAGES.global);
|
|
140
152
|
}
|
|
141
153
|
const providerHost = make('div', 'codex-wb-provider-host');
|
|
142
154
|
providerHost.dataset.providerSettingsHost = '';
|
|
@@ -218,31 +230,62 @@
|
|
|
218
230
|
&& /^\/project\/[^/]+/.test(win?.location?.pathname || '');
|
|
219
231
|
}
|
|
220
232
|
function available(item) {
|
|
221
|
-
return
|
|
233
|
+
return !item.projectOnly || hasProject();
|
|
234
|
+
}
|
|
235
|
+
// A page whose only visible group repeats the page title hides that group's
|
|
236
|
+
// title; the group header keeps only its Saved mark.
|
|
237
|
+
function refreshSoleSections() {
|
|
238
|
+
for (const page of pages.values()) {
|
|
239
|
+
const pageGroups = Array.from(page.querySelectorAll('.codex-set-group'));
|
|
240
|
+
const visibleGroups = pageGroups.filter(node => !node.hidden);
|
|
241
|
+
const pageTitle = page.querySelector('.codex-wb-page-title')?.textContent.trim();
|
|
242
|
+
for (const node of pageGroups) {
|
|
243
|
+
const groupTitle = node.querySelector('.codex-set-group-head .codex-set-group-title');
|
|
244
|
+
const sole = visibleGroups.length === 1 && visibleGroups[0] === node
|
|
245
|
+
&& groupTitle && groupTitle.textContent.trim() === pageTitle;
|
|
246
|
+
if (sole) node.dataset.soleSection = 'true';
|
|
247
|
+
else delete node.dataset.soleSection;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// Each page states its scope once, under its title.
|
|
252
|
+
function renderPageScope(page, scope, projectName) {
|
|
253
|
+
const line = page.querySelector('.codex-wb-page-scope');
|
|
254
|
+
if (!line) return;
|
|
255
|
+
const text = t(scope === 'project' ? 'settingsPageScopeProject' : 'settingsPageScopeGlobal');
|
|
256
|
+
if (scope !== 'project' || !projectName) { line.textContent = text; return; }
|
|
257
|
+
const name = doc.createElement('b');
|
|
258
|
+
name.textContent = projectName;
|
|
259
|
+
line.replaceChildren(text + ' \u00b7 ', name);
|
|
222
260
|
}
|
|
223
261
|
function refresh() {
|
|
224
262
|
if (destroyed) return;
|
|
225
|
-
if (
|
|
226
|
-
if (panel.dataset.view === 'skills') { active = 'instructions'; filter = 'all'; }
|
|
263
|
+
if (panel.dataset.view === 'skills') active = SKILLS_PAGE;
|
|
227
264
|
const availablePages = new Set(groups.filter(available).map(item => item.category));
|
|
228
|
-
if (!availablePages.has(active)) active =
|
|
265
|
+
if (!availablePages.has(active)) active = Array.from(navButtons.keys()).find(id => availablePages.has(id)) || 'appearance';
|
|
229
266
|
for (const node of dialog.querySelectorAll('[data-i18n]')) {
|
|
230
267
|
// Existing controls use their established translation pass; update the
|
|
231
268
|
// newly owned chrome only, without replacing controls or skill rows.
|
|
232
|
-
if (node.closest('.codex-wb-
|
|
269
|
+
if (node.closest('.codex-wb-nav, .codex-wb-footer')
|
|
270
|
+
|| node.classList.contains('codex-wb-title')
|
|
233
271
|
|| node.classList.contains('codex-wb-page-title')
|
|
234
|
-
|| node.classList.contains('codex-wb-scope-label')
|
|
235
272
|
|| node.classList.contains('codex-wb-theme-caption')
|
|
236
273
|
|| node.classList.contains('codex-wb-skills-caption')) node.textContent = t(node.dataset.i18n);
|
|
237
274
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
275
|
+
const projectName = hasProject() ? String(instance.getProjectName?.() || '').trim() : '';
|
|
276
|
+
for (const [id, page] of pages) renderPageScope(page, pageScopes.get(id), projectName);
|
|
277
|
+
for (const [scope, label] of sectionLabels) {
|
|
278
|
+
label.hidden = !Array.from(pageScopes).some(([id, pageScope]) => pageScope === scope && availablePages.has(id));
|
|
279
|
+
}
|
|
241
280
|
nav.setAttribute('aria-label', t('settingsWorkbenchCategories'));
|
|
242
|
-
allFilter.setAttribute('aria-pressed', String(filter === 'all'));
|
|
243
|
-
projectFilter.setAttribute('aria-pressed', String(filter === 'project'));
|
|
244
281
|
closeButton.title = t('settingsWorkbenchClose');
|
|
245
282
|
closeButton.setAttribute('aria-label', t('settingsWorkbenchClose'));
|
|
283
|
+
const skillsBack = skills?.querySelector('[data-skills-back]');
|
|
284
|
+
if (skillsBack) {
|
|
285
|
+
skillsBack.title = t('settingsBack');
|
|
286
|
+
skillsBack.setAttribute('aria-label', t('settingsBack'));
|
|
287
|
+
}
|
|
288
|
+
if (status) status.hidden = Boolean(status.dataset.statusPage) && status.dataset.statusPage !== active;
|
|
246
289
|
for (const [id, tab] of navButtons) {
|
|
247
290
|
tab.hidden = !availablePages.has(id);
|
|
248
291
|
tab.setAttribute('aria-selected', String(id === active));
|
|
@@ -251,12 +294,11 @@
|
|
|
251
294
|
}
|
|
252
295
|
for (const item of groups) {
|
|
253
296
|
const visible = available(item) && item.category === active && panel.dataset.view !== 'skills';
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
item.node.open = visible && item.expanded;
|
|
257
|
-
}
|
|
297
|
+
// Opening a group when its page is shown keeps the lazy toggle loaders (history, storage).
|
|
298
|
+
if (item.node.tagName === 'DETAILS' && item.node.open !== visible) item.node.open = visible;
|
|
258
299
|
item.node.hidden = !visible;
|
|
259
300
|
}
|
|
301
|
+
refreshSoleSections();
|
|
260
302
|
updateThemes();
|
|
261
303
|
}
|
|
262
304
|
function requestProviders() {
|
|
@@ -272,9 +314,17 @@
|
|
|
272
314
|
try { Promise.resolve(instance.callbacks.onProvidersOpen()).catch(failed); }
|
|
273
315
|
catch (error) { failed(error); }
|
|
274
316
|
}
|
|
317
|
+
// Shows the page that holds a group and returns the group, or null when the
|
|
318
|
+
// group is unavailable (for example a project group outside a project).
|
|
319
|
+
function revealGroup(key) {
|
|
320
|
+
const item = groups.find(entry => entry.node.dataset?.setGroup === key);
|
|
321
|
+
if (!item || !available(item)) return null;
|
|
322
|
+
active = item.category;
|
|
323
|
+
refresh();
|
|
324
|
+
return item.node;
|
|
325
|
+
}
|
|
275
326
|
function revealProviders() {
|
|
276
327
|
active = 'providers';
|
|
277
|
-
filter = 'all';
|
|
278
328
|
providerRequested = true;
|
|
279
329
|
pages.get('providers').dataset.providerEmbedded = 'true';
|
|
280
330
|
panel.dataset.view = 'settings';
|
|
@@ -325,13 +375,6 @@
|
|
|
325
375
|
if (['settings', 'skills'].includes(panel.dataset.view)) show();
|
|
326
376
|
else hide();
|
|
327
377
|
};
|
|
328
|
-
listen(allFilter, 'click', () => { filter = 'all'; refresh(); });
|
|
329
|
-
listen(projectFilter, 'click', () => {
|
|
330
|
-
filter = 'project';
|
|
331
|
-
if (panel.dataset.view === 'skills') instance.callbacks.onSkillsBack?.();
|
|
332
|
-
refresh();
|
|
333
|
-
body.scrollTop = 0;
|
|
334
|
-
});
|
|
335
378
|
listen(nav, 'keydown', event => {
|
|
336
379
|
if (!['ArrowUp', 'ArrowDown', 'Home', 'End'].includes(event.key)) return;
|
|
337
380
|
const tabs = Array.from(navButtons.values()).filter(tab => !tab.hidden);
|
|
@@ -358,7 +401,7 @@
|
|
|
358
401
|
observer.observe(panel, { attributes: true, attributeFilter: ['data-view', 'data-settings-scope', 'data-theme'] });
|
|
359
402
|
refresh();
|
|
360
403
|
return {
|
|
361
|
-
show, hide, refresh, revealProviders,
|
|
404
|
+
show, hide, refresh, revealGroup, revealProviders,
|
|
362
405
|
setProviderCloseGuard(guard) { providerCloseGuard = guard; },
|
|
363
406
|
destroy() {
|
|
364
407
|
destroyed = true;
|