vzcode 1.11.0 → 1.13.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 +1 -1
- package/dist/assets/index-Bm65AzMP.js +425 -0
- package/dist/assets/index-BpeGnq7b.js +157 -0
- package/dist/assets/{index-BKRpkJER.css → index-Wxh-Jaj6.css} +1 -1
- package/dist/assets/worker-CJWrLBN2.js +286 -0
- package/dist/index.html +2 -2
- package/package.json +18 -17
- package/src/client/AIAssist/AIAssistCodeMirrorKeyMap.ts +5 -2
- package/src/client/AIAssist/startAIAssist.ts +1 -1
- package/src/client/CodeEditor/getOrCreateEditor.ts +11 -4
- package/src/client/CodeEditor/index.tsx +2 -0
- package/src/client/CodeEditor/json1PresenceDisplay.ts +1 -1
- package/src/client/Icons/SplitEditorSVG.tsx +34 -0
- package/src/client/RunCodeWidget/index.tsx +48 -16
- package/src/client/RunCodeWidget/style.scss +6 -1
- package/src/client/TabList/Tab.tsx +1 -2
- package/src/client/TabList/index.tsx +1 -1
- package/src/client/VZCodeContext.tsx +30 -7
- package/src/client/VZKeyboardShortcutsDoc.tsx +2 -1
- package/src/client/VZSidebar/DirectoryListing.tsx +2 -1
- package/src/client/VZSidebar/FileListing.tsx +23 -3
- package/src/client/VZSidebar/Item.tsx +2 -2
- package/src/client/VZSidebar/Listing.tsx +8 -1
- package/src/client/VZSidebar/Search.tsx +7 -2
- package/src/client/VZSidebar/index.tsx +130 -24
- package/src/client/VZSidebar/styles.scss +25 -0
- package/src/client/tabsSearchParameters.ts +1 -2
- package/src/client/useActions.ts +29 -1
- package/src/client/useKeyboardShortcuts.ts +31 -1
- package/src/client/useURLSync.ts +1 -2
- package/src/client/vzReducer/closeTabReducer.test.ts +49 -33
- package/src/client/vzReducer/closeTabsReducer.ts +51 -19
- package/src/client/vzReducer/createInitialState.ts +9 -3
- package/src/client/vzReducer/findPane.ts +19 -0
- package/src/client/vzReducer/index.ts +38 -27
- package/src/client/vzReducer/openTabReducer.test.ts +38 -21
- package/src/client/vzReducer/openTabReducer.ts +26 -10
- package/src/client/vzReducer/searchReducer.ts +21 -1
- package/src/client/vzReducer/setActiveFileIdReducer.ts +23 -4
- package/src/client/vzReducer/setActiveFileLeftRightReducer.ts +37 -8
- package/src/client/vzReducer/splitCurrentPaneReducer.ts +71 -0
- package/src/client/vzReducer/updatePane.ts +44 -0
- package/src/client/vzReducer/updatePresenceIndicatorReducer.ts +30 -0
- package/src/server/index.js +1 -0
- package/src/types.ts +86 -1
- package/dist/assets/index--bvX81xc.js +0 -425
- package/dist/assets/index-BSuijdti.js +0 -157
- package/dist/assets/worker-Cs0ZU3m1.js +0 -291
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
useCallback,
|
|
3
3
|
useContext,
|
|
4
|
+
useEffect,
|
|
4
5
|
useMemo,
|
|
5
6
|
useState,
|
|
6
7
|
} from 'react';
|
|
@@ -8,6 +9,9 @@ import {
|
|
|
8
9
|
FileId,
|
|
9
10
|
FileTree,
|
|
10
11
|
FileTreeFile,
|
|
12
|
+
Presence,
|
|
13
|
+
PresenceId,
|
|
14
|
+
PresenceIndicator,
|
|
11
15
|
} from '../../types';
|
|
12
16
|
import { Tooltip, OverlayTrigger } from '../bootstrap';
|
|
13
17
|
import { Search } from './Search';
|
|
@@ -35,21 +39,74 @@ import './styles.scss';
|
|
|
35
39
|
const enableConnectionStatus = true;
|
|
36
40
|
|
|
37
41
|
export const VZSidebar = ({
|
|
38
|
-
createFileTooltipText =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
createFileTooltipText = (
|
|
43
|
+
<>
|
|
44
|
+
<strong>New file</strong>
|
|
45
|
+
{/* TODO verify that Ctrl + Shift + N works - does not work in Linux */}
|
|
46
|
+
<div>(Alt + N or Ctrl + Shift + N)</div>
|
|
47
|
+
</>
|
|
48
|
+
),
|
|
49
|
+
createDirTooltipText = (
|
|
50
|
+
<div>
|
|
51
|
+
<strong>New Directory</strong>
|
|
52
|
+
{/* TODO consider Alt+D, as Ctrl + Shift + D does not work in Linux */}
|
|
53
|
+
<div>(Ctrl + Shift + D)</div>
|
|
54
|
+
</div>
|
|
55
|
+
),
|
|
56
|
+
openSettingsTooltipText = (
|
|
57
|
+
<div>
|
|
58
|
+
<strong>Open Settings</strong>
|
|
59
|
+
<div>(Ctrl + Shift + S or Ctrl + ,)</div>
|
|
60
|
+
</div>
|
|
61
|
+
),
|
|
62
|
+
openKeyboardShortcuts = (
|
|
63
|
+
<div>
|
|
64
|
+
<strong>Keyboard Shortcuts</strong>
|
|
65
|
+
<div>(Ctrl + Shift + K)</div>
|
|
66
|
+
</div>
|
|
67
|
+
),
|
|
68
|
+
reportBugTooltipText = (
|
|
69
|
+
<div>
|
|
70
|
+
<strong>Report Bug</strong>
|
|
71
|
+
{/* TODO get this keyboard shortcut working? */}
|
|
72
|
+
{/* <div>(Ctrl + Shift + B)</div> */}
|
|
73
|
+
</div>
|
|
74
|
+
),
|
|
75
|
+
searchToolTipText = (
|
|
76
|
+
<div>
|
|
77
|
+
<strong>Search</strong>
|
|
78
|
+
<div>(Ctrl + Shift + F)</div>
|
|
79
|
+
</div>
|
|
80
|
+
),
|
|
81
|
+
filesToolTipText = (
|
|
82
|
+
<div>
|
|
83
|
+
<strong>Files</strong>
|
|
84
|
+
<div>(Ctrl + Shift + E)</div>
|
|
85
|
+
</div>
|
|
86
|
+
),
|
|
87
|
+
enableAutoFollowTooltipText = (
|
|
88
|
+
<div>
|
|
89
|
+
<strong>Enable Auto Follow</strong>
|
|
90
|
+
<div>(Ctrl + Shift + A)</div>
|
|
91
|
+
</div>
|
|
92
|
+
),
|
|
93
|
+
disableAutoFollowTooltipText = (
|
|
94
|
+
<div>
|
|
95
|
+
<strong>Disable Auto Follow</strong>
|
|
96
|
+
{/* TODO consider Alt+A, this breaks in Linux */}
|
|
97
|
+
<div>(Ctrl + Shift + A)</div>
|
|
98
|
+
</div>
|
|
99
|
+
),
|
|
45
100
|
}: {
|
|
46
|
-
createFileTooltipText?:
|
|
47
|
-
createDirTooltipText?:
|
|
48
|
-
openSettingsTooltipText?:
|
|
49
|
-
reportBugTooltipText?:
|
|
50
|
-
openKeyboardShortcuts?:
|
|
51
|
-
searchToolTipText?:
|
|
52
|
-
filesToolTipText?:
|
|
101
|
+
createFileTooltipText?: React.ReactNode;
|
|
102
|
+
createDirTooltipText?: React.ReactNode;
|
|
103
|
+
openSettingsTooltipText?: React.ReactNode;
|
|
104
|
+
reportBugTooltipText?: React.ReactNode;
|
|
105
|
+
openKeyboardShortcuts?: React.ReactNode;
|
|
106
|
+
searchToolTipText?: React.ReactNode;
|
|
107
|
+
filesToolTipText?: React.ReactNode;
|
|
108
|
+
enableAutoFollowTooltipText?: React.ReactNode;
|
|
109
|
+
disableAutoFollowTooltipText?: React.ReactNode;
|
|
53
110
|
}) => {
|
|
54
111
|
const {
|
|
55
112
|
files,
|
|
@@ -64,6 +121,9 @@ export const VZSidebar = ({
|
|
|
64
121
|
sidebarRef,
|
|
65
122
|
enableAutoFollow,
|
|
66
123
|
toggleAutoFollow,
|
|
124
|
+
docPresence,
|
|
125
|
+
updatePresenceIndicator,
|
|
126
|
+
sidebarPresenceIndicators,
|
|
67
127
|
} = useContext(VZCodeContext);
|
|
68
128
|
|
|
69
129
|
const fileTree = useMemo(
|
|
@@ -111,6 +171,42 @@ export const VZSidebar = ({
|
|
|
111
171
|
handleDrop,
|
|
112
172
|
} = useDragAndDrop();
|
|
113
173
|
|
|
174
|
+
// Track presence of remote users across files
|
|
175
|
+
// so that they can be displayed in the sidebar.
|
|
176
|
+
useEffect(() => {
|
|
177
|
+
docPresence;
|
|
178
|
+
}, []);
|
|
179
|
+
|
|
180
|
+
// Track the presence indicators for display in sidebar
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
if (docPresence) {
|
|
183
|
+
const handleReceive = (
|
|
184
|
+
presenceId: PresenceId,
|
|
185
|
+
update: Presence,
|
|
186
|
+
) => {
|
|
187
|
+
const presenceIndicator: PresenceIndicator = {
|
|
188
|
+
username: update.username,
|
|
189
|
+
fileId: update.start[1] as FileId,
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
console.log('Got presence!');
|
|
193
|
+
// console.log({presenceId,update})
|
|
194
|
+
console.log(
|
|
195
|
+
JSON.stringify(presenceIndicator, null, 2),
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
updatePresenceIndicator(presenceIndicator);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
docPresence.on('receive', handleReceive);
|
|
202
|
+
return () => {
|
|
203
|
+
docPresence.off('receive', handleReceive);
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}, [docPresence]);
|
|
207
|
+
|
|
208
|
+
console.log(sidebarPresenceIndicators);
|
|
209
|
+
|
|
114
210
|
return (
|
|
115
211
|
<div
|
|
116
212
|
className="vz-sidebar"
|
|
@@ -135,8 +231,9 @@ export const VZSidebar = ({
|
|
|
135
231
|
}
|
|
136
232
|
>
|
|
137
233
|
<i
|
|
138
|
-
|
|
234
|
+
id="files-icon"
|
|
139
235
|
className="icon-button icon-button-dark"
|
|
236
|
+
onClick={() => setIsSearchOpen(false)}
|
|
140
237
|
>
|
|
141
238
|
<FolderSVG />
|
|
142
239
|
</i>
|
|
@@ -151,8 +248,9 @@ export const VZSidebar = ({
|
|
|
151
248
|
}
|
|
152
249
|
>
|
|
153
250
|
<i
|
|
154
|
-
|
|
251
|
+
id="search-icon"
|
|
155
252
|
className="icon-button icon-button-dark"
|
|
253
|
+
onClick={() => setIsSearchOpen(true)}
|
|
156
254
|
>
|
|
157
255
|
<SearchSVG />
|
|
158
256
|
</i>
|
|
@@ -167,8 +265,9 @@ export const VZSidebar = ({
|
|
|
167
265
|
}
|
|
168
266
|
>
|
|
169
267
|
<i
|
|
170
|
-
|
|
268
|
+
id="shortcut-icon"
|
|
171
269
|
className="icon-button icon-button-dark"
|
|
270
|
+
onClick={handleQuestionMarkClick}
|
|
172
271
|
>
|
|
173
272
|
<QuestionMarkSVG />
|
|
174
273
|
</i>
|
|
@@ -187,7 +286,10 @@ export const VZSidebar = ({
|
|
|
187
286
|
target="_blank"
|
|
188
287
|
rel="noopener noreferrer"
|
|
189
288
|
>
|
|
190
|
-
<i
|
|
289
|
+
<i
|
|
290
|
+
id="bug-icon"
|
|
291
|
+
className="icon-button icon-button-dark"
|
|
292
|
+
>
|
|
191
293
|
<BugSVG />
|
|
192
294
|
</i>
|
|
193
295
|
</a>
|
|
@@ -202,8 +304,9 @@ export const VZSidebar = ({
|
|
|
202
304
|
}
|
|
203
305
|
>
|
|
204
306
|
<i
|
|
205
|
-
|
|
307
|
+
id="settings-icon"
|
|
206
308
|
className="icon-button icon-button-dark"
|
|
309
|
+
onClick={handleSettingsClick}
|
|
207
310
|
>
|
|
208
311
|
<GearSVG />
|
|
209
312
|
</i>
|
|
@@ -218,8 +321,9 @@ export const VZSidebar = ({
|
|
|
218
321
|
}
|
|
219
322
|
>
|
|
220
323
|
<i
|
|
221
|
-
|
|
324
|
+
id="new-file-icon"
|
|
222
325
|
className="icon-button icon-button-dark"
|
|
326
|
+
onClick={handleOpenCreateFileModal}
|
|
223
327
|
>
|
|
224
328
|
<NewSVG />
|
|
225
329
|
</i>
|
|
@@ -235,8 +339,9 @@ export const VZSidebar = ({
|
|
|
235
339
|
}
|
|
236
340
|
>
|
|
237
341
|
<i
|
|
238
|
-
|
|
342
|
+
id="new-directory-icon"
|
|
239
343
|
className="icon-button icon-button-dark"
|
|
344
|
+
onClick={handleOpenCreateDirModal}
|
|
240
345
|
>
|
|
241
346
|
<FileSVG />
|
|
242
347
|
</i>
|
|
@@ -248,18 +353,19 @@ export const VZSidebar = ({
|
|
|
248
353
|
overlay={
|
|
249
354
|
<Tooltip id="toggle-auto-follow">
|
|
250
355
|
{enableAutoFollow
|
|
251
|
-
?
|
|
252
|
-
:
|
|
356
|
+
? disableAutoFollowTooltipText
|
|
357
|
+
: enableAutoFollowTooltipText}
|
|
253
358
|
</Tooltip>
|
|
254
359
|
}
|
|
255
360
|
>
|
|
256
361
|
<i
|
|
257
|
-
|
|
362
|
+
id="auto-focus-icon"
|
|
258
363
|
className={`icon-button icon-button-dark${
|
|
259
364
|
enableAutoFollow
|
|
260
365
|
? ' vh-color-success-01'
|
|
261
366
|
: ''
|
|
262
367
|
}`}
|
|
368
|
+
onClick={toggleAutoFollow}
|
|
263
369
|
>
|
|
264
370
|
<PinSVG />
|
|
265
371
|
</i>
|
|
@@ -253,4 +253,29 @@
|
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
255
|
}
|
|
256
|
+
.name {
|
|
257
|
+
display: flex;
|
|
258
|
+
align-items: center;
|
|
259
|
+
white-space: nowrap;
|
|
260
|
+
overflow: hidden;
|
|
261
|
+
gap: 6px;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.presence-indicators {
|
|
265
|
+
display: flex;
|
|
266
|
+
gap: 4px;
|
|
267
|
+
margin-right: 6px; /* Space between the indicators and the file name */
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.presence-indicator {
|
|
271
|
+
width: 16px;
|
|
272
|
+
height: 16px;
|
|
273
|
+
border-radius: 50%;
|
|
274
|
+
display: flex;
|
|
275
|
+
align-items: center;
|
|
276
|
+
justify-content: center;
|
|
277
|
+
font-size: 10px;
|
|
278
|
+
background-color: #ff5733;
|
|
279
|
+
color: #ffffff;
|
|
280
|
+
}
|
|
256
281
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { FileId, VZCodeContent } from '../types';
|
|
2
|
-
import { TabState } from './vzReducer';
|
|
1
|
+
import { FileId, TabState, VZCodeContent } from '../types';
|
|
3
2
|
|
|
4
3
|
// The delimiter used to separate file names in the `tabs` parameter.
|
|
5
4
|
// We need a character that is both URL-safe (does not get escaped in URLs)
|
package/src/client/useActions.ts
CHANGED
|
@@ -2,12 +2,14 @@ import { useCallback } from 'react';
|
|
|
2
2
|
import { ThemeLabel } from './themes';
|
|
3
3
|
import {
|
|
4
4
|
FileId,
|
|
5
|
+
PresenceIndicator,
|
|
5
6
|
SearchFileVisibility,
|
|
6
7
|
ShareDBDoc,
|
|
8
|
+
TabState,
|
|
7
9
|
Username,
|
|
8
10
|
VZCodeContent,
|
|
9
11
|
} from '../types';
|
|
10
|
-
import {
|
|
12
|
+
import { VZAction } from './vzReducer';
|
|
11
13
|
|
|
12
14
|
// This is a custom hook that returns a set of functions
|
|
13
15
|
// that can be used to dispatch actions to the reducer.
|
|
@@ -113,6 +115,13 @@ export const useActions = (
|
|
|
113
115
|
[dispatch],
|
|
114
116
|
);
|
|
115
117
|
|
|
118
|
+
// Toggle the focused variable, which should focus the search input
|
|
119
|
+
const toggleSearchFocused = useCallback(() => {
|
|
120
|
+
dispatch({
|
|
121
|
+
type: 'toggle_search_focused',
|
|
122
|
+
});
|
|
123
|
+
}, [dispatch]);
|
|
124
|
+
|
|
116
125
|
// True to show the settings modal.
|
|
117
126
|
const setIsSettingsOpen = useCallback(
|
|
118
127
|
(value: boolean) => {
|
|
@@ -164,6 +173,22 @@ export const useActions = (
|
|
|
164
173
|
});
|
|
165
174
|
}, [dispatch]);
|
|
166
175
|
|
|
176
|
+
const updatePresenceIndicator = useCallback(
|
|
177
|
+
(presenceIndicator: PresenceIndicator) => {
|
|
178
|
+
dispatch({
|
|
179
|
+
type: 'update_presence_indicator',
|
|
180
|
+
presenceIndicator,
|
|
181
|
+
});
|
|
182
|
+
},
|
|
183
|
+
[dispatch],
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
const splitCurrentPane = useCallback(() => {
|
|
187
|
+
dispatch({
|
|
188
|
+
type: 'split_current_pane',
|
|
189
|
+
});
|
|
190
|
+
}, [dispatch]);
|
|
191
|
+
|
|
167
192
|
return {
|
|
168
193
|
setActiveFileId,
|
|
169
194
|
setActiveFileLeft,
|
|
@@ -175,6 +200,7 @@ export const useActions = (
|
|
|
175
200
|
setSearch,
|
|
176
201
|
setSearchResults,
|
|
177
202
|
setSearchFileVisibility,
|
|
203
|
+
toggleSearchFocused,
|
|
178
204
|
setIsSettingsOpen,
|
|
179
205
|
setIsDocOpen,
|
|
180
206
|
closeSettings,
|
|
@@ -182,5 +208,7 @@ export const useActions = (
|
|
|
182
208
|
editorNoLongerWantsFocus,
|
|
183
209
|
setUsername,
|
|
184
210
|
toggleAutoFollow,
|
|
211
|
+
updatePresenceIndicator,
|
|
212
|
+
splitCurrentPane,
|
|
185
213
|
};
|
|
186
214
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
1
|
+
import { useContext, useEffect } from 'react';
|
|
2
2
|
import { shouldTriggerRun } from './shouldTriggerRun';
|
|
3
3
|
import { syntaxTree } from '@codemirror/language';
|
|
4
4
|
import { SyntaxNode, SyntaxNodeRef } from '@lezer/common';
|
|
@@ -151,6 +151,18 @@ function jumpToDefinition(
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
// Sidebar keyboard shortcuts in form Ctrl + Shift + <key>
|
|
155
|
+
const sideBarKeyBoardMap = {
|
|
156
|
+
E: 'files-icon',
|
|
157
|
+
F: 'search-icon',
|
|
158
|
+
K: 'shortcut-icon',
|
|
159
|
+
B: 'bug-icon',
|
|
160
|
+
S: 'settings-icon',
|
|
161
|
+
N: 'new-file-icon',
|
|
162
|
+
D: 'new-directory-icon',
|
|
163
|
+
A: 'auto-focus-icon',
|
|
164
|
+
};
|
|
165
|
+
|
|
154
166
|
// This module implements the keyboard shortcuts
|
|
155
167
|
// for the VZCode editor.
|
|
156
168
|
// These include:
|
|
@@ -166,6 +178,7 @@ export const useKeyboardShortcuts = ({
|
|
|
166
178
|
handleOpenCreateFileModal,
|
|
167
179
|
setActiveFileLeft,
|
|
168
180
|
setActiveFileRight,
|
|
181
|
+
toggleSearchFocused,
|
|
169
182
|
runPrettierRef,
|
|
170
183
|
runCodeRef,
|
|
171
184
|
sidebarRef,
|
|
@@ -177,6 +190,7 @@ export const useKeyboardShortcuts = ({
|
|
|
177
190
|
handleOpenCreateFileModal: () => void;
|
|
178
191
|
setActiveFileLeft: () => void;
|
|
179
192
|
setActiveFileRight: () => void;
|
|
193
|
+
toggleSearchFocused: () => void;
|
|
180
194
|
runPrettierRef: React.MutableRefObject<() => void>;
|
|
181
195
|
runCodeRef: React.MutableRefObject<() => void>;
|
|
182
196
|
sidebarRef: React.RefObject<HTMLDivElement>;
|
|
@@ -203,6 +217,22 @@ export const useKeyboardShortcuts = ({
|
|
|
203
217
|
return;
|
|
204
218
|
}
|
|
205
219
|
|
|
220
|
+
if (event.ctrlKey && event.shiftKey) {
|
|
221
|
+
// Handle keyboard shortcuts related to the side bar icons
|
|
222
|
+
document
|
|
223
|
+
.getElementById(sideBarKeyBoardMap[event.key])
|
|
224
|
+
?.click();
|
|
225
|
+
|
|
226
|
+
// Ensure the search input is always focused
|
|
227
|
+
if (event.key === 'F') {
|
|
228
|
+
toggleSearchFocused();
|
|
229
|
+
}
|
|
230
|
+
} else if (event.ctrlKey && event.key === ',') {
|
|
231
|
+
document
|
|
232
|
+
.getElementById(sideBarKeyBoardMap['S'])
|
|
233
|
+
?.click();
|
|
234
|
+
}
|
|
235
|
+
|
|
206
236
|
if (event.ctrlKey === true) {
|
|
207
237
|
// On holding CTRL key, search for a potential definition jump using mouse location
|
|
208
238
|
document.addEventListener(
|
package/src/client/useURLSync.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useSearchParams } from 'react-router-dom';
|
|
2
|
-
import { FileId, VZCodeContent } from '../types';
|
|
3
|
-
import { TabState } from './vzReducer';
|
|
2
|
+
import { FileId, TabState, VZCodeContent } from '../types';
|
|
4
3
|
import { useEffect, useMemo, useRef } from 'react';
|
|
5
4
|
import {
|
|
6
5
|
TabStateParams,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
1
|
+
import { assert, describe, expect, it } from 'vitest';
|
|
2
2
|
import { closeTabsReducer } from './closeTabsReducer';
|
|
3
3
|
import { VZAction, VZState, createInitialState } from '.';
|
|
4
4
|
import { defaultTheme } from '../themes';
|
|
@@ -25,8 +25,9 @@ describe('closeTabsReducer', () => {
|
|
|
25
25
|
action,
|
|
26
26
|
);
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
expect(newState.
|
|
28
|
+
assert(newState.pane.type === 'leafPane');
|
|
29
|
+
expect(newState.pane.tabList.length).toBe(0);
|
|
30
|
+
expect(newState.pane.activeFileId).toBeNull();
|
|
30
31
|
});
|
|
31
32
|
|
|
32
33
|
it('Keeps other tabs open', () => {
|
|
@@ -36,11 +37,14 @@ describe('closeTabsReducer', () => {
|
|
|
36
37
|
};
|
|
37
38
|
const stateWithTabs = {
|
|
38
39
|
...initialState,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
pane: {
|
|
41
|
+
...initialState.pane,
|
|
42
|
+
tabList: [
|
|
43
|
+
{ fileId: 'file1', isTransient: false },
|
|
44
|
+
{ fileId: 'file2', isTransient: false },
|
|
45
|
+
],
|
|
46
|
+
activeFileId: 'file1',
|
|
47
|
+
},
|
|
44
48
|
};
|
|
45
49
|
|
|
46
50
|
const newState = closeTabsReducer(
|
|
@@ -48,24 +52,29 @@ describe('closeTabsReducer', () => {
|
|
|
48
52
|
action,
|
|
49
53
|
);
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
expect(newState.tabList
|
|
53
|
-
expect(newState.
|
|
55
|
+
assert(newState.pane.type === 'leafPane');
|
|
56
|
+
expect(newState.pane.tabList.length).toBe(1);
|
|
57
|
+
expect(newState.pane.tabList[0].fileId).toBe('file1');
|
|
58
|
+
expect(newState.pane.activeFileId).toBe('file1');
|
|
54
59
|
});
|
|
55
60
|
|
|
56
|
-
it('Activates previous tab after closing an active tab', () => {
|
|
61
|
+
it.only('Activates previous tab after closing an active tab', () => {
|
|
57
62
|
const action: VZAction = {
|
|
58
63
|
type: 'close_tabs',
|
|
59
64
|
fileIdsToClose: ['file2'],
|
|
60
65
|
};
|
|
61
|
-
const stateWithTabs = {
|
|
66
|
+
const stateWithTabs: VZState = {
|
|
62
67
|
...initialState,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
pane: {
|
|
69
|
+
...initialState.pane,
|
|
70
|
+
type: 'leafPane',
|
|
71
|
+
tabList: [
|
|
72
|
+
{ fileId: 'file1', isTransient: false },
|
|
73
|
+
{ fileId: 'file2', isTransient: false },
|
|
74
|
+
{ fileId: 'file3', isTransient: false },
|
|
75
|
+
],
|
|
76
|
+
activeFileId: 'file2',
|
|
77
|
+
},
|
|
69
78
|
};
|
|
70
79
|
|
|
71
80
|
const newState = closeTabsReducer(
|
|
@@ -73,8 +82,9 @@ describe('closeTabsReducer', () => {
|
|
|
73
82
|
action,
|
|
74
83
|
);
|
|
75
84
|
|
|
76
|
-
|
|
77
|
-
expect(newState.
|
|
85
|
+
assert(newState.pane.type === 'leafPane');
|
|
86
|
+
expect(newState.pane.tabList.length).toBe(2);
|
|
87
|
+
expect(newState.pane.activeFileId).toBe('file1'); // should switch to the previous tab
|
|
78
88
|
});
|
|
79
89
|
|
|
80
90
|
it('Does not modify the state if closing non-existing tabs', () => {
|
|
@@ -84,12 +94,15 @@ describe('closeTabsReducer', () => {
|
|
|
84
94
|
};
|
|
85
95
|
const stateWithTabs = {
|
|
86
96
|
...initialState,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
97
|
+
pane: {
|
|
98
|
+
...initialState.pane,
|
|
99
|
+
tabList: [
|
|
100
|
+
{ fileId: 'file1', isTransient: false },
|
|
101
|
+
{ fileId: 'file2', isTransient: false },
|
|
102
|
+
{ fileId: 'file3', isTransient: false },
|
|
103
|
+
],
|
|
104
|
+
activeFileId: 'file2',
|
|
105
|
+
},
|
|
93
106
|
};
|
|
94
107
|
|
|
95
108
|
const newState = closeTabsReducer(
|
|
@@ -121,8 +134,9 @@ describe('closeTabsReducer', () => {
|
|
|
121
134
|
action,
|
|
122
135
|
);
|
|
123
136
|
|
|
124
|
-
|
|
125
|
-
expect(newState.
|
|
137
|
+
assert(newState.pane.type === 'leafPane');
|
|
138
|
+
expect(newState.pane.tabList.length).toBe(2);
|
|
139
|
+
expect(newState.pane.activeFileId).toBe('file3'); // remains unchanged
|
|
126
140
|
});
|
|
127
141
|
|
|
128
142
|
it('Closes the first tab out of many, when it is active', () => {
|
|
@@ -146,8 +160,9 @@ describe('closeTabsReducer', () => {
|
|
|
146
160
|
action,
|
|
147
161
|
);
|
|
148
162
|
|
|
149
|
-
|
|
150
|
-
expect(newState.
|
|
163
|
+
assert(newState.pane.type === 'leafPane');
|
|
164
|
+
expect(newState.pane.tabList.length).toBe(2);
|
|
165
|
+
expect(newState.pane.activeFileId).toBe('file2'); // switches to the next available tab
|
|
151
166
|
});
|
|
152
167
|
|
|
153
168
|
it('Closes multiple tabs at once', () => {
|
|
@@ -171,7 +186,8 @@ describe('closeTabsReducer', () => {
|
|
|
171
186
|
action,
|
|
172
187
|
);
|
|
173
188
|
|
|
174
|
-
|
|
175
|
-
expect(newState.
|
|
189
|
+
assert(newState.pane.type === 'leafPane');
|
|
190
|
+
expect(newState.pane.tabList.length).toBe(1);
|
|
191
|
+
expect(newState.pane.activeFileId).toBe('file3'); // switches to the next available tab
|
|
176
192
|
});
|
|
177
193
|
});
|