@lvce-editor/explorer-view 6.2.0 → 6.4.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.
@@ -936,11 +936,13 @@ const FileCannotStartWithBackSlash = 'A file or folder name cannot start with a
936
936
  const FilesExplorer = 'Files Explorer';
937
937
  const NewFile$2 = 'New File...';
938
938
  const NewFolder$2 = 'New Folder...';
939
+ const OpenAnotherFolder = 'Open another folder';
939
940
  const OpenContainingFolder = 'Open Containing Folder';
940
941
  const OpenFolder$1 = 'Open folder';
941
942
  const OpenInIntegratedTerminal = 'Open in integrated Terminal';
942
943
  const Paste = 'Paste';
943
944
  const RefreshExplorer = 'Refresh Explorer';
945
+ const RemoveFolderFromWorkspace = 'Remove folder from workspace';
944
946
  const Rename = 'Rename';
945
947
  const TheNameIsNotValid = 'The name **{0}** is not valid as a file or folder name. Please choose a different name.';
946
948
  const TypeAFileName = 'Type file name. Press Enter to confirm or Escape to cancel.'; // TODO use keybinding
@@ -982,6 +984,9 @@ const deleteItem = () => {
982
984
  const refresh$1 = () => {
983
985
  return i18nString(RefreshExplorer);
984
986
  };
987
+ const removeFolderFromWorkspace = () => {
988
+ return i18nString(RemoveFolderFromWorkspace);
989
+ };
985
990
  const collapseAll$1 = () => {
986
991
  return i18nString(CollapseAllFoldersInExplorer);
987
992
  };
@@ -994,6 +999,9 @@ const youHaveNotYetOpenedAFolder = () => {
994
999
  const openFolder$1 = () => {
995
1000
  return i18nString(OpenFolder$1);
996
1001
  };
1002
+ const openAnotherFolder = () => {
1003
+ return i18nString(OpenAnotherFolder);
1004
+ };
997
1005
  const fileOrFolderNameMustBeProvided = () => {
998
1006
  return i18nString(FileOrFolderNameMustBeProvider);
999
1007
  };
@@ -1203,7 +1211,7 @@ const acceptEdit = async state => {
1203
1211
  };
1204
1212
 
1205
1213
  const getFocusedIndexCancel = (items, editingIndex) => {
1206
- const newFocusedIndex = editingIndex > items.length ? items.length - 1 : editingIndex;
1214
+ const newFocusedIndex = editingIndex >= items.length ? items.length - 1 : editingIndex;
1207
1215
  return newFocusedIndex;
1208
1216
  };
1209
1217
 
@@ -1325,14 +1333,9 @@ const getFocusedDirent$1 = state => {
1325
1333
 
1326
1334
  const copyPath = async state => {
1327
1335
  const dirent = getFocusedDirent$1(state);
1328
- if (!dirent) {
1329
- return state;
1330
- }
1331
1336
  // TODO windows paths
1332
1337
  // TODO handle error
1333
- const {
1334
- path
1335
- } = dirent;
1338
+ const path = dirent ? dirent.path : state.root;
1336
1339
  await writeClipBoardText(path);
1337
1340
  return state;
1338
1341
  };
@@ -1347,12 +1350,25 @@ const writeNativeFiles = async (type, files) => {
1347
1350
  return invoke$2('ClipBoard.writeNativeFiles', type, files);
1348
1351
  };
1349
1352
 
1353
+ const getRelativePath = (root, pathSeparator, path) => {
1354
+ if (root && path.startsWith(root)) {
1355
+ const relativePath = path.slice(root.length);
1356
+ if (relativePath.startsWith(pathSeparator)) {
1357
+ return relativePath.slice(pathSeparator.length);
1358
+ }
1359
+ return relativePath;
1360
+ }
1361
+ if (path.startsWith(pathSeparator)) {
1362
+ return path.slice(pathSeparator.length);
1363
+ }
1364
+ return path;
1365
+ };
1350
1366
  const copyRelativePath = async state => {
1351
1367
  const dirent = getFocusedDirent$1(state);
1352
1368
  if (!dirent) {
1353
1369
  return state;
1354
1370
  }
1355
- const relativePath = dirent.path.slice(1);
1371
+ const relativePath = getRelativePath(state.root, state.pathSeparator, dirent.path);
1356
1372
  // TODO handle error
1357
1373
  await writeText(relativePath);
1358
1374
  return state;
@@ -2556,6 +2572,12 @@ const menuEntryDelete = {
2556
2572
  id: 'delete',
2557
2573
  label: deleteItem()
2558
2574
  };
2575
+ const menuEntryRemoveFolderFromWorkspace = {
2576
+ command: 'Workspace.close',
2577
+ flags: None$2,
2578
+ id: 'removeFolderFromWorkspace',
2579
+ label: removeFolderFromWorkspace()
2580
+ };
2559
2581
  const ALL_ENTRIES = [menuEntryNewFile, menuEntryNewFolder, menuEntryOpenContainingFolder, menuEntryOpenInIntegratedTerminal, menuEntrySeparator, menuEntryCut, menuEntryCopy, menuEntryPaste, menuEntrySeparator, menuEntryCopyPath, menuEntryCopyRelativePath, menuEntrySeparator, menuEntryRename, menuEntryDelete];
2560
2582
 
2561
2583
  // TODO there are two possible ways of getting the focused dirent of explorer
@@ -2576,13 +2598,17 @@ const getMenuEntriesFile = () => {
2576
2598
  const getMenuEntriesDefault = () => {
2577
2599
  return ALL_ENTRIES;
2578
2600
  };
2579
- const getMenuEntriesRoot = () => {
2580
- return [menuEntryNewFile, menuEntryNewFolder, menuEntryOpenContainingFolder, menuEntryOpenInIntegratedTerminal, menuEntrySeparator, menuEntryPaste, menuEntrySeparator, menuEntryCopyPath, menuEntryCopyRelativePath];
2601
+ const getMenuEntriesRoot = root => {
2602
+ const entries = [menuEntryNewFile, menuEntryNewFolder, menuEntryOpenContainingFolder, menuEntryOpenInIntegratedTerminal, menuEntrySeparator, menuEntryPaste, menuEntrySeparator, menuEntryCopyPath, menuEntryCopyRelativePath];
2603
+ if (root) {
2604
+ entries.push(menuEntrySeparator, menuEntryRemoveFolderFromWorkspace);
2605
+ }
2606
+ return entries;
2581
2607
  };
2582
2608
  const getMenuEntries = state => {
2583
2609
  const focusedDirent = getFocusedDirent(state);
2584
2610
  if (!focusedDirent) {
2585
- return getMenuEntriesRoot();
2611
+ return getMenuEntriesRoot(state.root);
2586
2612
  }
2587
2613
  switch (focusedDirent.type) {
2588
2614
  case Directory:
@@ -2825,6 +2851,19 @@ const NewFolder$1 = 'NewFolder';
2825
2851
  const OpenFolder = 'OpenFolder';
2826
2852
  const Refresh$1 = 'Refresh';
2827
2853
 
2854
+ const isFolder = direntType => {
2855
+ return direntType === Directory || direntType === DirectoryExpanded || direntType === SymLinkFolder;
2856
+ };
2857
+ const getFittingIndex = (dirents, startIndex) => {
2858
+ for (let i = startIndex; i >= 0; i--) {
2859
+ const dirent = dirents[i];
2860
+ if (dirent && isFolder(dirent.type)) {
2861
+ return i;
2862
+ }
2863
+ }
2864
+ return -1;
2865
+ };
2866
+
2828
2867
  const getNewChildDirentsForNewDirent = async (items, depth, parentPath, direntType) => {
2829
2868
  // Get existing children or query them if they don't exist
2830
2869
  let existingChildren = items.filter(item => item.depth === depth && item.path.startsWith(parentPath));
@@ -2912,18 +2951,6 @@ const getNewDirentType = editingType => {
2912
2951
  }
2913
2952
  };
2914
2953
 
2915
- const isFolder = direntType => {
2916
- return direntType === Directory || direntType === DirectoryExpanded || direntType === SymLinkFolder;
2917
- };
2918
- const getFittingIndex = (dirents, startIndex) => {
2919
- for (let i = startIndex; i >= 0; i--) {
2920
- const dirent = dirents[i];
2921
- if (isFolder(dirent.type)) {
2922
- return i;
2923
- }
2924
- }
2925
- return -1;
2926
- };
2927
2954
  const newDirent = async (state, editingType) => {
2928
2955
  // TODO do it like vscode, select position between folders and files
2929
2956
  const {
@@ -3829,16 +3856,24 @@ const getFileOperations = (root, uploadTree) => {
3829
3856
  };
3830
3857
 
3831
3858
  const isDroppedFile = item => {
3832
- return item.kind === 'file' && 'value' in item && item.value instanceof FileSystemHandle;
3859
+ return item.kind === 'file' && 'value' in item;
3860
+ };
3861
+ const getFileSystemHandle = item => {
3862
+ if (isDroppedFile(item)) {
3863
+ return item.value;
3864
+ }
3865
+ return item;
3866
+ };
3867
+ const getDroppedName = item => {
3868
+ if (isDroppedFile(item)) {
3869
+ return item.value.name;
3870
+ }
3871
+ return item.name;
3833
3872
  };
3834
3873
  const getFileSystemHandlesNormalized = fileSystemHandles => {
3835
3874
  const normalized = [];
3836
3875
  for (const item of fileSystemHandles) {
3837
- if (isDroppedFile(item)) {
3838
- normalized.push(item.value);
3839
- } else {
3840
- normalized.push(item);
3841
- }
3876
+ normalized.push(getFileSystemHandle(item));
3842
3877
  }
3843
3878
  return normalized;
3844
3879
  };
@@ -3870,7 +3905,7 @@ const getMergedDirents$2 = async (root, pathSeparator, dirents) => {
3870
3905
  const getDroppedDirectoryWorkspacePath = fileHandle => {
3871
3906
  return `html://${fileHandle.name}`;
3872
3907
  };
3873
- const openDroppedDirectoryAsWorkspace = async (state, fileHandle) => {
3908
+ const openDroppedDirectoryAsWorkspace$1 = async (state, fileHandle) => {
3874
3909
  const path = getDroppedDirectoryWorkspacePath(fileHandle);
3875
3910
  await invoke$2('PersistentFileHandle.addHandle', fileHandle.name, fileHandle);
3876
3911
  await invoke$2('Workspace.setPath', path);
@@ -3884,17 +3919,15 @@ const getFirstDroppedDirectory = (state, fileHandles) => {
3884
3919
  if (state.root !== '') {
3885
3920
  return undefined;
3886
3921
  }
3887
- for (const fileHandle of fileHandles) {
3922
+ for (const item of fileHandles) {
3923
+ const fileHandle = getFileSystemHandle(item);
3888
3924
  if (isDirectoryHandle(fileHandle)) {
3889
3925
  return fileHandle;
3890
3926
  }
3891
3927
  }
3892
3928
  return undefined;
3893
3929
  };
3894
- const shouldIgnoreDroppedHandles = (state, fileHandles) => {
3895
- return state.root === '' && fileHandles.length > 0 && !getFirstDroppedDirectory(state, fileHandles);
3896
- };
3897
- const handleDrop$2 = async (state, fileHandles, files) => {
3930
+ const handleDrop$2 = async (state, fileHandles, files, paths) => {
3898
3931
  const {
3899
3932
  items,
3900
3933
  pathSeparator,
@@ -3902,9 +3935,9 @@ const handleDrop$2 = async (state, fileHandles, files) => {
3902
3935
  } = state;
3903
3936
  const droppedDirectory = getFirstDroppedDirectory(state, fileHandles);
3904
3937
  if (droppedDirectory) {
3905
- return openDroppedDirectoryAsWorkspace(state, droppedDirectory);
3938
+ return openDroppedDirectoryAsWorkspace$1(state, droppedDirectory);
3906
3939
  }
3907
- if (shouldIgnoreDroppedHandles(state, fileHandles)) {
3940
+ if (root === '') {
3908
3941
  return {
3909
3942
  ...state,
3910
3943
  dropTargets: []
@@ -3930,9 +3963,7 @@ const getFileOperationsElectron = async (root, paths, fileHandles, pathSeparator
3930
3963
  const operations = [];
3931
3964
  for (let i = 0; i < paths.length; i++) {
3932
3965
  const fileHandle = fileHandles[i];
3933
- const {
3934
- name
3935
- } = fileHandle;
3966
+ const name = getDroppedName(fileHandle);
3936
3967
  const path = paths[i];
3937
3968
  operations.push({
3938
3969
  from: path,
@@ -3958,12 +3989,42 @@ const getMergedDirents$1 = async (root, pathSeparator, dirents) => {
3958
3989
  const mergedDirents = mergeDirents(dirents, childDirents);
3959
3990
  return mergedDirents;
3960
3991
  };
3992
+ const openDroppedDirectoryAsWorkspace = async (state, path) => {
3993
+ await invoke$2('Workspace.setPath', path);
3994
+ const updated = await loadContent(state, undefined);
3995
+ return {
3996
+ ...updated,
3997
+ dropTargets: []
3998
+ };
3999
+ };
4000
+ const getFirstDroppedDirectoryPath = (state, fileHandles, paths) => {
4001
+ if (state.root !== '') {
4002
+ return undefined;
4003
+ }
4004
+ for (let i = 0; i < fileHandles.length; i++) {
4005
+ const fileHandle = getFileSystemHandle(fileHandles[i]);
4006
+ if (isDirectoryHandle(fileHandle)) {
4007
+ return paths[i];
4008
+ }
4009
+ }
4010
+ return undefined;
4011
+ };
3961
4012
  const handleDrop$1 = async (state, fileHandles, files, paths) => {
3962
4013
  const {
3963
4014
  items,
3964
4015
  pathSeparator,
3965
4016
  root
3966
4017
  } = state;
4018
+ const droppedDirectoryPath = getFirstDroppedDirectoryPath(state, fileHandles, paths);
4019
+ if (droppedDirectoryPath) {
4020
+ return openDroppedDirectoryAsWorkspace(state, droppedDirectoryPath);
4021
+ }
4022
+ if (root === '') {
4023
+ return {
4024
+ ...state,
4025
+ dropTargets: []
4026
+ };
4027
+ }
3967
4028
  await copyFilesElectron(root, fileHandles, files, paths);
3968
4029
  const mergedDirents = await getMergedDirents$1(root, pathSeparator, items);
3969
4030
  return {
@@ -5041,6 +5102,12 @@ const getLabelDom = (isEditing, name, isDimmed) => {
5041
5102
  return [label, text(name)];
5042
5103
  };
5043
5104
 
5105
+ const getTitle = path => {
5106
+ if (path.startsWith('file://')) {
5107
+ return path.slice('file://'.length);
5108
+ }
5109
+ return path;
5110
+ };
5044
5111
  const getExplorerItemVirtualDom = item => {
5045
5112
  const {
5046
5113
  ariaExpanded,
@@ -5073,7 +5140,7 @@ const getExplorerItemVirtualDom = item => {
5073
5140
  draggable: true,
5074
5141
  id,
5075
5142
  role: TreeItem,
5076
- title: path,
5143
+ title: getTitle(path),
5077
5144
  type: Div
5078
5145
  }, ...chevronDom, getFileIconVirtualDom(icon), ...getInputDom(isEditing, hasEditingError), ...getLabelDom(isEditing, name, isCut || isIgnored)];
5079
5146
  };
@@ -5124,13 +5191,26 @@ const getParentNode$1 = childCount => {
5124
5191
  type: Div
5125
5192
  };
5126
5193
  };
5127
- const getLoadErrorVirtualDom = loadErrorMessage => {
5194
+ const getLoadErrorVirtualDom = (loadErrorMessage, isWide, showOpenAnotherFolderButton) => {
5195
+ const childCount = showOpenAnotherFolderButton ? 2 : 1;
5128
5196
  const errorDom = [{
5129
- childCount: 1,
5197
+ childCount,
5198
+ className: Welcome,
5130
5199
  type: Div
5200
+ }, {
5201
+ childCount: 1,
5202
+ className: WelcomeMessage,
5203
+ type: P
5131
5204
  }, text(loadErrorMessage)];
5205
+ const buttonDom = showOpenAnotherFolderButton ? [{
5206
+ childCount: 1,
5207
+ className: mergeClassNames(Button$2, ButtonPrimary, isWide ? ButtonWide : ButtonNarrow),
5208
+ name: OpenFolder,
5209
+ onClick: HandleClickOpenFolder,
5210
+ type: Button$1
5211
+ }, text(openAnotherFolder())] : [];
5132
5212
  const parentNode = getParentNode$1(1);
5133
- return [parentNode, ...errorDom];
5213
+ return [parentNode, ...errorDom, ...buttonDom];
5134
5214
  };
5135
5215
 
5136
5216
  const getScrollBarVirtualDom = scrollBarHeight => {
@@ -5167,12 +5247,12 @@ const getChildCount = (scrollBarDomLength, errorDomLength) => {
5167
5247
  }
5168
5248
  return childCount;
5169
5249
  };
5170
- const getExplorerVirtualDom = (visibleItems, focusedIndex, root, isWide, focused, dropTargets, height, contentHeight, editingErrorMessage, loadErrorMessage) => {
5250
+ const getExplorerVirtualDom = (visibleItems, focusedIndex, root, isWide, focused, dropTargets, height, contentHeight, editingErrorMessage, loadErrorMessage, showOpenAnotherFolderButton) => {
5171
5251
  if (!root) {
5172
5252
  return getExplorerWelcomeVirtualDom(isWide, dropTargets);
5173
5253
  }
5174
5254
  if (loadErrorMessage) {
5175
- return getLoadErrorVirtualDom(loadErrorMessage);
5255
+ return getLoadErrorVirtualDom(loadErrorMessage, isWide, showOpenAnotherFolderButton);
5176
5256
  }
5177
5257
  const scrollBarHeight = getScrollBarSize(height, contentHeight, 20);
5178
5258
  const scrollBarDom = getScrollBarVirtualDom(scrollBarHeight);
@@ -5183,14 +5263,26 @@ const getExplorerVirtualDom = (visibleItems, focusedIndex, root, isWide, focused
5183
5263
  return dom;
5184
5264
  };
5185
5265
 
5266
+ const getMissingFolderMessage = root => {
5267
+ if (root) {
5268
+ return `Could not open "${root}" because the folder does not exist. It may have been moved or deleted.`;
5269
+ }
5270
+ return 'Could not open folder because the folder does not exist. It may have been moved or deleted.';
5271
+ };
5186
5272
  const getLoadErrorMessage = state => {
5187
5273
  if (state.hasError) {
5274
+ if (state.errorCode === 'ENOENT') {
5275
+ return getMissingFolderMessage(state.root);
5276
+ }
5188
5277
  const code = state.errorCode ? ` (error code: ${state.errorCode})` : '';
5189
5278
  const reason = state.errorMessage || 'an unexpected error occurred';
5190
5279
  return `Could not open folder due to ${reason}${code}.`;
5191
5280
  }
5192
5281
  return '';
5193
5282
  };
5283
+ const shouldShowOpenAnotherFolderButton = state => {
5284
+ return state.hasError && state.errorCode === 'ENOENT';
5285
+ };
5194
5286
 
5195
5287
  const renderItems = (oldState, newState) => {
5196
5288
  const {
@@ -5209,10 +5301,11 @@ const renderItems = (oldState, newState) => {
5209
5301
  const isWide = width > 450;
5210
5302
  const contentHeight = items.length * itemHeight;
5211
5303
  const loadErrorMessage = getLoadErrorMessage(newState);
5304
+ const showOpenAnotherFolderButton = shouldShowOpenAnotherFolderButton(newState);
5212
5305
  if (initial) {
5213
5306
  return [SetDom2, newState.uid, []];
5214
5307
  }
5215
- const dom = getExplorerVirtualDom(visibleDirents, focusedIndex, root, isWide, focused, dropTargets, height, contentHeight, editingErrorMessage, loadErrorMessage);
5308
+ const dom = getExplorerVirtualDom(visibleDirents, focusedIndex, root, isWide, focused, dropTargets, height, contentHeight, editingErrorMessage, loadErrorMessage, showOpenAnotherFolderButton);
5216
5309
  return [SetDom2, newState.uid, dom];
5217
5310
  };
5218
5311
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/explorer-view",
3
- "version": "6.2.0",
3
+ "version": "6.4.0",
4
4
  "description": "Explorer Worker",
5
5
  "repository": {
6
6
  "type": "git",