@opensumi/ide-file-tree-next 3.7.2-next-1740450374.0 → 3.7.2-next-1741226843.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/browser/dialog/file-dialog.service.d.ts +0 -4
- package/lib/browser/dialog/file-dialog.service.d.ts.map +1 -1
- package/lib/browser/dialog/file-dialog.service.js +1 -7
- package/lib/browser/dialog/file-dialog.service.js.map +1 -1
- package/lib/browser/dialog/file-dialog.view.d.ts.map +1 -1
- package/lib/browser/dialog/file-dialog.view.js +9 -44
- package/lib/browser/dialog/file-dialog.view.js.map +1 -1
- package/lib/browser/file-tree-contribution.d.ts.map +1 -1
- package/lib/browser/file-tree-contribution.js +1 -8
- package/lib/browser/file-tree-contribution.js.map +1 -1
- package/lib/browser/services/file-tree-api.service.d.ts +2 -3
- package/lib/browser/services/file-tree-api.service.d.ts.map +1 -1
- package/lib/browser/services/file-tree-api.service.js +1 -3
- package/lib/browser/services/file-tree-api.service.js.map +1 -1
- package/lib/browser/services/file-tree-model.service.d.ts.map +1 -1
- package/lib/browser/services/file-tree-model.service.js +8 -29
- package/lib/browser/services/file-tree-model.service.js.map +1 -1
- package/lib/common/index.d.ts +1 -2
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js.map +1 -1
- package/package.json +17 -18
- package/src/browser/dialog/file-dialog.service.ts +1 -12
- package/src/browser/dialog/file-dialog.view.tsx +9 -69
- package/src/browser/file-tree-contribution.ts +1 -8
- package/src/browser/services/file-tree-api.service.ts +2 -5
- package/src/browser/services/file-tree-model.service.ts +12 -34
- package/src/common/index.ts +1 -3
|
@@ -42,7 +42,6 @@ export const FileDialog = ({
|
|
|
42
42
|
const [isReady, setIsReady] = useState<boolean>(false);
|
|
43
43
|
const [selectPath, setSelectPath] = useState<string>('');
|
|
44
44
|
const [directoryList, setDirectoryList] = useState<string[]>([]);
|
|
45
|
-
const currentSaveFileName = useRef<string>((options as ISaveDialogOptions).defaultFileName || '');
|
|
46
45
|
|
|
47
46
|
useEffect(() => {
|
|
48
47
|
if (model) {
|
|
@@ -57,8 +56,7 @@ export const FileDialog = ({
|
|
|
57
56
|
|
|
58
57
|
useEffect(() => {
|
|
59
58
|
if ((options as ISaveDialogOptions).defaultFileName) {
|
|
60
|
-
setFileName((options as ISaveDialogOptions).defaultFileName
|
|
61
|
-
currentSaveFileName.current = (options as ISaveDialogOptions).defaultFileName || '';
|
|
59
|
+
setFileName((options as ISaveDialogOptions).defaultFileName!);
|
|
62
60
|
}
|
|
63
61
|
}, [options]);
|
|
64
62
|
|
|
@@ -72,25 +70,19 @@ export const FileDialog = ({
|
|
|
72
70
|
const ensure = useCallback(() => {
|
|
73
71
|
const value: string[] = model.selectedFiles.map((file) => file.uri.path.toString());
|
|
74
72
|
// 如果有文件名的,说明肯定是保存文件的情况
|
|
75
|
-
if (
|
|
76
|
-
currentSaveFileName.current &&
|
|
77
|
-
(options as ISaveDialogOptions).showNameInput &&
|
|
78
|
-
(value?.length === 1 || options.defaultUri)
|
|
79
|
-
) {
|
|
73
|
+
if (fileName && (options as ISaveDialogOptions).showNameInput && (value?.length === 1 || options.defaultUri)) {
|
|
80
74
|
const filePath = value?.length === 1 ? value[0] : options.defaultUri!.path.toString();
|
|
81
75
|
if ((options as ISaveDialogOptions & { saveAs?: boolean | undefined })?.saveAs) {
|
|
82
76
|
fileService.saveAs({
|
|
83
77
|
oldFilePath: path.join(filePath!, (options as ISaveDialogOptions)?.defaultFileName || ''),
|
|
84
|
-
newFilePath: path.join(filePath!,
|
|
78
|
+
newFilePath: path.join(filePath!, fileName),
|
|
85
79
|
});
|
|
86
80
|
}
|
|
87
81
|
|
|
88
|
-
dialogService.hide([path.join(filePath!,
|
|
82
|
+
dialogService.hide([path.join(filePath!, fileName)]);
|
|
89
83
|
} else {
|
|
90
84
|
if (value.length > 0) {
|
|
91
85
|
dialogService.hide(value);
|
|
92
|
-
} else if (selectPath) {
|
|
93
|
-
dialogService.hide([selectPath]);
|
|
94
86
|
} else if (options.defaultUri) {
|
|
95
87
|
dialogService.hide([options.defaultUri!.path.toString()]);
|
|
96
88
|
} else if (model.treeModel && model.treeModel.root) {
|
|
@@ -101,17 +93,7 @@ export const FileDialog = ({
|
|
|
101
93
|
}
|
|
102
94
|
setIsReady(false);
|
|
103
95
|
fileService.contextKey.fileDialogViewVisibleContext.set(false);
|
|
104
|
-
}, [isReady, dialogService, model,
|
|
105
|
-
|
|
106
|
-
const getDefaultPath = async (model) => {
|
|
107
|
-
let defaultPath = (model.treeModel.root as Directory).uri.codeUri.fsPath;
|
|
108
|
-
|
|
109
|
-
if (fileService.getDefaultFilePath) {
|
|
110
|
-
defaultPath = await fileService.getDefaultFilePath(model, defaultPath);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return defaultPath;
|
|
114
|
-
};
|
|
96
|
+
}, [isReady, dialogService, model, fileName, options]);
|
|
115
97
|
|
|
116
98
|
const close = useCallback(() => {
|
|
117
99
|
setIsReady(false);
|
|
@@ -124,9 +106,7 @@ export const FileDialog = ({
|
|
|
124
106
|
// 确保数据初始化完毕,减少初始化数据过程中多次刷新视图
|
|
125
107
|
// 这里需要重新取一下treeModel的值确保为最新的TreeModel
|
|
126
108
|
await model.treeModel.ensureReady;
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
setSelectPath(path);
|
|
109
|
+
setSelectPath((model.treeModel.root as Directory).uri.codeUri.fsPath);
|
|
130
110
|
setIsReady(true);
|
|
131
111
|
}, [model, selectPath, isReady]);
|
|
132
112
|
|
|
@@ -221,24 +201,6 @@ export const FileDialog = ({
|
|
|
221
201
|
[model, isReady, selectPath],
|
|
222
202
|
);
|
|
223
203
|
|
|
224
|
-
const onSearchChangeHandler = useCallback(
|
|
225
|
-
async (value: string) => {
|
|
226
|
-
setIsReady(false);
|
|
227
|
-
setSelectPath(value);
|
|
228
|
-
await model.updateTreeModel(value);
|
|
229
|
-
setIsReady(true);
|
|
230
|
-
},
|
|
231
|
-
[model, isReady, selectPath, directoryList],
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
const renderCustomMsg = useCallback(() => {
|
|
235
|
-
if (fileService.renderCustomMsg) {
|
|
236
|
-
return fileService.renderCustomMsg();
|
|
237
|
-
} else {
|
|
238
|
-
return null;
|
|
239
|
-
}
|
|
240
|
-
}, [fileService.renderCustomMsg]);
|
|
241
|
-
|
|
242
204
|
const renderDialogTreeNode = useCallback(
|
|
243
205
|
(props: INodeRendererProps) => (
|
|
244
206
|
<FileTreeDialogNode
|
|
@@ -272,23 +234,10 @@ export const FileDialog = ({
|
|
|
272
234
|
}
|
|
273
235
|
}, [isReady, model]);
|
|
274
236
|
|
|
275
|
-
const showFilePathSearch = useMemo(
|
|
276
|
-
() => (fileService.showFilePathSearch === false ? false : true),
|
|
277
|
-
[fileService.showFilePathSearch],
|
|
278
|
-
);
|
|
279
|
-
|
|
280
237
|
const renderDirectorySelection = useCallback(() => {
|
|
281
238
|
if (directoryList.length > 0) {
|
|
282
239
|
return (
|
|
283
|
-
<Select
|
|
284
|
-
onChange={onRootChangeHandler}
|
|
285
|
-
onSearchChange={onSearchChangeHandler}
|
|
286
|
-
className={styles.select_control}
|
|
287
|
-
size='large'
|
|
288
|
-
searchPlaceholder={selectPath}
|
|
289
|
-
value={selectPath}
|
|
290
|
-
showSearch={showFilePathSearch}
|
|
291
|
-
>
|
|
240
|
+
<Select onChange={onRootChangeHandler} className={styles.select_control} size={'small'} value={selectPath}>
|
|
292
241
|
{directoryList.map((item, idx) => (
|
|
293
242
|
<Option value={item} key={`${idx} - ${item}`}>
|
|
294
243
|
{item}
|
|
@@ -324,7 +273,6 @@ export const FileDialog = ({
|
|
|
324
273
|
const DialogContent = useMemo(
|
|
325
274
|
() => (
|
|
326
275
|
<>
|
|
327
|
-
{renderCustomMsg()}
|
|
328
276
|
<div className={styles.file_dialog_directory}>{renderDirectorySelection()}</div>
|
|
329
277
|
<div className={styles.file_dialog_content}>{renderDialogTree()}</div>
|
|
330
278
|
</>
|
|
@@ -335,7 +283,7 @@ export const FileDialog = ({
|
|
|
335
283
|
const DialogButtons = useMemo(
|
|
336
284
|
() => (
|
|
337
285
|
<div className={styles.file_dialog_buttons}>
|
|
338
|
-
<Button onClick={close} type='
|
|
286
|
+
<Button onClick={close} type='secondary' className={styles.button}>
|
|
339
287
|
{localize('dialog.file.close')}
|
|
340
288
|
</Button>
|
|
341
289
|
<Button
|
|
@@ -353,14 +301,6 @@ export const FileDialog = ({
|
|
|
353
301
|
[close, ensure, isSaveDialog, isOpenDialog, fileName, options],
|
|
354
302
|
);
|
|
355
303
|
|
|
356
|
-
const handleSaveInputChange = useCallback(
|
|
357
|
-
(event: React.ChangeEvent<HTMLInputElement>) => {
|
|
358
|
-
setFileName(event.target.value);
|
|
359
|
-
currentSaveFileName.current = event.target.value;
|
|
360
|
-
},
|
|
361
|
-
[fileName],
|
|
362
|
-
);
|
|
363
|
-
|
|
364
304
|
return (
|
|
365
305
|
<div className={styles.file_dialog_wrapper} ref={wrapperRef}>
|
|
366
306
|
<div className={styles.file_dialog_directory_title}>
|
|
@@ -379,7 +319,7 @@ export const FileDialog = ({
|
|
|
379
319
|
value={fileName}
|
|
380
320
|
autoFocus={true}
|
|
381
321
|
selection={{ start: 0, end: fileName.indexOf('.') || fileName.length }}
|
|
382
|
-
onChange={
|
|
322
|
+
onChange={(event) => setFileName(event.target.value)}
|
|
383
323
|
/>
|
|
384
324
|
</div>
|
|
385
325
|
)}
|
|
@@ -50,7 +50,6 @@ import { EXPLORER_CONTAINER_ID } from '@opensumi/ide-explorer/lib/browser/explor
|
|
|
50
50
|
import { IMainLayoutService, IViewsRegistry, MainLayoutContribution } from '@opensumi/ide-main-layout';
|
|
51
51
|
import { ViewContentGroups } from '@opensumi/ide-main-layout/lib/browser/views-registry';
|
|
52
52
|
import { IOpenDialogOptions, ISaveDialogOptions, IWindowDialogService } from '@opensumi/ide-overlay';
|
|
53
|
-
import { Path } from '@opensumi/ide-utils/lib/path';
|
|
54
53
|
import { IWorkspaceService, UNTITLED_WORKSPACE } from '@opensumi/ide-workspace';
|
|
55
54
|
|
|
56
55
|
import { IFileTreeService, PasteTypes, RESOURCE_VIEW_ID } from '../common';
|
|
@@ -779,15 +778,9 @@ export class FileTreeContribution
|
|
|
779
778
|
}
|
|
780
779
|
if (uri.scheme === DIFF_SCHEME) {
|
|
781
780
|
const query = uri.getParsedQuery();
|
|
781
|
+
// 需要file scheme才能与工作区计算相对路径
|
|
782
782
|
uri = new URI(query.modified).withScheme('file');
|
|
783
783
|
}
|
|
784
|
-
const node = this.fileTreeService.getNodeByPathOrUri(uri);
|
|
785
|
-
if (node) {
|
|
786
|
-
if (node.filestat.isInSymbolicDirectory) {
|
|
787
|
-
// 软链接文件需要通过直接通过文件树 Path 获取
|
|
788
|
-
return await this.clipboardService.writeText(node.path.split(Path.separator).slice(2).join(Path.separator));
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
784
|
let rootUri: URI;
|
|
792
785
|
if (this.fileTreeService.isMultipleWorkspace) {
|
|
793
786
|
// 多工作区额外处理
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Autowired, Injectable } from '@opensumi/di';
|
|
2
2
|
import { ITree } from '@opensumi/ide-components';
|
|
3
3
|
import { CorePreferences, EDITOR_COMMANDS } from '@opensumi/ide-core-browser';
|
|
4
|
-
import { CommandService,
|
|
4
|
+
import { CommandService, URI, formatLocalize, localize, path } from '@opensumi/ide-core-common';
|
|
5
5
|
import { FileStat } from '@opensumi/ide-file-service';
|
|
6
6
|
import { IFileServiceClient } from '@opensumi/ide-file-service/lib/common';
|
|
7
7
|
import { IDialogService } from '@opensumi/ide-overlay';
|
|
@@ -12,9 +12,6 @@ import { Directory, File } from '../../common/file-tree-node.define';
|
|
|
12
12
|
|
|
13
13
|
@Injectable()
|
|
14
14
|
export class FileTreeAPI implements IFileTreeAPI {
|
|
15
|
-
private readonly onDidResolveChildrenEmitter: Emitter<string> = new Emitter();
|
|
16
|
-
onDidResolveChildren: Event<string> = this.onDidResolveChildrenEmitter.event;
|
|
17
|
-
|
|
18
15
|
@Autowired(IFileServiceClient)
|
|
19
16
|
protected fileServiceClient: IFileServiceClient;
|
|
20
17
|
|
|
@@ -29,6 +26,7 @@ export class FileTreeAPI implements IFileTreeAPI {
|
|
|
29
26
|
|
|
30
27
|
@Autowired(IDialogService)
|
|
31
28
|
private readonly dialogService: IDialogService;
|
|
29
|
+
private cacheFileStat: Map<string, FileStat> = new Map();
|
|
32
30
|
|
|
33
31
|
private userhomePath: URI;
|
|
34
32
|
|
|
@@ -47,7 +45,6 @@ export class FileTreeAPI implements IFileTreeAPI {
|
|
|
47
45
|
}
|
|
48
46
|
|
|
49
47
|
if (file) {
|
|
50
|
-
this.onDidResolveChildrenEmitter.fire(file.uri.toString());
|
|
51
48
|
if (file.children?.length === 1 && file.children[0].isDirectory && compact) {
|
|
52
49
|
return await this.resolveChildren(tree, file.children[0].uri, parent, compact);
|
|
53
50
|
} else {
|
|
@@ -23,7 +23,6 @@ import {
|
|
|
23
23
|
IClipboardService,
|
|
24
24
|
IContextKey,
|
|
25
25
|
IStorage,
|
|
26
|
-
MessageType,
|
|
27
26
|
STORAGE_NAMESPACE,
|
|
28
27
|
StorageProvider,
|
|
29
28
|
ThrottledDelayer,
|
|
@@ -31,11 +30,9 @@ import {
|
|
|
31
30
|
URI,
|
|
32
31
|
arrays,
|
|
33
32
|
formatLocalize,
|
|
34
|
-
isLinux,
|
|
35
33
|
localize,
|
|
36
34
|
path,
|
|
37
35
|
strings,
|
|
38
|
-
toMarkdown,
|
|
39
36
|
} from '@opensumi/ide-core-browser';
|
|
40
37
|
import { ResourceContextKey } from '@opensumi/ide-core-browser/lib/contextkey/resource';
|
|
41
38
|
import { AbstractContextMenuService, ICtxMenuRenderer, MenuId } from '@opensumi/ide-core-browser/lib/menu/next';
|
|
@@ -728,10 +725,6 @@ export class FileTreeModelService {
|
|
|
728
725
|
};
|
|
729
726
|
|
|
730
727
|
handleItemRangeClick = (item: File | Directory, type: TreeNodeType) => {
|
|
731
|
-
// 由于文件树存在选择根目录的逻辑,使用 Shift+Click 时需要清理根目录选中态
|
|
732
|
-
if (this.selectedFiles.length === 1 && Directory.isRoot(this.selectedFiles[0])) {
|
|
733
|
-
this.clearFileSelectedDecoration();
|
|
734
|
-
}
|
|
735
728
|
if (!this.focusedFile) {
|
|
736
729
|
this.handleItemClick(item, type);
|
|
737
730
|
} else if (this.focusedFile && this.focusedFile !== item) {
|
|
@@ -751,10 +744,7 @@ export class FileTreeModelService {
|
|
|
751
744
|
if (type !== TreeNodeType.CompositeTreeNode && type !== TreeNodeType.TreeNode) {
|
|
752
745
|
return;
|
|
753
746
|
}
|
|
754
|
-
|
|
755
|
-
if (this.selectedFiles.length === 1 && Directory.isRoot(this.selectedFiles[0])) {
|
|
756
|
-
this.clearFileSelectedDecoration();
|
|
757
|
-
}
|
|
747
|
+
|
|
758
748
|
// 根据节点的选中态进行复选操作
|
|
759
749
|
this.toggleFileSelectedDecoration(item);
|
|
760
750
|
};
|
|
@@ -987,29 +977,18 @@ export class FileTreeModelService {
|
|
|
987
977
|
if (uris.length === 0) {
|
|
988
978
|
return;
|
|
989
979
|
}
|
|
990
|
-
// 默认过滤掉根目录的选择
|
|
991
980
|
if (this.corePreferences['explorer.confirmDelete']) {
|
|
992
|
-
const ok =
|
|
981
|
+
const ok = localize('file.confirm.delete.ok');
|
|
993
982
|
const cancel = localize('file.confirm.delete.cancel');
|
|
994
|
-
const
|
|
995
|
-
|
|
996
|
-
.slice(0, MAX_FILES)
|
|
983
|
+
const deleteFilesMessage = `[ ${uris
|
|
984
|
+
.slice(0, 5)
|
|
997
985
|
.map((uri) => uri.displayName)
|
|
998
|
-
.join('
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
}
|
|
1005
|
-
const confirm = await this.dialogService.open({
|
|
1006
|
-
message: toMarkdown(formatLocalize('file.confirm.delete', uris.length, deleteFilesMessage)),
|
|
1007
|
-
type: MessageType.Warning,
|
|
1008
|
-
props: {
|
|
1009
|
-
width: 580,
|
|
1010
|
-
},
|
|
1011
|
-
buttons: [cancel, ok],
|
|
1012
|
-
});
|
|
986
|
+
.join(',')}${uris.length > 5 ? ' ...' : ''} ]`;
|
|
987
|
+
|
|
988
|
+
const confirm = await this.dialogService.warning(formatLocalize('file.confirm.delete', deleteFilesMessage), [
|
|
989
|
+
cancel,
|
|
990
|
+
ok,
|
|
991
|
+
]);
|
|
1013
992
|
if (confirm !== ok) {
|
|
1014
993
|
return;
|
|
1015
994
|
}
|
|
@@ -1730,8 +1709,7 @@ export class FileTreeModelService {
|
|
|
1730
1709
|
this._nextLocationTarget = undefined;
|
|
1731
1710
|
}
|
|
1732
1711
|
};
|
|
1733
|
-
|
|
1734
|
-
public selectChildNode(uris: URI[]) {
|
|
1712
|
+
selectChildNode(uris: URI[]) {
|
|
1735
1713
|
for (const uri of uris) {
|
|
1736
1714
|
const file = this.fileTreeService.getNodeByPathOrUri(uri);
|
|
1737
1715
|
|
|
@@ -1743,7 +1721,7 @@ export class FileTreeModelService {
|
|
|
1743
1721
|
const last = children[children.length - 1];
|
|
1744
1722
|
const firstIndex = this.treeModel.root.getIndexAtTreeNode(first);
|
|
1745
1723
|
const lastIndex = this.treeModel.root.getIndexAtTreeNode(last);
|
|
1746
|
-
|
|
1724
|
+
|
|
1747
1725
|
this.activeFileDecorationByRange(firstIndex, lastIndex);
|
|
1748
1726
|
}
|
|
1749
1727
|
}
|
package/src/common/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ITree, ITreeNode } from '@opensumi/ide-components';
|
|
2
|
-
import { BasicEvent,
|
|
2
|
+
import { BasicEvent, IDisposable, URI } from '@opensumi/ide-core-common';
|
|
3
3
|
import { FileStat } from '@opensumi/ide-file-service';
|
|
4
4
|
|
|
5
5
|
import { Directory, File } from './file-tree-node.define';
|
|
@@ -19,8 +19,6 @@ export interface IMoveFileMetadata {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export interface IFileTreeAPI {
|
|
22
|
-
onDidResolveChildren: Event<string>;
|
|
23
|
-
|
|
24
22
|
copyFile(from: URI, to: URI): Promise<FileStat | string | void>;
|
|
25
23
|
createFile(newUri: URI, content?: string): Promise<string | void>;
|
|
26
24
|
createDirectory(newUri: URI): Promise<string | void>;
|