clay-server 4.1.0-beta.8 → 4.1.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/lib/context-usage.js +47 -0
- package/lib/issues-mcp-server.js +1 -1
- package/lib/issues-service.js +3 -1
- package/lib/loop-registry-occurrence.js +1 -0
- package/lib/notes.js +20 -3
- package/lib/os-users.js +6 -0
- package/lib/project-connection.js +14 -3
- package/lib/project-file-path.js +13 -0
- package/lib/project-file-watch.js +19 -8
- package/lib/project-filesystem.js +10 -16
- package/lib/project-http.js +53 -48
- package/lib/project-logs-mcp-server.js +8 -8
- package/lib/project-logs-schema.js +1 -1
- package/lib/project-logs-service.js +46 -13
- package/lib/project-logs-store.js +17 -15
- package/lib/project-logs.js +70 -0
- package/lib/project-loop.js +1 -0
- package/lib/project-notifications.js +1 -1
- package/lib/project-pending-message-queue.js +71 -7
- package/lib/project-scheduled-messages.js +235 -52
- package/lib/project-scheduled-result-store.js +131 -0
- package/lib/project-scheduled-task-execution.js +35 -2
- package/lib/project-session-notes.js +11 -4
- package/lib/project-sessions.js +7 -0
- package/lib/project-user-message.js +72 -5
- package/lib/project.js +60 -5
- package/lib/public/app.js +27 -12
- package/lib/public/css/avatar-imprints.css +1 -1
- package/lib/public/css/command-palette.css +20 -0
- package/lib/public/css/git-panel.css +13 -12
- package/lib/public/css/git-placard.css +4 -4
- package/lib/public/css/input.css +0 -109
- package/lib/public/css/issues.css +78 -31
- package/lib/public/css/mobile-nav.css +7 -0
- package/lib/public/css/notifications-center.css +3 -3
- package/lib/public/css/pending-message-queue.css +3 -0
- package/lib/public/css/project-logs.css +15 -0
- package/lib/public/css/sidebar.css +7 -0
- package/lib/public/css/sticky-notes.css +29 -0
- package/lib/public/modules/app-connection.js +9 -1
- package/lib/public/modules/app-favicon.js +10 -0
- package/lib/public/modules/app-messages.js +49 -37
- package/lib/public/modules/app-notifications.js +2 -0
- package/lib/public/modules/app-panels.js +77 -23
- package/lib/public/modules/app-projects.js +3 -0
- package/lib/public/modules/app-rate-limit.js +148 -243
- package/lib/public/modules/avatar-imprint.js +25 -70
- package/lib/public/modules/avatar.js +12 -4
- package/lib/public/modules/chat-render-runtime.js +20 -2
- package/lib/public/modules/clay-issue-links.js +23 -2
- package/lib/public/modules/clay-log-links.js +11 -1
- package/lib/public/modules/context-view-preference.js +143 -0
- package/lib/public/modules/default-vendor.js +116 -0
- package/lib/public/modules/filebrowser-tabs.js +1 -0
- package/lib/public/modules/filebrowser.js +45 -18
- package/lib/public/modules/input.js +81 -20
- package/lib/public/modules/issues-render.js +36 -10
- package/lib/public/modules/issues.js +95 -13
- package/lib/public/modules/markdown.js +3 -1
- package/lib/public/modules/pane-bridge.js +14 -8
- package/lib/public/modules/pane-issue-bridge.js +27 -0
- package/lib/public/modules/pending-message-queue.js +43 -1
- package/lib/public/modules/permission-hints.js +13 -0
- package/lib/public/modules/profile.js +9 -9
- package/lib/public/modules/project-activation.js +49 -0
- package/lib/public/modules/project-logs-render.js +13 -3
- package/lib/public/modules/project-logs.js +45 -15
- package/lib/public/modules/right-workbench.js +44 -0
- package/lib/public/modules/scheduled-message-state.js +12 -36
- package/lib/public/modules/scheduled-result-client.js +33 -0
- package/lib/public/modules/scheduled-result-display.js +50 -0
- package/lib/public/modules/scheduled-result-notification.js +31 -0
- package/lib/public/modules/scheduled-task-presentation.js +15 -0
- package/lib/public/modules/scheduled-tasks.js +9 -21
- package/lib/public/modules/sidebar-mobile.js +51 -3
- package/lib/public/modules/sidebar-sessions.js +65 -5
- package/lib/public/modules/split-session-boundary.js +28 -0
- package/lib/public/modules/split-view.js +42 -7
- package/lib/public/modules/sticky-notes-browser.js +130 -18
- package/lib/public/modules/sticky-notes.js +2 -3
- package/lib/public/modules/terminal.js +4 -4
- package/lib/public/modules/thinking-lifecycle.js +4 -1
- package/lib/public/modules/tools.js +5 -1
- package/lib/scheduled-run-state.js +10 -2
- package/lib/scheduler.js +1 -0
- package/lib/sdk-bridge.js +97 -61
- package/lib/sdk-message-processor.js +44 -13
- package/lib/sdk-skill-discovery.js +6 -28
- package/lib/sdk-turn-queue.js +14 -0
- package/lib/server-context-view.js +53 -0
- package/lib/server-default-vendor.js +60 -0
- package/lib/server.js +23 -6
- package/lib/session-notes-mcp-server.js +3 -5
- package/lib/session-pair-factory.js +2 -2
- package/lib/session-pair-mcp-server.js +5 -4
- package/lib/session-title-generator.js +89 -0
- package/lib/session-title-policy.js +8 -2
- package/lib/sessions.js +26 -1
- package/lib/user-presence.js +6 -0
- package/lib/users-context-view-preferences.js +65 -0
- package/lib/users-default-vendor-preferences.js +80 -0
- package/lib/users.js +12 -0
- package/lib/ws-schema.js +11 -0
- package/lib/yoke/acp-agent-profiles.js +15 -2
- package/lib/yoke/adapters/acp.js +3 -2
- package/lib/yoke/adapters/antigravity.js +2 -2
- package/lib/yoke/adapters/claude-worker.js +11 -12
- package/lib/yoke/adapters/claude.js +75 -22
- package/lib/yoke/adapters/codex.js +216 -29
- package/lib/yoke/adapters/kiro.js +6 -5
- package/lib/yoke/claude-context-usage.js +57 -0
- package/lib/yoke/claude-message-correlation.js +31 -0
- package/lib/yoke/claude-model-switch.js +15 -0
- package/lib/yoke/index.js +5 -1
- package/lib/yoke/mcp-bridge-server.js +18 -5
- package/lib/yoke/session-skill-catalog.js +45 -0
- package/lib/yoke/skill-discovery.js +60 -20
- package/lib/yoke/vendor-registry.js +1 -1
- package/package.json +5 -7
|
@@ -145,8 +145,26 @@ export function addToMessages(element) {
|
|
|
145
145
|
var messagesEl = getMessagesEl();
|
|
146
146
|
if (prependAnchor) messagesEl.insertBefore(element, prependAnchor);
|
|
147
147
|
else messagesEl.appendChild(element);
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
keepActiveThinkingAtTail();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Thinking is a single accumulating record for the active turn. Other live
|
|
152
|
+
// transcript entries may arrive between reasoning segments, so keep only the
|
|
153
|
+
// currently active record after the tail activity indicator.
|
|
154
|
+
export function keepActiveThinkingAtTail() {
|
|
155
|
+
if (prependAnchor || store.get('replayingHistory')) return;
|
|
156
|
+
var thinkingState = store.get('thinkingState');
|
|
157
|
+
var thinkingEl = thinkingState && thinkingState.active && thinkingState.el;
|
|
158
|
+
var messagesEl = getMessagesEl();
|
|
159
|
+
if (!thinkingEl || !messagesEl || thinkingEl.parentNode !== messagesEl) return;
|
|
160
|
+
if (activityEl && activityEl.parentNode === messagesEl) {
|
|
161
|
+
if (activityEl.nextSibling !== thinkingEl || messagesEl.lastElementChild !== thinkingEl) {
|
|
162
|
+
messagesEl.appendChild(activityEl);
|
|
163
|
+
messagesEl.appendChild(thinkingEl);
|
|
164
|
+
}
|
|
165
|
+
} else if (messagesEl.lastElementChild !== thinkingEl) {
|
|
166
|
+
messagesEl.appendChild(thinkingEl);
|
|
167
|
+
}
|
|
150
168
|
}
|
|
151
169
|
|
|
152
170
|
export function scrollToBottom() {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { store } from './store.js';
|
|
2
2
|
import { getWs } from './ws-ref.js';
|
|
3
|
+
import { forwardPaneIssueReference } from './pane-bridge.js';
|
|
3
4
|
function accountKey(state) { return state.isMultiUserMode ? 'user:' + String(state.myUserId || '') : 'single'; }
|
|
4
5
|
function requestContext(state) { return { accountKey: accountKey(state), projectSlug: state.currentSlug || null, epoch: state.issuesEpoch || 0 }; }
|
|
5
6
|
function sameContext(request, state) {
|
|
@@ -42,12 +43,17 @@ function createIssueLink(ref, labelText) {
|
|
|
42
43
|
button.appendChild(meta);
|
|
43
44
|
}
|
|
44
45
|
var cache = store.get('issuesCache') || {};
|
|
45
|
-
if (cache[ref])
|
|
46
|
+
if (cache[ref]) updateIssueLink(button, cache[ref]);
|
|
46
47
|
setTimeout(function () { resolve(ref); }, 0);
|
|
47
48
|
return button;
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
export function enhanceClayIssueLinks(root) {
|
|
52
|
+
root.querySelectorAll('a').forEach(function (anchor) {
|
|
53
|
+
var ref = anchor.getAttribute('data-clay-record-ref') || anchor.getAttribute('href');
|
|
54
|
+
if (anchor.closest('pre, code, button') || !isExactClayIssueReference(ref)) return;
|
|
55
|
+
anchor.replaceWith(createIssueLink(ref.trim(), anchor.textContent.trim()));
|
|
56
|
+
});
|
|
51
57
|
var codeNodes = root.querySelectorAll("code");
|
|
52
58
|
for (var codeIndex = 0; codeIndex < codeNodes.length; codeIndex++) {
|
|
53
59
|
var code = codeNodes[codeIndex];
|
|
@@ -80,6 +86,20 @@ export function enhanceClayIssueLinks(root) {
|
|
|
80
86
|
}
|
|
81
87
|
}
|
|
82
88
|
|
|
89
|
+
export function updateIssueLink(button, target) {
|
|
90
|
+
var status = target.status || 'open';
|
|
91
|
+
var title = target.title || 'Issue';
|
|
92
|
+
button.replaceChildren();
|
|
93
|
+
var label = document.createElement('span');
|
|
94
|
+
label.textContent = 'Issue';
|
|
95
|
+
var meta = document.createElement('small');
|
|
96
|
+
meta.textContent = title;
|
|
97
|
+
button.append(label, meta);
|
|
98
|
+
button.dataset.status = status;
|
|
99
|
+
button.title = title + ' · ' + status.replace(/_/g, ' ');
|
|
100
|
+
button.setAttribute('aria-label', 'Open Project Issue: ' + button.title);
|
|
101
|
+
}
|
|
102
|
+
|
|
83
103
|
function resolve(ref) {
|
|
84
104
|
var ws = getWs();
|
|
85
105
|
var requests = store.get('issueLinkRequests') || {};
|
|
@@ -101,7 +121,7 @@ export function handleIssueReference(msg) {
|
|
|
101
121
|
}
|
|
102
122
|
document.querySelectorAll('[data-issue-ref]').forEach(function (button) {
|
|
103
123
|
if (button.dataset.issueRef !== msg.ref) return;
|
|
104
|
-
if (msg.target)
|
|
124
|
+
if (msg.target) updateIssueLink(button, msg.target);
|
|
105
125
|
else button.title = msg.error || 'Issue unavailable';
|
|
106
126
|
});
|
|
107
127
|
if (store.get('issueLinkOpenRef') === msg.ref) {
|
|
@@ -111,6 +131,7 @@ export function handleIssueReference(msg) {
|
|
|
111
131
|
return true;
|
|
112
132
|
}
|
|
113
133
|
function navigate(target) {
|
|
134
|
+
if (forwardPaneIssueReference(target.ref, target.projectSlug)) return;
|
|
114
135
|
if (target.projectSlug !== store.get('currentSlug')) { window.location.assign('/p/' + encodeURIComponent(target.projectSlug) + '/?issue=' + encodeURIComponent(target.ref)); return; }
|
|
115
136
|
import('./issues.js').then(function (module) { module.openIssues(target.ref); });
|
|
116
137
|
}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import { enhanceClayIssueLinks } from './clay-issue-links.js';
|
|
1
|
+
import { enhanceClayIssueLinks, isExactClayIssueReference } from './clay-issue-links.js';
|
|
2
|
+
|
|
3
|
+
export function renderClayRecordLink(href, text) {
|
|
4
|
+
if (!isExactClayLogReference(href) && !isExactClayIssueReference(href)) return null;
|
|
5
|
+
return '<a href="#" data-clay-record-ref="' + href.trim() + '">' + text + '</a>';
|
|
6
|
+
}
|
|
2
7
|
export function parseClayLogReferences(text) {
|
|
3
8
|
var pattern = /\[clayos\/(log:[A-Za-z0-9_-]{24})(?:\s+[\u2014-]\s+([^\]\n]{1,80}))?\]|(^|[^A-Za-z0-9_/:])(log:[A-Za-z0-9_-]{24})(?![A-Za-z0-9_-])/g;
|
|
4
9
|
var results = [];
|
|
@@ -39,6 +44,11 @@ function createLogLink(ref, labelText) {
|
|
|
39
44
|
|
|
40
45
|
export function enhanceClayLogLinks(root) {
|
|
41
46
|
enhanceClayIssueLinks(root);
|
|
47
|
+
root.querySelectorAll('a').forEach(function (anchor) {
|
|
48
|
+
var ref = anchor.getAttribute('data-clay-record-ref') || anchor.getAttribute('href');
|
|
49
|
+
if (anchor.closest('pre, code, button') || !isExactClayLogReference(ref)) return;
|
|
50
|
+
anchor.replaceWith(createLogLink(ref.trim(), anchor.textContent.trim()));
|
|
51
|
+
});
|
|
42
52
|
var codeNodes = root.querySelectorAll("code");
|
|
43
53
|
for (var codeIndex = 0; codeIndex < codeNodes.length; codeIndex++) {
|
|
44
54
|
var code = codeNodes[codeIndex];
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { getWs } from './ws-ref.js';
|
|
3
|
+
|
|
4
|
+
var MODES = ["off", "mini", "panel"];
|
|
5
|
+
var sequence = 0;
|
|
6
|
+
|
|
7
|
+
function validMode(mode) { return MODES.indexOf(mode) !== -1; }
|
|
8
|
+
function nextRequestId(prefix) { sequence += 1; return prefix + Date.now() + "-" + sequence; }
|
|
9
|
+
function accountId() { return store.get("myUserId") || "default"; }
|
|
10
|
+
function initialState() {
|
|
11
|
+
return { mode: "off", canonicalMode: "off", preferencePresent: false, loading: false, saving: false, requestId: null, saveRequestId: null, pendingSaves: [], accountId: null, serverEpoch: null, rejectedEpoch: null, canonicalRevision: 0, error: "" };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function send(message) {
|
|
15
|
+
var ws = getWs();
|
|
16
|
+
if (!ws || ws.readyState !== 1) return false;
|
|
17
|
+
ws.send(JSON.stringify(message));
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function getContextView() {
|
|
22
|
+
var state = store.get("contextViewPreferenceState") || initialState();
|
|
23
|
+
return validMode(state.mode) ? state.mode : "off";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function getEffectiveContextView() {
|
|
27
|
+
if (store.get("paneMode") !== true) return getContextView();
|
|
28
|
+
var override = store.get("contextViewOverride");
|
|
29
|
+
return override === null || override === undefined ? getContextView() : (validMode(override) ? override : getContextView());
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function beginContextViewConnection() {
|
|
33
|
+
var state = store.get("contextViewPreferenceState") || initialState();
|
|
34
|
+
store.set({ contextViewPreferenceState: Object.assign({}, state, {
|
|
35
|
+
mode: validMode(state.canonicalMode) ? state.canonicalMode : "off",
|
|
36
|
+
loading: false,
|
|
37
|
+
saving: false,
|
|
38
|
+
requestId: null,
|
|
39
|
+
saveRequestId: null,
|
|
40
|
+
pendingSaves: [],
|
|
41
|
+
rejectedEpoch: state.serverEpoch || null,
|
|
42
|
+
serverEpoch: null,
|
|
43
|
+
canonicalRevision: 0,
|
|
44
|
+
error: "",
|
|
45
|
+
}) });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function requestContextView() {
|
|
49
|
+
var id = nextRequestId("context-view-");
|
|
50
|
+
var state = store.get("contextViewPreferenceState") || initialState();
|
|
51
|
+
store.set({ contextViewPreferenceState: Object.assign({}, state, { loading: true, requestId: id, error: "" }) });
|
|
52
|
+
if (!send({ type: "context_view_get", requestId: id })) {
|
|
53
|
+
store.set({ contextViewPreferenceState: Object.assign({}, store.get("contextViewPreferenceState") || initialState(), { loading: false, requestId: null, error: "Clay is offline. Reconnect and try again." }) });
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function setContextView(mode) {
|
|
60
|
+
if (!validMode(mode)) return false;
|
|
61
|
+
var id = nextRequestId("context-view-save-");
|
|
62
|
+
var state = store.get("contextViewPreferenceState") || initialState();
|
|
63
|
+
var pendingSaves = (state.pendingSaves || []).concat([{ requestId: id, mode: mode }]);
|
|
64
|
+
store.set({ contextViewPreferenceState: Object.assign({}, state, { mode: mode, saving: true, saveRequestId: id, pendingSaves: pendingSaves, error: "" }) });
|
|
65
|
+
if (!send({ type: "context_view_set", requestId: id, mode: mode })) {
|
|
66
|
+
var reverted = store.get("contextViewPreferenceState") || initialState();
|
|
67
|
+
pendingSaves = (reverted.pendingSaves || []).filter(function (item) { return item.requestId !== id; });
|
|
68
|
+
var pendingMode = pendingSaves.length ? pendingSaves[pendingSaves.length - 1].mode : (reverted.canonicalMode || "off");
|
|
69
|
+
store.set({ contextViewPreferenceState: Object.assign({}, reverted, { mode: pendingMode, saving: pendingSaves.length > 0, saveRequestId: pendingSaves.length ? pendingSaves[pendingSaves.length - 1].requestId : null, pendingSaves: pendingSaves, error: "Clay is offline. Reconnect and try again." }) });
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function handleContextViewMessage(msg) {
|
|
76
|
+
if (!msg || msg.type !== "context_view_state") return false;
|
|
77
|
+
var state = store.get("contextViewPreferenceState") || initialState();
|
|
78
|
+
var currentAccount = accountId();
|
|
79
|
+
var isGetReply = !!msg.requestId && msg.requestId === state.requestId;
|
|
80
|
+
var pendingSaves = state.pendingSaves || [];
|
|
81
|
+
var saveIndex = -1;
|
|
82
|
+
for (var i = 0; i < pendingSaves.length; i++) if (pendingSaves[i].requestId === msg.requestId) saveIndex = i;
|
|
83
|
+
var isSaveReply = !!msg.requestId && saveIndex !== -1;
|
|
84
|
+
var isOlderSaveRevision = isSaveReply && typeof msg.canonicalRevision === "number" && msg.canonicalRevision < (state.canonicalRevision || 0);
|
|
85
|
+
var isCorrelatedAccountFailure = (isGetReply || isSaveReply) && msg.accountId === null && msg.accountAvailable === false;
|
|
86
|
+
if ((!isCorrelatedAccountFailure && msg.accountId !== currentAccount) || (msg.accountId === null && !isCorrelatedAccountFailure)) return true;
|
|
87
|
+
if (msg.serverEpoch && state.serverEpoch && msg.serverEpoch !== state.serverEpoch && (!msg.requestId || (!isGetReply && !isSaveReply))) return true;
|
|
88
|
+
if (msg.serverEpoch && state.rejectedEpoch && msg.serverEpoch === state.rejectedEpoch && (!isGetReply && !isSaveReply)) return true;
|
|
89
|
+
if (msg.canonicalRevision !== undefined && msg.canonicalRevision < (state.canonicalRevision || 0) && msg.serverEpoch === state.serverEpoch && !isSaveReply) return true;
|
|
90
|
+
if (msg.requestId && !isGetReply && !isSaveReply) return true;
|
|
91
|
+
if (msg.requestId && !isSaveReply && msg.ready === false && state.saving) return true;
|
|
92
|
+
var next = Object.assign({}, state, {
|
|
93
|
+
accountId: msg.accountId || currentAccount,
|
|
94
|
+
serverEpoch: msg.serverEpoch || state.serverEpoch || null,
|
|
95
|
+
rejectedEpoch: isGetReply || isSaveReply ? null : state.rejectedEpoch || null,
|
|
96
|
+
canonicalRevision: isOlderSaveRevision ? (state.canonicalRevision || 0) : (typeof msg.canonicalRevision === "number" ? msg.canonicalRevision : state.canonicalRevision || 0),
|
|
97
|
+
loading: isGetReply ? false : state.loading,
|
|
98
|
+
saving: state.saving,
|
|
99
|
+
requestId: isGetReply ? null : state.requestId,
|
|
100
|
+
saveRequestId: state.saveRequestId,
|
|
101
|
+
error: msg.error || "",
|
|
102
|
+
});
|
|
103
|
+
if (Object.prototype.hasOwnProperty.call(msg, "mode") && validMode(msg.mode) && msg.ready !== false && !isCorrelatedAccountFailure) {
|
|
104
|
+
if (isSaveReply) {
|
|
105
|
+
if (!isOlderSaveRevision && msg.ready !== false) {
|
|
106
|
+
pendingSaves = pendingSaves.slice(saveIndex + 1);
|
|
107
|
+
} else {
|
|
108
|
+
pendingSaves = pendingSaves.filter(function (item) { return item.requestId !== msg.requestId; });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (!isOlderSaveRevision) {
|
|
112
|
+
next.canonicalMode = msg.mode;
|
|
113
|
+
next.preferencePresent = msg.preferencePresent === true;
|
|
114
|
+
}
|
|
115
|
+
if (pendingSaves.length) {
|
|
116
|
+
next.mode = pendingSaves[pendingSaves.length - 1].mode;
|
|
117
|
+
next.saving = true;
|
|
118
|
+
next.saveRequestId = pendingSaves[pendingSaves.length - 1].requestId;
|
|
119
|
+
} else {
|
|
120
|
+
next.mode = next.canonicalMode;
|
|
121
|
+
next.saving = false;
|
|
122
|
+
next.saveRequestId = null;
|
|
123
|
+
}
|
|
124
|
+
next.pendingSaves = pendingSaves;
|
|
125
|
+
} else if (isSaveReply && (msg.ready === false || isCorrelatedAccountFailure)) {
|
|
126
|
+
pendingSaves = pendingSaves.filter(function (item) { return item.requestId !== msg.requestId; });
|
|
127
|
+
next.pendingSaves = pendingSaves;
|
|
128
|
+
next.mode = pendingSaves.length ? pendingSaves[pendingSaves.length - 1].mode : (state.canonicalMode || "off");
|
|
129
|
+
next.saving = pendingSaves.length > 0;
|
|
130
|
+
next.saveRequestId = pendingSaves.length ? pendingSaves[pendingSaves.length - 1].requestId : null;
|
|
131
|
+
}
|
|
132
|
+
store.set({ contextViewPreferenceState: next });
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
store.subscribe(function (state, previous) {
|
|
137
|
+
if (state.myUserId !== previous.myUserId || state.currentSlug !== previous.currentSlug) {
|
|
138
|
+
store.set({ contextViewPreferenceState: Object.assign({}, initialState(), { accountId: accountId() }), contextViewOverride: null });
|
|
139
|
+
if (state.connected) requestContextView();
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
export { validMode };
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { getWs } from './ws-ref.js';
|
|
3
|
+
import { firstInstalledVendor } from './vendor-priority.js';
|
|
4
|
+
|
|
5
|
+
function send(message) {
|
|
6
|
+
var ws = getWs();
|
|
7
|
+
if (!ws || ws.readyState !== 1) return false;
|
|
8
|
+
ws.send(JSON.stringify(message));
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
var sequence = 0;
|
|
13
|
+
|
|
14
|
+
function nextRequestId(prefix) {
|
|
15
|
+
sequence += 1;
|
|
16
|
+
return prefix + Date.now() + "-" + sequence;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function emptyState(accountId, projectSlug) {
|
|
20
|
+
return { loading: false, saving: false, getRequestId: null, saveRequestId: null, preference: null, preferencePresent: false, installedVendors: [], accountId: accountId || null, projectSlug: projectSlug || null, serverEpoch: null, canonicalRevision: 0, error: "" };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function requestDefaultVendor() {
|
|
24
|
+
var id = nextRequestId("default-vendor-");
|
|
25
|
+
var state = store.get("defaultVendorState") || {};
|
|
26
|
+
store.set({ defaultVendorState: Object.assign({}, state, { loading: true, getRequestId: id, error: "" }) });
|
|
27
|
+
if (!send({ type: "default_vendor_get", requestId: id })) {
|
|
28
|
+
store.set({ defaultVendorState: Object.assign({}, store.get("defaultVendorState") || {}, { loading: false, getRequestId: null, error: "Clay is offline. Reconnect and try again." }) });
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function beginDefaultVendorConnection() {
|
|
35
|
+
var state = store.get("defaultVendorState") || {};
|
|
36
|
+
store.set({ defaultVendorState: Object.assign({}, state, {
|
|
37
|
+
loading: false,
|
|
38
|
+
saving: false,
|
|
39
|
+
getRequestId: null,
|
|
40
|
+
saveRequestId: null,
|
|
41
|
+
preference: null,
|
|
42
|
+
preferencePresent: false,
|
|
43
|
+
installedVendors: [],
|
|
44
|
+
accountId: store.get("myUserId") || "default",
|
|
45
|
+
projectSlug: store.get("currentSlug") || null,
|
|
46
|
+
serverEpoch: null,
|
|
47
|
+
canonicalRevision: 0,
|
|
48
|
+
error: "",
|
|
49
|
+
}) });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function saveDefaultVendor(vendor) {
|
|
53
|
+
var state = store.get("defaultVendorState") || {};
|
|
54
|
+
if (vendor !== "" && (state.installedVendors || []).indexOf(vendor) === -1) return false;
|
|
55
|
+
var id = nextRequestId("default-vendor-save-");
|
|
56
|
+
store.set({ defaultVendorState: Object.assign({}, state, { saving: true, saveRequestId: id, error: "" }) });
|
|
57
|
+
if (!send({ type: "default_vendor_set", requestId: id, vendor: vendor })) {
|
|
58
|
+
store.set({ defaultVendorState: Object.assign({}, store.get("defaultVendorState") || {}, { saving: false, saveRequestId: null, error: "Clay is offline. Reconnect and try again." }) });
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function handleDefaultVendorMessage(msg) {
|
|
65
|
+
if (!msg || msg.type !== "default_vendor_state") return false;
|
|
66
|
+
var state = store.get("defaultVendorState") || {};
|
|
67
|
+
var accountId = store.get("myUserId") || "default";
|
|
68
|
+
var projectSlug = store.get("currentSlug") || null;
|
|
69
|
+
var isGetReply = !!msg.requestId && msg.requestId === state.getRequestId;
|
|
70
|
+
var isSaveReply = !!msg.requestId && msg.requestId === state.saveRequestId;
|
|
71
|
+
var isCorrelatedAccountFailure = (isGetReply || isSaveReply) && msg.accountId === null && msg.accountAvailable === false;
|
|
72
|
+
if ((!isCorrelatedAccountFailure && msg.accountId !== accountId) || (msg.accountId === null && !isCorrelatedAccountFailure)) return true;
|
|
73
|
+
if (Object.prototype.hasOwnProperty.call(msg, "projectSlug") && msg.projectSlug !== projectSlug) return true;
|
|
74
|
+
if (msg.serverEpoch && state.serverEpoch && msg.serverEpoch !== state.serverEpoch && (!msg.requestId || (msg.requestId !== state.getRequestId && msg.requestId !== state.saveRequestId))) return true;
|
|
75
|
+
if (msg.canonicalRevision !== undefined && msg.canonicalRevision < (state.canonicalRevision || 0) && msg.serverEpoch === state.serverEpoch) return true;
|
|
76
|
+
if (msg.requestId && !isGetReply && !isSaveReply) return true;
|
|
77
|
+
if (msg.requestId && !isSaveReply && msg.ready === false && state.saving) return true;
|
|
78
|
+
var next = Object.assign({}, state, {
|
|
79
|
+
accountId: msg.accountId || accountId,
|
|
80
|
+
projectSlug: projectSlug,
|
|
81
|
+
serverEpoch: msg.serverEpoch || state.serverEpoch || null,
|
|
82
|
+
canonicalRevision: typeof msg.canonicalRevision === "number" ? msg.canonicalRevision : state.canonicalRevision || 0,
|
|
83
|
+
installedVendors: Array.isArray(msg.installedVendors) ? msg.installedVendors : state.installedVendors || [],
|
|
84
|
+
loading: isGetReply ? false : state.loading,
|
|
85
|
+
saving: isSaveReply ? false : state.saving,
|
|
86
|
+
getRequestId: isGetReply ? null : state.getRequestId,
|
|
87
|
+
saveRequestId: isSaveReply ? null : state.saveRequestId,
|
|
88
|
+
error: msg.error || ""
|
|
89
|
+
});
|
|
90
|
+
if (Object.prototype.hasOwnProperty.call(msg, "preference")) {
|
|
91
|
+
next.preference = msg.preference || null;
|
|
92
|
+
next.preferencePresent = msg.preferencePresent === true;
|
|
93
|
+
}
|
|
94
|
+
store.set({ defaultVendorState: next });
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
store.subscribe(function (state, previous) {
|
|
99
|
+
if (state.myUserId !== previous.myUserId || state.currentSlug !== previous.currentSlug) {
|
|
100
|
+
var accountId = state.myUserId || "default";
|
|
101
|
+
store.set({ defaultVendorState: emptyState(accountId, state.currentSlug || null) });
|
|
102
|
+
if (state.connected) requestDefaultVendor();
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
export function resolvePreferredVendor(installedVendors) {
|
|
107
|
+
var installed = Array.isArray(installedVendors) ? installedVendors : [];
|
|
108
|
+
var state = store.get("defaultVendorState") || {};
|
|
109
|
+
if (state.preference && installed.indexOf(state.preference) !== -1) return state.preference;
|
|
110
|
+
return firstInstalledVendor(installed);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function defaultVendorUnavailable(installedVendors) {
|
|
114
|
+
var state = store.get("defaultVendorState") || {};
|
|
115
|
+
return !!state.preference && (installedVendors || []).indexOf(state.preference) === -1;
|
|
116
|
+
}
|
|
@@ -101,4 +101,5 @@ export function closeFileViewerTab(path) {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
export function focusedFileViewerTab() { return focusedPath; }
|
|
104
|
+
export function focusedFileViewerTabData() { return focusedPath && tabs.has(focusedPath) ? tabs.get(focusedPath) : null; }
|
|
104
105
|
export function clearFileViewerTabs() { tabs.clear(); focusedPath = null; previewPath = null; render(); }
|
|
@@ -2,15 +2,14 @@ import { iconHtml, refreshIcons } from './icons.js';
|
|
|
2
2
|
import { escapeHtml, copyToClipboard } from './utils.js';
|
|
3
3
|
import { renderMarkdown, highlightCodeBlocks, renderMermaidBlocks, exportMarkdownAsPdf } from './markdown.js';
|
|
4
4
|
import { closeSidebar } from './sidebar.js';
|
|
5
|
-
import {
|
|
5
|
+
import { claimRightWorkbench, registerRightWorkbench, releaseRightWorkbench, isRightWorkbenchCurrent } from './right-workbench.js';
|
|
6
6
|
import { renderUnifiedDiff, renderSplitDiff } from './diff.js';
|
|
7
7
|
import { initFileIcons, getFileIconSvg, getFolderIconSvg } from './fileicons.js';
|
|
8
8
|
import { copyMarkdownFormatting } from './rich-clipboard.js';
|
|
9
9
|
import { animateMarkdownChange, beginMarkdownPresentation, cancelMarkdownFollow, isFollowingMarkdown } from './markdown-live-edit.js';
|
|
10
10
|
import { store } from './store.js';
|
|
11
11
|
import { enterMarkdownSlides, exitMarkdownSlides, handleMarkdownSlideKey, syncMarkdownSlidesButton, toggleMarkdownSlideLevelMenu } from './markdown-slides.js';
|
|
12
|
-
import { initFileViewerTabs, openFileViewerTab, previewFileViewerTab, updateFileViewerTab, closeFileViewerTab, focusedFileViewerTab, clearFileViewerTabs } from './filebrowser-tabs.js';
|
|
13
|
-
import { closeIssues } from './issues.js';
|
|
12
|
+
import { initFileViewerTabs, openFileViewerTab, previewFileViewerTab, updateFileViewerTab, closeFileViewerTab, focusedFileViewerTab, focusedFileViewerTabData, clearFileViewerTabs } from './filebrowser-tabs.js';
|
|
14
13
|
import { initFileBrowserContextMenu, downloadProjectFile } from './filebrowser-context-menu.js';
|
|
15
14
|
import { registerClayFileLinkOpener } from './clay-file-links.js';
|
|
16
15
|
|
|
@@ -41,10 +40,13 @@ export function initFileBrowser(_ctx) {
|
|
|
41
40
|
if (mainPanels && ctx.fileViewerEl) mainPanels.appendChild(ctx.fileViewerEl);
|
|
42
41
|
initFileViewerTabs({
|
|
43
42
|
onFocus: function(path) {
|
|
43
|
+
claimRightWorkbench("file-viewer");
|
|
44
|
+
ctx.fileViewerEl.classList.remove("hidden");
|
|
44
45
|
if (path !== currentFilePath) requestFileContent(path);
|
|
45
46
|
},
|
|
46
47
|
onEmpty: function() { teardownFileViewer(); },
|
|
47
48
|
});
|
|
49
|
+
registerRightWorkbench("file-viewer", teardownFileViewer);
|
|
48
50
|
|
|
49
51
|
// Load material file icons in background
|
|
50
52
|
initFileIcons().then(function () {
|
|
@@ -149,7 +151,7 @@ export function initFileBrowser(_ctx) {
|
|
|
149
151
|
|
|
150
152
|
// Close button
|
|
151
153
|
document.getElementById("file-viewer-close").addEventListener("click", function () {
|
|
152
|
-
|
|
154
|
+
closeFileViewer();
|
|
153
155
|
});
|
|
154
156
|
|
|
155
157
|
// Full-viewport presentation toggle
|
|
@@ -395,6 +397,7 @@ function kbCollapseOrAscend() {
|
|
|
395
397
|
function kbActivate() {
|
|
396
398
|
if (!_kbFocused) return;
|
|
397
399
|
if (!isDirRow(_kbFocused) && _kbFocused.dataset.path) {
|
|
400
|
+
claimRightWorkbench("file-viewer");
|
|
398
401
|
openFileViewerTab(_kbFocused.dataset.path);
|
|
399
402
|
}
|
|
400
403
|
_kbFocused.click();
|
|
@@ -477,10 +480,7 @@ function ensureRenderedMarkdown() {
|
|
|
477
480
|
}
|
|
478
481
|
|
|
479
482
|
export function closeFileViewer() {
|
|
480
|
-
|
|
481
|
-
closeFileViewerTab(focusedFileViewerTab());
|
|
482
|
-
return;
|
|
483
|
-
}
|
|
483
|
+
releaseRightWorkbench("file-viewer");
|
|
484
484
|
teardownFileViewer();
|
|
485
485
|
}
|
|
486
486
|
|
|
@@ -512,6 +512,7 @@ export function setFileViewerFullscreen(enabled) {
|
|
|
512
512
|
}
|
|
513
513
|
|
|
514
514
|
export function resetFileBrowser() {
|
|
515
|
+
releaseRightWorkbench("file-viewer");
|
|
515
516
|
clearFileViewerTabs();
|
|
516
517
|
teardownFileViewer();
|
|
517
518
|
// Clear all cached state
|
|
@@ -552,12 +553,13 @@ export function openFile(filePath, opts) {
|
|
|
552
553
|
if (!state.connected) return false;
|
|
553
554
|
if (opts && opts.projectSlug && opts.projectSlug !== state.currentSlug) return false;
|
|
554
555
|
if (opts && opts.sessionId && String(opts.sessionId) !== String(state.activeSessionId)) return false;
|
|
555
|
-
|
|
556
|
+
var workbenchRevision = claimRightWorkbench("file-viewer");
|
|
556
557
|
if (followedFileChanged(filePath) || (opts && opts.diff && isFollowingMarkdown(filePath))) {
|
|
557
558
|
cancelMarkdownFollow();
|
|
558
559
|
}
|
|
559
560
|
pendingRenderedOpen = !!(opts && opts.rendered);
|
|
560
561
|
store.set({ pendingFileNavigation: opts && opts.line ? { path: filePath, line: opts.line, column: opts.column || null, requestId: null } : null });
|
|
562
|
+
store.set({ fileViewerOpenRevision: workbenchRevision });
|
|
561
563
|
openFileViewerTab(filePath);
|
|
562
564
|
if (opts && opts.diff) {
|
|
563
565
|
pendingOpenMode = { type: "diff", oldStr: opts.diff.oldStr, newStr: opts.diff.newStr };
|
|
@@ -567,9 +569,28 @@ export function openFile(filePath, opts) {
|
|
|
567
569
|
requestFileContent(filePath);
|
|
568
570
|
}
|
|
569
571
|
|
|
572
|
+
export function reopenFileViewer() {
|
|
573
|
+
var workbenchRevision = claimRightWorkbench("file-viewer");
|
|
574
|
+
store.set({ fileViewerOpenRevision: workbenchRevision });
|
|
575
|
+
if (!focusedFileViewerTab()) return false;
|
|
576
|
+
ctx.fileViewerEl.classList.remove("hidden");
|
|
577
|
+
var tab = focusedFileViewerTabData();
|
|
578
|
+
if (currentFilePath === focusedFileViewerTab() && currentContent != null) {
|
|
579
|
+
sendWatch(currentFilePath);
|
|
580
|
+
return true;
|
|
581
|
+
}
|
|
582
|
+
if (tab && tab.content != null) {
|
|
583
|
+
showFileContent({ path: focusedFileViewerTab(), content: tab.content, size: tab.content.length });
|
|
584
|
+
return true;
|
|
585
|
+
}
|
|
586
|
+
requestFileContent(focusedFileViewerTab());
|
|
587
|
+
return true;
|
|
588
|
+
}
|
|
589
|
+
|
|
570
590
|
export function openWorkingTreeDiff(diff) {
|
|
571
591
|
if (!diff || !diff.path) return;
|
|
572
|
-
|
|
592
|
+
var workbenchRevision = claimRightWorkbench("file-viewer");
|
|
593
|
+
store.set({ fileViewerOpenRevision: workbenchRevision });
|
|
573
594
|
openFileViewerTab(diff.path);
|
|
574
595
|
pendingRenderedOpen = false;
|
|
575
596
|
pendingOpenMode = diff.binary ? null : {
|
|
@@ -588,6 +609,8 @@ export function openWorkingTreeDiff(diff) {
|
|
|
588
609
|
|
|
589
610
|
export function presentMarkdownEdit(msg) {
|
|
590
611
|
if (!msg || !beginMarkdownPresentation(msg.path)) return;
|
|
612
|
+
var workbenchRevision = claimRightWorkbench("file-viewer");
|
|
613
|
+
store.set({ fileViewerOpenRevision: workbenchRevision });
|
|
591
614
|
openFileViewerTab(msg.path, { content: msg.content });
|
|
592
615
|
pendingOpenMode = null;
|
|
593
616
|
pendingRenderedOpen = true;
|
|
@@ -687,7 +710,7 @@ function requestDirectory(dirPath) {
|
|
|
687
710
|
function requestFileContent(filePath) {
|
|
688
711
|
var requestId = "file-read-" + Date.now() + "-" + Math.random().toString(36).slice(2);
|
|
689
712
|
var state = store.snap();
|
|
690
|
-
store.set({ fileReadRequest: { requestId: requestId, path: filePath, projectSlug: state.currentSlug || null, sessionId: state.activeSessionId != null ? String(state.activeSessionId) : null, accountId: state.myUserId || null } });
|
|
713
|
+
store.set({ fileReadRequest: { requestId: requestId, path: filePath, projectSlug: state.currentSlug || null, sessionId: state.activeSessionId != null ? String(state.activeSessionId) : null, accountId: state.myUserId || null, workbenchRevision: store.get('rightWorkbenchRevision') || 0 } });
|
|
691
714
|
var pending = store.get('pendingFileNavigation');
|
|
692
715
|
if (pending && pending.path === filePath) store.set({ pendingFileNavigation: Object.assign({}, pending, { requestId: requestId }) });
|
|
693
716
|
if (ctx.ws && ctx.connected) {
|
|
@@ -811,6 +834,7 @@ function renderFilteredTree(container, tree, depth, query) {
|
|
|
811
834
|
(function (rowEl, childEl, folderName) {
|
|
812
835
|
rowEl.addEventListener("click", function (e) {
|
|
813
836
|
e.stopPropagation();
|
|
837
|
+
claimRightWorkbench("file-viewer");
|
|
814
838
|
var isExpanded = rowEl.classList.contains("expanded");
|
|
815
839
|
rowEl.classList.toggle("expanded");
|
|
816
840
|
childEl.classList.toggle("hidden", isExpanded);
|
|
@@ -833,6 +857,7 @@ function renderFilteredTree(container, tree, depth, query) {
|
|
|
833
857
|
(function (filePath, rowEl) {
|
|
834
858
|
rowEl.addEventListener("click", function (e) {
|
|
835
859
|
e.stopPropagation();
|
|
860
|
+
claimRightWorkbench("file-viewer");
|
|
836
861
|
if (followedFileChanged(filePath)) cancelMarkdownFollow();
|
|
837
862
|
var prev = ctx.fileTreeEl.querySelector(".file-tree-item.active");
|
|
838
863
|
if (prev) prev.classList.remove("active");
|
|
@@ -843,7 +868,7 @@ function renderFilteredTree(container, tree, depth, query) {
|
|
|
843
868
|
});
|
|
844
869
|
rowEl.addEventListener("dblclick", function (e) {
|
|
845
870
|
e.stopPropagation();
|
|
846
|
-
|
|
871
|
+
openFile(filePath);
|
|
847
872
|
});
|
|
848
873
|
})(entry.path, row);
|
|
849
874
|
|
|
@@ -973,7 +998,7 @@ export function handleFsRead(msg) {
|
|
|
973
998
|
if ((request.projectSlug || null) !== (msg.projectSlug || null)) return;
|
|
974
999
|
if ((request.sessionId || null) !== (msg.sessionId == null ? null : String(msg.sessionId))) return;
|
|
975
1000
|
if ((request.accountId || null) !== (msg.accountId || null)) return;
|
|
976
|
-
showFileContent(msg);
|
|
1001
|
+
showFileContent(msg, request.workbenchRevision);
|
|
977
1002
|
}
|
|
978
1003
|
|
|
979
1004
|
// --- Tree rendering ---
|
|
@@ -1040,6 +1065,7 @@ function renderEntries(container, entries, depth) {
|
|
|
1040
1065
|
(function (dirPath, childEl, rowEl, folderName) {
|
|
1041
1066
|
rowEl.addEventListener("click", function (e) {
|
|
1042
1067
|
e.stopPropagation();
|
|
1068
|
+
claimRightWorkbench("file-viewer");
|
|
1043
1069
|
var isExpanded = rowEl.classList.contains("expanded");
|
|
1044
1070
|
if (isExpanded) {
|
|
1045
1071
|
rowEl.classList.remove("expanded");
|
|
@@ -1079,6 +1105,7 @@ function renderEntries(container, entries, depth) {
|
|
|
1079
1105
|
(function (filePath, rowEl) {
|
|
1080
1106
|
rowEl.addEventListener("click", function (e) {
|
|
1081
1107
|
e.stopPropagation();
|
|
1108
|
+
claimRightWorkbench("file-viewer");
|
|
1082
1109
|
if (followedFileChanged(filePath)) cancelMarkdownFollow();
|
|
1083
1110
|
// Mark active
|
|
1084
1111
|
var prev = ctx.fileTreeEl.querySelector(".file-tree-item.active");
|
|
@@ -1093,7 +1120,7 @@ function renderEntries(container, entries, depth) {
|
|
|
1093
1120
|
});
|
|
1094
1121
|
rowEl.addEventListener("dblclick", function (e) {
|
|
1095
1122
|
e.stopPropagation();
|
|
1096
|
-
|
|
1123
|
+
openFile(filePath);
|
|
1097
1124
|
});
|
|
1098
1125
|
})(entry.path, row);
|
|
1099
1126
|
|
|
@@ -1105,8 +1132,9 @@ function renderEntries(container, entries, depth) {
|
|
|
1105
1132
|
|
|
1106
1133
|
// --- File viewer ---
|
|
1107
1134
|
|
|
1108
|
-
function showFileContent(msg) {
|
|
1135
|
+
function showFileContent(msg, expectedRevision) {
|
|
1109
1136
|
if (!updateFileViewerTab(msg.path, { content: msg.content })) return;
|
|
1137
|
+
if (expectedRevision != null && !isRightWorkbenchCurrent("file-viewer", expectedRevision)) return;
|
|
1110
1138
|
var pathEl = document.getElementById("file-viewer-path");
|
|
1111
1139
|
var bodyEl = document.getElementById("file-viewer-body");
|
|
1112
1140
|
var renderBtn = document.getElementById("file-viewer-render");
|
|
@@ -1183,7 +1211,6 @@ function showFileContent(msg) {
|
|
|
1183
1211
|
}
|
|
1184
1212
|
}
|
|
1185
1213
|
|
|
1186
|
-
closeTerminal();
|
|
1187
1214
|
ctx.fileViewerEl.classList.remove("hidden");
|
|
1188
1215
|
sendWatch(msg.path);
|
|
1189
1216
|
refreshIcons();
|
|
@@ -1291,7 +1318,7 @@ function pathsReferToSameFile(left, right) {
|
|
|
1291
1318
|
}
|
|
1292
1319
|
|
|
1293
1320
|
export function handleFileChanged(msg) {
|
|
1294
|
-
if (!msg.path || msg.path
|
|
1321
|
+
if (!msg.path || !pathsReferToSameFile(msg.path, currentFilePath)) return;
|
|
1295
1322
|
if (ctx.fileViewerEl.classList.contains("hidden")) return;
|
|
1296
1323
|
if (historyVisible || inlineDiffActive) return;
|
|
1297
1324
|
if (msg.content === currentContent) return;
|
|
@@ -1299,7 +1326,7 @@ export function handleFileChanged(msg) {
|
|
|
1299
1326
|
var bodyEl = document.getElementById("file-viewer-body");
|
|
1300
1327
|
var scrollPos = bodyEl ? bodyEl.scrollTop : 0;
|
|
1301
1328
|
pendingRefresh = true;
|
|
1302
|
-
showFileContent(msg);
|
|
1329
|
+
showFileContent(msg.path === currentFilePath ? msg : Object.assign({}, msg, { path: currentFilePath }));
|
|
1303
1330
|
if (bodyEl) bodyEl.scrollTop = scrollPos;
|
|
1304
1331
|
}
|
|
1305
1332
|
|