clay-server 5.2.0-beta.8 → 5.2.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 +0 -4
- package/lib/clay-product-control-tools.js +1 -0
- package/lib/clay-product-control.js +14 -11
- package/lib/clay-vendor-usage.js +44 -0
- package/lib/github-star-count.js +147 -0
- package/lib/notes-checklist.js +43 -1
- package/lib/notes.js +2 -1
- package/lib/pane-pending-interactions.js +20 -0
- package/lib/pane-session-activation.js +114 -0
- package/lib/pane-session-transport.js +26 -0
- package/lib/project-session-notes.js +33 -8
- package/lib/project-sessions.js +78 -29
- package/lib/project-start-protocol.js +29 -0
- package/lib/project-vendor-login.js +2 -0
- package/lib/project.js +16 -4
- package/lib/public/app.js +41 -18
- package/lib/public/css/contextual-clay.css +2 -2
- package/lib/public/css/filebrowser.css +1 -1
- package/lib/public/css/input.css +6 -0
- package/lib/public/css/mate-loading-scene.css +21 -0
- package/lib/public/css/overlays.css +64 -256
- package/lib/public/css/project-mate-creation.css +5 -6
- package/lib/public/css/project-start.css +108 -0
- package/lib/public/css/projects-hub.css +53 -14
- package/lib/public/css/settings-shell.css +103 -0
- package/lib/public/css/sidebar.css +7 -0
- package/lib/public/css/sticky-notes.css +37 -11
- package/lib/public/css/title-bar.css +83 -0
- package/lib/public/index.html +50 -63
- package/lib/public/modules/account-transport-settings.js +8 -2
- package/lib/public/modules/admin-settings-email.js +7 -2
- package/lib/public/modules/admin-settings-invitations.js +2 -2
- package/lib/public/modules/admin-settings-projects.js +2 -2
- package/lib/public/modules/admin-settings-ui.js +20 -4
- package/lib/public/modules/admin-settings-users.js +4 -4
- package/lib/public/modules/app-connection.js +3 -0
- package/lib/public/modules/app-home-hub.js +2 -1
- package/lib/public/modules/app-message-router.js +13 -0
- package/lib/public/modules/app-messages.js +35 -7
- package/lib/public/modules/app-misc.js +3 -1
- package/lib/public/modules/app-projects.js +6 -407
- package/lib/public/modules/app-rate-limit.js +12 -1
- package/lib/public/modules/clay-owner-navigation.js +0 -3
- package/lib/public/modules/clay-studio-render.js +3 -1
- package/lib/public/modules/clay-tool-presentation.js +1 -0
- package/lib/public/modules/command-palette.js +52 -14
- package/lib/public/modules/contextual-clay-workspace.js +14 -2
- package/lib/public/modules/contextual-clay.js +19 -4
- package/lib/public/modules/contextual-mate-context.js +6 -4
- package/lib/public/modules/elicitation-form.js +5 -0
- package/lib/public/modules/github-star.js +66 -0
- package/lib/public/modules/history-replay-batch.js +8 -0
- package/lib/public/modules/home-surface-boot.js +0 -1
- package/lib/public/modules/input.js +55 -11
- package/lib/public/modules/mate-loading-scene.js +17 -0
- package/lib/public/modules/message-delivery.js +10 -2
- package/lib/public/modules/model-picker.js +2 -0
- package/lib/public/modules/pane-activation.js +214 -0
- package/lib/public/modules/pane-appearance-bridge.js +59 -0
- package/lib/public/modules/pane-binding.js +82 -0
- package/lib/public/modules/pane-bridge.js +5 -2
- package/lib/public/modules/pane-browser-bridge.js +5 -3
- package/lib/public/modules/pane-file-bridge.js +4 -0
- package/lib/public/modules/pane-issue-bridge.js +4 -1
- package/lib/public/modules/profile.js +11 -3
- package/lib/public/modules/project-mate-creation-workspace.js +13 -4
- package/lib/public/modules/project-session-visibility-settings.js +19 -16
- package/lib/public/modules/project-settings-environment.js +12 -1
- package/lib/public/modules/project-settings.js +119 -129
- package/lib/public/modules/project-start-dialog.js +130 -0
- package/lib/public/modules/project-start-folder-state.js +78 -0
- package/lib/public/modules/project-start-folder-view.js +190 -0
- package/lib/public/modules/project-start-forms.js +66 -0
- package/lib/public/modules/project-start-path.js +60 -0
- package/lib/public/modules/project-start-state.js +54 -0
- package/lib/public/modules/project-start-submit.js +67 -0
- package/lib/public/modules/projects-hub-view.js +32 -44
- package/lib/public/modules/projects-hub.js +39 -28
- package/lib/public/modules/rewind.js +5 -0
- package/lib/public/modules/server-settings.js +36 -91
- package/lib/public/modules/session-actions.js +5 -2
- package/lib/public/modules/session-context-menu.js +5 -0
- package/lib/public/modules/session-rich-drafts.js +21 -0
- package/lib/public/modules/session-switch-defer.js +67 -0
- package/lib/public/modules/settings-project-target.js +56 -0
- package/lib/public/modules/settings-select.js +1 -1
- package/lib/public/modules/settings-shell-registry.js +88 -0
- package/lib/public/modules/settings-shell-view.js +104 -0
- package/lib/public/modules/settings-shell.js +342 -0
- package/lib/public/modules/sidebar-mobile.js +8 -30
- package/lib/public/modules/sidebar-projects.js +2 -1
- package/lib/public/modules/split-group-restore.js +68 -0
- package/lib/public/modules/split-pair-ui.js +1 -0
- package/lib/public/modules/split-pane-reconciler.js +15 -0
- package/lib/public/modules/split-pane-renderer.js +87 -6
- package/lib/public/modules/split-session-boundary.js +1 -1
- package/lib/public/modules/split-view.js +51 -52
- package/lib/public/modules/sticky-notes-checklist.js +51 -6
- package/lib/public/modules/stt-controller.js +4 -1
- package/lib/public/modules/stt-recording.js +1 -1
- package/lib/public/modules/theme.js +31 -3
- package/lib/public/modules/tools.js +18 -2
- package/lib/public/modules/user-settings-integrations.js +2 -1
- package/lib/public/modules/user-settings-layout.js +12 -34
- package/lib/public/modules/user-settings-profile.js +1 -1
- package/lib/public/modules/user-settings.js +18 -85
- package/lib/public/modules/vendor-usage-format.js +93 -0
- package/lib/public/modules/vendor-usage-list.js +45 -0
- package/lib/public/modules/vendor-usage-model.js +215 -0
- package/lib/public/modules/vendor-usage-overview.js +323 -0
- package/lib/public/style.css +10 -7
- package/lib/public/welcome-art/conversation-desk.png +0 -0
- package/lib/public/welcome-art/mate-clay.png +0 -0
- package/lib/public/welcome-art/project-clay.png +0 -0
- package/lib/sdk-bridge.js +6 -1
- package/lib/sdk-message-processor.js +9 -1
- package/lib/sdk-quota-snapshot.js +20 -2
- package/lib/server-github-stars.js +39 -0
- package/lib/server-global-ws.js +21 -17
- package/lib/server.js +11 -0
- package/lib/session-notes-mcp-server.js +26 -4
- package/lib/session-notes-writes.js +88 -0
- package/lib/session-visibility.js +20 -8
- package/lib/sessions.js +27 -10
- package/lib/vendor-usage-acp-readers.js +97 -0
- package/lib/vendor-usage-capabilities.js +88 -0
- package/lib/vendor-usage-http-readers.js +214 -0
- package/lib/vendor-usage-metrics.js +47 -0
- package/lib/vendor-usage-native-readers.js +106 -0
- package/lib/vendor-usage-overview.js +406 -0
- package/lib/vendor-usage-service.js +281 -0
- package/lib/ws-schema.js +4 -2
- package/lib/yoke/adapters/claude.js +12 -0
- package/lib/yoke/adapters/codex-query-contract.js +1 -0
- package/lib/yoke/adapters/codex.js +45 -12
- package/lib/yoke/claude-hook-installer.js +1 -0
- package/lib/yoke/codex-dynamic-tool-names.js +80 -0
- package/lib/yoke/codex-model-catalog.js +37 -3
- package/lib/yoke/muse-services.js +16 -3
- package/lib/yoke/providers/claude-model-descriptions.js +22 -2
- package/lib/yoke/vendor-registry.js +6 -2
- package/package.json +5 -3
- package/lib/public/modules/server-settings-navigation.js +0 -39
|
@@ -26,6 +26,7 @@ import { clearMcpPermissionModePending } from './mcp-ui.js';
|
|
|
26
26
|
import { createWebSocketLifecycle } from './websocket-lifecycle.js';
|
|
27
27
|
import { createWebSocketWatchdog } from './websocket-watchdog.js';
|
|
28
28
|
import { resetHistoryReplayBatch } from './history-replay-batch.js';
|
|
29
|
+
import { paneOutgoing } from './pane-activation.js';
|
|
29
30
|
|
|
30
31
|
var connectOverlay = null;
|
|
31
32
|
var hasConnectedOnce = false;
|
|
@@ -371,6 +372,8 @@ export function connect() {
|
|
|
371
372
|
var currentWs = getWs();
|
|
372
373
|
var _origSend = currentWs.send.bind(currentWs);
|
|
373
374
|
currentWs.send = function (data) {
|
|
375
|
+
data = paneOutgoing(data);
|
|
376
|
+
if (data === null) return false;
|
|
374
377
|
blinkIO();
|
|
375
378
|
return _origSend(data);
|
|
376
379
|
};
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
import { showProjectsHub, hideProjectsHub } from './projects-hub.js';
|
|
4
4
|
import { store } from './store.js';
|
|
5
5
|
import { getWs } from './ws-ref.js';
|
|
6
|
-
import { getCachedProjects,
|
|
6
|
+
import { getCachedProjects, switchProject } from './app-projects.js';
|
|
7
|
+
import { openAddProjectModal } from './project-start-dialog.js';
|
|
7
8
|
import { chooseProjectActivationTarget, homeProjectCreationState } from './project-activation.js';
|
|
8
9
|
import { mateAvatarUrl } from './avatar.js';
|
|
9
10
|
import { exitDmMode } from './app-dm.js';
|
|
@@ -17,6 +17,8 @@ import { handleDefaultAiMessage } from './default-ai.js';
|
|
|
17
17
|
import { handleCursorSharingMessage } from './cursor-sharing-preference.js';
|
|
18
18
|
import { handlePendingMessageQueueMessage } from './pending-message-queue.js';
|
|
19
19
|
import { receiveHistoryReplay } from './history-replay-batch.js';
|
|
20
|
+
import { filterPaneActivation } from './pane-activation.js';
|
|
21
|
+
import { deferSessionSwitch } from './session-switch-defer.js';
|
|
20
22
|
import { handleProjectMateCreationMessage } from './project-mate-creation-workspace.js';
|
|
21
23
|
import { handleProjectDebatePlanningMessage } from './project-debate-planning-workspace.js';
|
|
22
24
|
|
|
@@ -94,6 +96,17 @@ export function handleHomeProtocolMessage(msg) {
|
|
|
94
96
|
}
|
|
95
97
|
|
|
96
98
|
export function processMessage(msg) {
|
|
99
|
+
if (filterPaneActivation(msg)) return;
|
|
100
|
+
if (deferSessionSwitch(msg)) return;
|
|
101
|
+
if (msg.type === 'pane_history_batch') {
|
|
102
|
+
if (!msg.paneActivation || !Array.isArray(msg.items) || msg.items.length > 100) return;
|
|
103
|
+
msg.items.forEach(function (item) {
|
|
104
|
+
// Every original event keeps its order/index and goes through the same
|
|
105
|
+
// stale-binding filter and replay handler as an individual socket event.
|
|
106
|
+
if (item && item.type !== 'pane_history_batch') processMessage(Object.assign({}, item, { paneActivation: msg.paneActivation }));
|
|
107
|
+
});
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
97
110
|
receiveHistoryReplay(msg, dispatchMessage);
|
|
98
111
|
}
|
|
99
112
|
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { handleStudioDocumentMessage } from './clay-studio-document.js';
|
|
2
|
+
import { saveSessionRichDraft, restoreSessionRichDraft } from './session-rich-drafts.js';
|
|
3
|
+
import { refreshPaneActivation, primePaneSession } from './pane-activation.js';
|
|
4
|
+
import { paneCallbackCurrent } from './pane-binding.js';
|
|
2
5
|
import { handleClayControlActivity } from './clay-control-activity.js';
|
|
3
6
|
import { handleContextualWorkspaceMessage } from './contextual-clay-workspace.js';
|
|
4
7
|
import { handleContextualSessionMessage } from './contextual-clay-session.js';
|
|
@@ -62,7 +65,7 @@ import { showDoneNotification, playDoneSound, isNotifAlertEnabled, isNotifSoundE
|
|
|
62
65
|
import { handleFsList, handleFsRead, handleFileChanged, handleDirChanged, handleFileHistory, handleGitDiff, handleFileAt, refreshIfOpen, getPendingNavigate, handleFsSearch, presentMarkdownEdit } from './filebrowser.js';
|
|
63
66
|
import { beginMarkdownTurn, finishMarkdownTurn, markdownPathFromToolInput } from './markdown-live-edit.js';
|
|
64
67
|
import { forwardPaneMarkdownPresentation } from './pane-bridge.js';
|
|
65
|
-
import { handleProjectOwnerChanged } from './project-settings.js';
|
|
68
|
+
import { handleProjectOwnerChanged, handleProjectSettingsEditResult } from './project-settings.js';
|
|
66
69
|
import { handleProjectEnv, handleProjectEnvSaved } from './project-settings-environment.js';
|
|
67
70
|
import { handleProjectSessionVisibilityDefault, refreshProjectSessionVisibilitySettings } from './project-session-visibility-settings.js';
|
|
68
71
|
import { updateSettingsStats, updateDaemonConfig, handleSetPinResult, handleKeepAwakeChanged, handleAutoContinueChanged, handleRestartResult, handleShutdownResult, handleSharedEnv, handleSharedEnvSaved, handleServerSettingResult } from './server-settings.js';
|
|
@@ -97,13 +100,15 @@ import { markProjectSessionListHydrated, applyProjectSplitGroups, clearProjectSp
|
|
|
97
100
|
import { selectDefaultVendorForBlankSession } from './vendor-selection.js';
|
|
98
101
|
import { getModelInfoUpdate, modelEntryValue, modelEntryMatches, handleModelSelectionResult, requestVendorModels } from './model-picker.js';
|
|
99
102
|
import { getModelEffortLevels, accumulateUsage, updateUsagePanel, accumulateContext, updateContextPanel, renderCtxPopover, updateStatusPanel, markContextUnavailable } from './app-panels.js';
|
|
100
|
-
import { updateProjectList, resetClientState, showUpdateAvailable, handleRemoveProjectCheckResult, handleRemoveProjectResult,
|
|
103
|
+
import { updateProjectList, resetClientState, showUpdateAvailable, handleRemoveProjectCheckResult, handleRemoveProjectResult, finishProjectSessionActivation } from './app-projects.js';
|
|
104
|
+
import { handleBrowseDirResult, handleAddProjectResult, handleCloneProgress } from './project-start-dialog.js';
|
|
101
105
|
import { updateHistorySentinel, prependOlderHistory } from './app-header.js';
|
|
102
106
|
import { handleToolsState, handleToolInstalled, handleToolRemoved, handleToolStorageResult, handleToolLlmResult, handleToolsError, handleToolControlRequest, handleToolServerState, handleToolServerEvent, handleCapsuleGameSession } from './home-tools.js';
|
|
103
107
|
import { handleHomeDockState } from './home-dock.js';
|
|
104
108
|
import { handleToolFrameUrlState } from './home-tool-frame.js';
|
|
105
109
|
import { enterDmMode, exitDmMode, handleMateCreatedInApp, updateMateIconStatus, appendDmMessage, showDmTypingIndicator, buildMateInterviewPrompt } from './app-dm.js';
|
|
106
110
|
import { handleRateLimitEvent, updateRateLimitUsage, handleFastModeState } from './app-rate-limit.js';
|
|
111
|
+
import { handleVendorUsageOverview } from './vendor-usage-overview.js';
|
|
107
112
|
import { handleRemoteCursorMove, handleRemoteCursorLeave, handleRemoteSelection, clearRemoteCursors } from './app-cursors.js';
|
|
108
113
|
import { showLoopBanner, updateLoopBanner, updateLoopInputVisibility, showRalphApprovalBar, updateRalphApprovalStatus, openRalphPreviewModal, showExecModal, updateExecModalStatus } from './app-loop-ui.js';
|
|
109
114
|
import { handleAutonomousRunMessage, syncAutonomousRunForSession } from './autonomous-run.js';
|
|
@@ -268,6 +273,7 @@ export function processMessage(msg) {
|
|
|
268
273
|
break;
|
|
269
274
|
|
|
270
275
|
case "history_done":
|
|
276
|
+
var historyPaintEpoch = store.get('sessionActionEpoch') || 0;
|
|
271
277
|
if (messagesEl && msg.sessionId === store.get("activeSessionId") && msg.sessionOriginId === store.get("sessionOriginId")) { messagesEl.dataset.controlSessionId = String(msg.sessionId); messagesEl.dataset.controlSessionOrigin = msg.sessionOriginId; messagesEl.dataset.controlHistoryRevision = msg.controlHistoryRevision || ""; }
|
|
272
278
|
store.set({ replayingHistory: false });
|
|
273
279
|
resumeThinkingAfterReplay(store.get('sessionIsProcessing'));
|
|
@@ -350,6 +356,7 @@ export function processMessage(msg) {
|
|
|
350
356
|
// Scroll to tool element if navigating from file edit history
|
|
351
357
|
if (hasNavTarget) {
|
|
352
358
|
requestAnimationFrame(function() {
|
|
359
|
+
if (historyPaintEpoch !== (store.get('sessionActionEpoch') || 0) || !paneCallbackCurrent(msg.paneActivation)) return;
|
|
353
360
|
// Prefer scrolling to the exact tool element
|
|
354
361
|
var target = nav.toolId ? messagesEl.querySelector('[data-tool-id="' + nav.toolId + '"]') : null;
|
|
355
362
|
if (!target && nav.assistantUuid) {
|
|
@@ -365,7 +372,7 @@ export function processMessage(msg) {
|
|
|
365
372
|
}
|
|
366
373
|
});
|
|
367
374
|
}
|
|
368
|
-
requestAnimationFrame(function () { handlePaletteHistoryDone(); });
|
|
375
|
+
requestAnimationFrame(function () { if (historyPaintEpoch === (store.get('sessionActionEpoch') || 0) && paneCallbackCurrent(msg.paneActivation)) handlePaletteHistoryDone(); });
|
|
369
376
|
break;
|
|
370
377
|
|
|
371
378
|
case "restore_mate_dm":
|
|
@@ -777,9 +784,11 @@ export function processMessage(msg) {
|
|
|
777
784
|
markProjectSessionListHydrated();
|
|
778
785
|
renderMateSessionList(msg.sessions || []);
|
|
779
786
|
renderSessionList(msg.sessions || []);
|
|
787
|
+
store.set({ paneBindingSessions: msg.sessions || [] });
|
|
788
|
+
refreshPaneActivation();
|
|
780
789
|
syncGithubSessions(msg.sessions || []);
|
|
781
790
|
syncPaneTitles();
|
|
782
|
-
var panePin = resolvePaneSession(store.get('paneMode'), store.get('panePinPending'), store.get('paneSessionId'), msg.sessions);
|
|
791
|
+
var panePin = resolvePaneSession(store.get('paneMode') && !primePaneSession(), store.get('panePinPending'), store.get('paneSessionId'), msg.sessions);
|
|
783
792
|
if (panePin.consumed) {
|
|
784
793
|
store.set({ panePinPending: false });
|
|
785
794
|
if (panePin.sessionId && getWs() && getWs().readyState === 1) {
|
|
@@ -906,6 +915,8 @@ export function processMessage(msg) {
|
|
|
906
915
|
break;
|
|
907
916
|
|
|
908
917
|
case "session_switched":
|
|
918
|
+
saveSessionRichDraft();
|
|
919
|
+
store.set({ sessionActionEpoch: (store.get('sessionActionEpoch') || 0) + 1 });
|
|
909
920
|
clearPairResultStatus();
|
|
910
921
|
resetStreamBuffer();
|
|
911
922
|
syncAutonomousRunForSession(msg.autonomousRun || null);
|
|
@@ -923,7 +934,7 @@ export function processMessage(msg) {
|
|
|
923
934
|
? msg.runtimeTerminalId
|
|
924
935
|
: (typeof msg.terminalId === "number" ? msg.terminalId : null);
|
|
925
936
|
var _sessionRole = msg.sessionRole === "worker" ? "worker" : "driver";
|
|
926
|
-
store.set({ activeSessionId: msg.id, sessionOriginId: msg.sessionOriginId || null, cliSessionId: msg.cliSessionId || null, currentModel: msg.model || "", currentEffort: msg.effort ||
|
|
937
|
+
store.set({ activeSessionId: msg.id, sessionOriginId: msg.sessionOriginId || null, cliSessionId: msg.cliSessionId || null, currentModel: msg.model || "", currentEffort: msg.effort || '', vendorCapabilities: msg.capabilities || {}, sessionIsProcessing: !!msg.isProcessing, turnActivity: null, activeSessionMode: _effectiveMode, activeTerminalId: _effectiveTerminalId, sessionHasHistory: !!msg.hasHistory, sessionVendorBound: !!msg.vendor || !!msg.hasHistory, sessionFullAccess: msg.permissionMode === "bypassPermissions", currentMode: msg.permissionMode || 'default', effectivePermissionMode: msg.effectivePermissionMode || null, permissionCapabilities: msg.permissionCapabilities || { auto: false, mcpOverride: false }, mcpPermissionModeOverrides: msg.mcpPermissionModeOverrides || {}, activeSessionMateId: _sessionRole === "worker" ? null : (store.get('activeProjectMateId') || null), activeSessionMateName: _sessionRole === "worker" ? "" : (store.get('activeProjectMateName') || "") });
|
|
927
938
|
handleScheduledTaskSessionSwitched(msg);
|
|
928
939
|
requestLoopInterviewState();
|
|
929
940
|
activateDeliverySession(msg.id, msg.cliSessionId || null, msg.sessionOriginId || null);
|
|
@@ -998,14 +1009,19 @@ export function processMessage(msg) {
|
|
|
998
1009
|
// Restore draft for incoming session
|
|
999
1010
|
var draft = store.get('sessionDrafts')[store.get('activeSessionId')] || "";
|
|
1000
1011
|
inputEl.value = draft;
|
|
1012
|
+
restoreSessionRichDraft();
|
|
1001
1013
|
autoResize();
|
|
1002
1014
|
if (!("ontouchstart" in window)) {
|
|
1003
1015
|
inputEl.focus();
|
|
1004
1016
|
}
|
|
1005
1017
|
// Reload survival: a restored active session that is a split-group
|
|
1006
1018
|
// member reopens its group (no-op when a split is already open).
|
|
1007
|
-
|
|
1008
|
-
|
|
1019
|
+
var deferredSwitch = store.get('deferredSessionSwitch');
|
|
1020
|
+
if (!deferredSwitch || !deferredSwitch.draining || deferredSwitch.finalSwitch === msg) {
|
|
1021
|
+
finishProjectSessionActivation();
|
|
1022
|
+
maybeRestoreSplitGroup();
|
|
1023
|
+
handlePaletteSessionSwitch(true);
|
|
1024
|
+
}
|
|
1009
1025
|
break;
|
|
1010
1026
|
|
|
1011
1027
|
case "session_full_access_changed":
|
|
@@ -1350,6 +1366,11 @@ export function processMessage(msg) {
|
|
|
1350
1366
|
stopUrgentBlink();
|
|
1351
1367
|
break;
|
|
1352
1368
|
|
|
1369
|
+
case "ask_user_pending":
|
|
1370
|
+
renderAskUserQuestion(msg.toolId, msg.input);
|
|
1371
|
+
startUrgentBlink();
|
|
1372
|
+
break;
|
|
1373
|
+
|
|
1353
1374
|
case "permission_request_pending":
|
|
1354
1375
|
store.set({ turnActivity: null });
|
|
1355
1376
|
setActivity(null);
|
|
@@ -1596,6 +1617,10 @@ export function processMessage(msg) {
|
|
|
1596
1617
|
updateRateLimitUsage(msg);
|
|
1597
1618
|
break;
|
|
1598
1619
|
|
|
1620
|
+
case "vendor_usage_overview":
|
|
1621
|
+
handleVendorUsageOverview(msg);
|
|
1622
|
+
break;
|
|
1623
|
+
|
|
1599
1624
|
case "auto_continue_scheduled":
|
|
1600
1625
|
// Scheduler auto-continue, just show info
|
|
1601
1626
|
break;
|
|
@@ -1770,6 +1795,7 @@ export function processMessage(msg) {
|
|
|
1770
1795
|
store.set({ pendingTermCommand: null });
|
|
1771
1796
|
// Small delay to let terminal initialize
|
|
1772
1797
|
setTimeout(function() {
|
|
1798
|
+
if (!paneCallbackCurrent(msg.paneActivation)) return;
|
|
1773
1799
|
sendTerminalCommand(cmd);
|
|
1774
1800
|
}, 300);
|
|
1775
1801
|
}
|
|
@@ -1902,12 +1928,14 @@ export function processMessage(msg) {
|
|
|
1902
1928
|
break;
|
|
1903
1929
|
|
|
1904
1930
|
case "set_project_title_result":
|
|
1931
|
+
handleProjectSettingsEditResult(msg);
|
|
1905
1932
|
if (!msg.ok) {
|
|
1906
1933
|
showToast(msg.error || "Failed to rename project", "error");
|
|
1907
1934
|
}
|
|
1908
1935
|
break;
|
|
1909
1936
|
|
|
1910
1937
|
case "set_project_icon_result":
|
|
1938
|
+
handleProjectSettingsEditResult(msg);
|
|
1911
1939
|
if (!msg.ok) {
|
|
1912
1940
|
showToast(msg.error || "Failed to set icon", "error");
|
|
1913
1941
|
}
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
import { refreshIcons, iconHtml } from './icons.js';
|
|
5
5
|
import { getWs } from './ws-ref.js';
|
|
6
|
+
import { store } from './store.js';
|
|
7
|
+
import { sessionCallback } from './pane-binding.js';
|
|
6
8
|
import { updateBrowserTabList } from './context-sources.js';
|
|
7
9
|
import { setExtensionConnected } from './mcp-ui.js';
|
|
8
10
|
import { initPasteModal } from './paste-modal.js';
|
|
@@ -270,7 +272,7 @@ export function showConfirm(text, onConfirm, okLabel, destructive, onCancel) {
|
|
|
270
272
|
confirmCancelCallback = null;
|
|
271
273
|
if (replaced) replaced();
|
|
272
274
|
confirmText.textContent = text;
|
|
273
|
-
confirmCallback = onConfirm;
|
|
275
|
+
confirmCallback = store.get('paneCommittedBinding') ? sessionCallback(onConfirm) : onConfirm;
|
|
274
276
|
confirmCancelCallback = onCancel || null;
|
|
275
277
|
confirmOk.textContent = okLabel || "Delete";
|
|
276
278
|
confirmOk.className = "confirm-btn " + (destructive === false ? "confirm-ok" : "confirm-delete");
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { prepareContextualWorkspaceDeparture } from './contextual-clay-workspace.js';
|
|
2
|
+
import { checkComposerDeparture, saveSessionRichDraft } from './session-rich-drafts.js';
|
|
2
3
|
// app-projects.js - Project list, switching, add/remove project modals
|
|
3
4
|
// Extracted from app.js (PR-29)
|
|
4
5
|
|
|
5
6
|
import { showProjectsHub, hideProjectsHub, completeProjectsOnboarding } from './projects-hub.js';
|
|
6
|
-
import {
|
|
7
|
+
import { showToast } from './utils.js';
|
|
7
8
|
import { refreshIcons } from './icons.js';
|
|
8
|
-
import { parseEmojis } from './markdown.js';
|
|
9
9
|
import { store } from './store.js';
|
|
10
10
|
import { resetModelPickerState } from './model-picker.js';
|
|
11
11
|
import { getWs, setWs } from './ws-ref.js';
|
|
@@ -49,157 +49,6 @@ var cachedRemovedProjects = [];
|
|
|
49
49
|
var pendingRemoveSlug = null;
|
|
50
50
|
var pendingRemoveName = null;
|
|
51
51
|
|
|
52
|
-
// Add-project modal state
|
|
53
|
-
var addProjectModal = null;
|
|
54
|
-
var addProjectInput = null;
|
|
55
|
-
var addProjectCreateInput = null;
|
|
56
|
-
var addProjectCloneInput = null;
|
|
57
|
-
var addProjectCloneProgress = null;
|
|
58
|
-
var addProjectSuggestions = null;
|
|
59
|
-
var addProjectError = null;
|
|
60
|
-
var addProjectOk = null;
|
|
61
|
-
var addProjectCancel = null;
|
|
62
|
-
var addProjectModeBtns = null;
|
|
63
|
-
var addProjectPanels = null;
|
|
64
|
-
var addProjectRemoved = null;
|
|
65
|
-
var addProjectPrefixEl = null;
|
|
66
|
-
var addProjectPrefixValue = "";
|
|
67
|
-
var addProjectDebounce = null;
|
|
68
|
-
var addProjectActiveIdx = -1;
|
|
69
|
-
var addProjectMode = "existing";
|
|
70
|
-
|
|
71
|
-
export function initProjects() {
|
|
72
|
-
// Init add-project modal DOM refs
|
|
73
|
-
addProjectModal = document.getElementById("add-project-modal");
|
|
74
|
-
addProjectInput = document.getElementById("add-project-input");
|
|
75
|
-
addProjectCreateInput = document.getElementById("add-project-create-input");
|
|
76
|
-
addProjectCloneInput = document.getElementById("add-project-clone-input");
|
|
77
|
-
addProjectCloneProgress = document.getElementById("add-project-clone-progress");
|
|
78
|
-
addProjectSuggestions = document.getElementById("add-project-suggestions");
|
|
79
|
-
addProjectError = document.getElementById("add-project-error");
|
|
80
|
-
addProjectOk = document.getElementById("add-project-ok");
|
|
81
|
-
addProjectCancel = document.getElementById("add-project-cancel");
|
|
82
|
-
addProjectModeBtns = addProjectModal.querySelectorAll(".add-project-mode-btn");
|
|
83
|
-
addProjectPanels = addProjectModal.querySelectorAll(".add-project-panel");
|
|
84
|
-
addProjectRemoved = document.getElementById("add-project-removed");
|
|
85
|
-
addProjectPrefixEl = document.getElementById("add-project-prefix");
|
|
86
|
-
|
|
87
|
-
// Mode button click listeners
|
|
88
|
-
for (var mbi = 0; mbi < addProjectModeBtns.length; mbi++) {
|
|
89
|
-
addProjectModeBtns[mbi].addEventListener("click", function () {
|
|
90
|
-
if (this.disabled) return;
|
|
91
|
-
switchAddProjectMode(this.dataset.mode);
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Existing project input listeners
|
|
96
|
-
addProjectInput.addEventListener("focus", function () {
|
|
97
|
-
var val = addProjectInput.value;
|
|
98
|
-
if ((val || addProjectPrefixValue) && addProjectSuggestions.children.length === 0) {
|
|
99
|
-
requestBrowseDir(val);
|
|
100
|
-
} else if (addProjectSuggestions.children.length > 0) {
|
|
101
|
-
addProjectSuggestions.classList.remove("hidden");
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
addProjectModal.querySelector(".confirm-dialog").addEventListener("click", function (e) {
|
|
106
|
-
if (e.target === addProjectInput || addProjectInput.contains(e.target)) return;
|
|
107
|
-
if (e.target === addProjectSuggestions || addProjectSuggestions.contains(e.target)) return;
|
|
108
|
-
addProjectSuggestions.classList.add("hidden");
|
|
109
|
-
addProjectActiveIdx = -1;
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
addProjectInput.addEventListener("input", function () {
|
|
113
|
-
var val = addProjectInput.value;
|
|
114
|
-
addProjectError.classList.add("hidden");
|
|
115
|
-
if (addProjectDebounce) clearTimeout(addProjectDebounce);
|
|
116
|
-
addProjectDebounce = setTimeout(function () {
|
|
117
|
-
requestBrowseDir(val);
|
|
118
|
-
}, 200);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
addProjectInput.addEventListener("keydown", function (e) {
|
|
122
|
-
var items = addProjectSuggestions.querySelectorAll(".add-project-suggestion-item");
|
|
123
|
-
|
|
124
|
-
if (e.key === "ArrowDown") {
|
|
125
|
-
e.preventDefault();
|
|
126
|
-
if (items.length > 0) {
|
|
127
|
-
var next = addProjectActiveIdx < items.length - 1 ? addProjectActiveIdx + 1 : 0;
|
|
128
|
-
setActiveIdx(next);
|
|
129
|
-
}
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (e.key === "ArrowUp") {
|
|
134
|
-
e.preventDefault();
|
|
135
|
-
if (items.length > 0) {
|
|
136
|
-
var prev = addProjectActiveIdx > 0 ? addProjectActiveIdx - 1 : items.length - 1;
|
|
137
|
-
setActiveIdx(prev);
|
|
138
|
-
}
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (e.key === "Tab") {
|
|
143
|
-
e.preventDefault();
|
|
144
|
-
var target = addProjectActiveIdx >= 0 && addProjectActiveIdx < items.length
|
|
145
|
-
? items[addProjectActiveIdx]
|
|
146
|
-
: items.length > 0 ? items[0] : null;
|
|
147
|
-
if (target) {
|
|
148
|
-
var fullP = target.dataset.path + "/";
|
|
149
|
-
addProjectInput.value = stripPrefix(fullP);
|
|
150
|
-
addProjectError.classList.add("hidden");
|
|
151
|
-
requestBrowseDir(addProjectInput.value);
|
|
152
|
-
}
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (e.key === "Enter") {
|
|
157
|
-
e.preventDefault();
|
|
158
|
-
if (addProjectActiveIdx >= 0 && addProjectActiveIdx < items.length) {
|
|
159
|
-
var fullPicked = items[addProjectActiveIdx].dataset.path + "/";
|
|
160
|
-
addProjectInput.value = stripPrefix(fullPicked);
|
|
161
|
-
addProjectError.classList.add("hidden");
|
|
162
|
-
requestBrowseDir(addProjectInput.value);
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
submitAddProject();
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (e.key === "Escape") {
|
|
170
|
-
e.preventDefault();
|
|
171
|
-
closeAddProjectModal();
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
// Enter key on create/clone inputs
|
|
177
|
-
addProjectCreateInput.addEventListener("keydown", function (e) {
|
|
178
|
-
if (e.key === "Enter") { e.preventDefault(); submitAddProject(); }
|
|
179
|
-
if (e.key === "Escape") { e.preventDefault(); closeAddProjectModal(); }
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
addProjectCloneInput.addEventListener("keydown", function (e) {
|
|
183
|
-
if (e.key === "Enter") { e.preventDefault(); submitAddProject(); }
|
|
184
|
-
if (e.key === "Escape") { e.preventDefault(); closeAddProjectModal(); }
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
addProjectOk.addEventListener("click", function () { submitAddProject(); });
|
|
188
|
-
addProjectCancel.addEventListener("click", function () { closeAddProjectModal(); });
|
|
189
|
-
|
|
190
|
-
// Close on backdrop click
|
|
191
|
-
addProjectModal.querySelector(".confirm-backdrop").addEventListener("click", function () {
|
|
192
|
-
closeAddProjectModal();
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
// Project list add button
|
|
196
|
-
var projectListAddBtn = document.getElementById("project-list-add");
|
|
197
|
-
if (projectListAddBtn) {
|
|
198
|
-
projectListAddBtn.addEventListener("click", function () {
|
|
199
|
-
openAddProjectModal();
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
52
|
|
|
204
53
|
// --- State accessors ---
|
|
205
54
|
|
|
@@ -391,6 +240,10 @@ export function resetClientState() {
|
|
|
391
240
|
|
|
392
241
|
export function switchProject(slug) {
|
|
393
242
|
if (!slug) return;
|
|
243
|
+
if (slug !== store.get('currentSlug')) {
|
|
244
|
+
try { checkComposerDeparture(); saveSessionRichDraft(); }
|
|
245
|
+
catch (error) { showToast(error.message, 'warn'); return; }
|
|
246
|
+
}
|
|
394
247
|
if (prepareContextualWorkspaceDeparture(slug) === false) return;
|
|
395
248
|
var target = cachedProjects.find(function (project) { return project.slug === slug; });
|
|
396
249
|
if (target && target.contentAccess === false && target.administrativeAccess === true) {
|
|
@@ -638,257 +491,3 @@ export function handleRemoveProjectResult(msg) {
|
|
|
638
491
|
showToast(msg.error || "Failed to remove project", "error");
|
|
639
492
|
}
|
|
640
493
|
}
|
|
641
|
-
|
|
642
|
-
// --- Add project modal ---
|
|
643
|
-
|
|
644
|
-
function switchAddProjectMode(mode) {
|
|
645
|
-
addProjectMode = mode;
|
|
646
|
-
for (var mi = 0; mi < addProjectModeBtns.length; mi++) {
|
|
647
|
-
var btn = addProjectModeBtns[mi];
|
|
648
|
-
if (btn.dataset.mode === mode) {
|
|
649
|
-
btn.classList.add("active");
|
|
650
|
-
} else {
|
|
651
|
-
btn.classList.remove("active");
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
for (var pi = 0; pi < addProjectPanels.length; pi++) {
|
|
655
|
-
var panel = addProjectPanels[pi];
|
|
656
|
-
if (panel.dataset.panel === mode) {
|
|
657
|
-
panel.classList.add("active");
|
|
658
|
-
} else {
|
|
659
|
-
panel.classList.remove("active");
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
addProjectError.classList.add("hidden");
|
|
663
|
-
addProjectCloneProgress.classList.add("hidden");
|
|
664
|
-
if (mode === "existing") {
|
|
665
|
-
addProjectOk.textContent = "Add";
|
|
666
|
-
} else if (mode === "create") {
|
|
667
|
-
addProjectOk.textContent = "Create";
|
|
668
|
-
} else if (mode === "clone") {
|
|
669
|
-
addProjectOk.textContent = "Clone";
|
|
670
|
-
}
|
|
671
|
-
setTimeout(function () {
|
|
672
|
-
if (mode === "existing") {
|
|
673
|
-
addProjectInput.focus();
|
|
674
|
-
} else if (mode === "create") {
|
|
675
|
-
addProjectCreateInput.focus();
|
|
676
|
-
} else if (mode === "clone") {
|
|
677
|
-
addProjectCloneInput.focus();
|
|
678
|
-
}
|
|
679
|
-
}, 50);
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
export function openAddProjectModal(mode) {
|
|
683
|
-
addProjectModal.classList.remove("hidden");
|
|
684
|
-
addProjectCreateInput.value = "";
|
|
685
|
-
addProjectCloneInput.value = "";
|
|
686
|
-
addProjectError.classList.add("hidden");
|
|
687
|
-
addProjectError.textContent = "";
|
|
688
|
-
addProjectCloneProgress.classList.add("hidden");
|
|
689
|
-
addProjectSuggestions.classList.add("hidden");
|
|
690
|
-
addProjectSuggestions.innerHTML = "";
|
|
691
|
-
addProjectActiveIdx = -1;
|
|
692
|
-
addProjectOk.disabled = false;
|
|
693
|
-
var existingBtn = addProjectModal.querySelector('.add-project-mode-btn[data-mode="existing"]');
|
|
694
|
-
var st = store.snap();
|
|
695
|
-
if (st.isOsUsers) {
|
|
696
|
-
existingBtn.disabled = false;
|
|
697
|
-
var myUser = st.cachedAllUsers.find(function (u) { return u.id === st.myUserId; });
|
|
698
|
-
var isAdmin = myUser && myUser.role === "admin";
|
|
699
|
-
if (!isAdmin && myUser && myUser.linuxUser) {
|
|
700
|
-
// Non-admin: lock prefix to home directory
|
|
701
|
-
addProjectPrefixValue = "/home/" + myUser.linuxUser + "/";
|
|
702
|
-
addProjectPrefixEl.textContent = addProjectPrefixValue;
|
|
703
|
-
addProjectPrefixEl.classList.remove("hidden");
|
|
704
|
-
addProjectInput.value = "";
|
|
705
|
-
addProjectInput.placeholder = "subdirectory";
|
|
706
|
-
} else {
|
|
707
|
-
// Admin: no prefix restriction
|
|
708
|
-
addProjectPrefixValue = "";
|
|
709
|
-
addProjectPrefixEl.classList.add("hidden");
|
|
710
|
-
addProjectInput.value = "/";
|
|
711
|
-
addProjectInput.placeholder = "/";
|
|
712
|
-
}
|
|
713
|
-
switchAddProjectMode("existing");
|
|
714
|
-
} else {
|
|
715
|
-
addProjectPrefixValue = "";
|
|
716
|
-
addProjectPrefixEl.classList.add("hidden");
|
|
717
|
-
addProjectInput.value = "/";
|
|
718
|
-
addProjectInput.placeholder = "/";
|
|
719
|
-
existingBtn.disabled = false;
|
|
720
|
-
switchAddProjectMode("existing");
|
|
721
|
-
}
|
|
722
|
-
if (mode === "create" || mode === "clone") switchAddProjectMode(mode);
|
|
723
|
-
renderRemovedProjectsList();
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
function renderRemovedProjectsList() {
|
|
727
|
-
if (!addProjectRemoved) return;
|
|
728
|
-
addProjectRemoved.innerHTML = "";
|
|
729
|
-
if (!cachedRemovedProjects || cachedRemovedProjects.length === 0) {
|
|
730
|
-
addProjectRemoved.classList.add("hidden");
|
|
731
|
-
return;
|
|
732
|
-
}
|
|
733
|
-
addProjectRemoved.classList.remove("hidden");
|
|
734
|
-
for (var ri = 0; ri < cachedRemovedProjects.length; ri++) {
|
|
735
|
-
var rp = cachedRemovedProjects[ri];
|
|
736
|
-
var item = document.createElement("div");
|
|
737
|
-
item.className = "add-project-removed-item";
|
|
738
|
-
item.dataset.path = rp.path;
|
|
739
|
-
item.addEventListener("click", function () {
|
|
740
|
-
var p = this.dataset.path;
|
|
741
|
-
var ws = getWs();
|
|
742
|
-
if (ws && ws.readyState === 1) {
|
|
743
|
-
ws.send(JSON.stringify({ type: "add_project", path: p }));
|
|
744
|
-
}
|
|
745
|
-
closeAddProjectModal();
|
|
746
|
-
});
|
|
747
|
-
var iconEl = document.createElement("span");
|
|
748
|
-
iconEl.className = "add-project-removed-icon";
|
|
749
|
-
iconEl.textContent = rp.icon || "\uD83D\uDCC1";
|
|
750
|
-
item.appendChild(iconEl);
|
|
751
|
-
var info = document.createElement("div");
|
|
752
|
-
info.className = "add-project-removed-info";
|
|
753
|
-
var nameEl = document.createElement("div");
|
|
754
|
-
nameEl.className = "add-project-removed-name";
|
|
755
|
-
nameEl.textContent = rp.title || rp.path.split("/").pop() || rp.path;
|
|
756
|
-
info.appendChild(nameEl);
|
|
757
|
-
var pathEl = document.createElement("div");
|
|
758
|
-
pathEl.className = "add-project-removed-path";
|
|
759
|
-
pathEl.textContent = rp.path;
|
|
760
|
-
info.appendChild(pathEl);
|
|
761
|
-
item.appendChild(info);
|
|
762
|
-
addProjectRemoved.appendChild(item);
|
|
763
|
-
}
|
|
764
|
-
try { parseEmojis(addProjectRemoved); } catch (e) {}
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
export function closeAddProjectModal() {
|
|
768
|
-
addProjectModal.classList.add("hidden");
|
|
769
|
-
addProjectInput.value = "";
|
|
770
|
-
addProjectCreateInput.value = "";
|
|
771
|
-
addProjectCloneInput.value = "";
|
|
772
|
-
addProjectSuggestions.classList.add("hidden");
|
|
773
|
-
addProjectSuggestions.innerHTML = "";
|
|
774
|
-
addProjectError.classList.add("hidden");
|
|
775
|
-
addProjectCloneProgress.classList.add("hidden");
|
|
776
|
-
addProjectActiveIdx = -1;
|
|
777
|
-
addProjectPrefixValue = "";
|
|
778
|
-
addProjectPrefixEl.classList.add("hidden");
|
|
779
|
-
if (addProjectDebounce) { clearTimeout(addProjectDebounce); addProjectDebounce = null; }
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
function getFullPath(inputVal) {
|
|
783
|
-
return addProjectPrefixValue + inputVal;
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
function stripPrefix(fullPath) {
|
|
787
|
-
if (addProjectPrefixValue && fullPath.indexOf(addProjectPrefixValue) === 0) {
|
|
788
|
-
return fullPath.slice(addProjectPrefixValue.length);
|
|
789
|
-
}
|
|
790
|
-
return fullPath;
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
function requestBrowseDir(val) {
|
|
794
|
-
var ws = getWs();
|
|
795
|
-
if (!ws || ws.readyState !== 1) return;
|
|
796
|
-
ws.send(JSON.stringify({ type: "browse_dir", path: getFullPath(val) }));
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
export function handleBrowseDirResult(msg) {
|
|
800
|
-
addProjectSuggestions.innerHTML = "";
|
|
801
|
-
addProjectActiveIdx = -1;
|
|
802
|
-
if (msg.error) {
|
|
803
|
-
addProjectSuggestions.classList.add("hidden");
|
|
804
|
-
return;
|
|
805
|
-
}
|
|
806
|
-
var entries = msg.entries || [];
|
|
807
|
-
if (entries.length === 0) {
|
|
808
|
-
addProjectSuggestions.classList.add("hidden");
|
|
809
|
-
return;
|
|
810
|
-
}
|
|
811
|
-
for (var si = 0; si < entries.length; si++) {
|
|
812
|
-
var entry = entries[si];
|
|
813
|
-
var item = document.createElement("div");
|
|
814
|
-
item.className = "add-project-suggestion-item";
|
|
815
|
-
item.dataset.path = entry.path;
|
|
816
|
-
item.innerHTML = '<i data-lucide="folder"></i><span class="add-project-suggestion-name">' +
|
|
817
|
-
escapeHtml(entry.name) + '</span>';
|
|
818
|
-
item.addEventListener("click", function (e) {
|
|
819
|
-
var fullP = this.dataset.path + "/";
|
|
820
|
-
addProjectInput.value = stripPrefix(fullP);
|
|
821
|
-
addProjectInput.focus();
|
|
822
|
-
addProjectError.classList.add("hidden");
|
|
823
|
-
requestBrowseDir(addProjectInput.value);
|
|
824
|
-
});
|
|
825
|
-
addProjectSuggestions.appendChild(item);
|
|
826
|
-
}
|
|
827
|
-
addProjectSuggestions.classList.remove("hidden");
|
|
828
|
-
refreshIcons();
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
export function handleAddProjectResult(msg) {
|
|
832
|
-
addProjectCloneProgress.classList.add("hidden");
|
|
833
|
-
if (msg.ok) {
|
|
834
|
-
closeAddProjectModal();
|
|
835
|
-
if (msg.existing) {
|
|
836
|
-
showToast("Project already registered", "info");
|
|
837
|
-
} else {
|
|
838
|
-
var toastMsg = addProjectMode === "create" ? "Project created" : addProjectMode === "clone" ? "Project cloned" : "Project added";
|
|
839
|
-
showToast(toastMsg, "success");
|
|
840
|
-
}
|
|
841
|
-
if (msg.slug) switchProject(msg.slug);
|
|
842
|
-
} else {
|
|
843
|
-
addProjectError.textContent = msg.error || "Failed to add project";
|
|
844
|
-
addProjectError.classList.remove("hidden");
|
|
845
|
-
addProjectOk.disabled = false;
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
export function handleCloneProgress(msg) {
|
|
850
|
-
if (msg.status === "cloning") {
|
|
851
|
-
addProjectCloneProgress.classList.remove("hidden");
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
function setActiveIdx(idx) {
|
|
856
|
-
var items = addProjectSuggestions.querySelectorAll(".add-project-suggestion-item");
|
|
857
|
-
addProjectActiveIdx = idx;
|
|
858
|
-
for (var ai = 0; ai < items.length; ai++) {
|
|
859
|
-
if (ai === idx) {
|
|
860
|
-
items[ai].classList.add("active");
|
|
861
|
-
items[ai].scrollIntoView({ block: "nearest" });
|
|
862
|
-
} else {
|
|
863
|
-
items[ai].classList.remove("active");
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
function submitAddProject() {
|
|
869
|
-
addProjectError.classList.add("hidden");
|
|
870
|
-
addProjectOk.disabled = true;
|
|
871
|
-
|
|
872
|
-
if (addProjectMode === "existing") {
|
|
873
|
-
var val = getFullPath(addProjectInput.value).replace(/\/+$/, "");
|
|
874
|
-
if (!val) { addProjectOk.disabled = false; return; }
|
|
875
|
-
var ws = getWs();
|
|
876
|
-
if (ws && ws.readyState === 1) {
|
|
877
|
-
ws.send(JSON.stringify({ type: "add_project", path: val }));
|
|
878
|
-
}
|
|
879
|
-
} else if (addProjectMode === "create") {
|
|
880
|
-
var name = addProjectCreateInput.value.trim();
|
|
881
|
-
if (!name) { addProjectOk.disabled = false; return; }
|
|
882
|
-
var ws2 = getWs();
|
|
883
|
-
if (ws2 && ws2.readyState === 1) {
|
|
884
|
-
ws2.send(JSON.stringify({ type: "create_project", name: name }));
|
|
885
|
-
}
|
|
886
|
-
} else if (addProjectMode === "clone") {
|
|
887
|
-
var url = addProjectCloneInput.value.trim();
|
|
888
|
-
if (!url) { addProjectOk.disabled = false; return; }
|
|
889
|
-
var ws3 = getWs();
|
|
890
|
-
if (ws3 && ws3.readyState === 1) {
|
|
891
|
-
ws3.send(JSON.stringify({ type: "clone_project", url: url }));
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
}
|