@theia/filesystem 1.65.0-next.55 → 1.65.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.
Files changed (117) hide show
  1. package/lib/browser/download/file-download-command-contribution.d.ts +1 -1
  2. package/lib/browser/download/file-download-command-contribution.d.ts.map +1 -1
  3. package/lib/browser/download/file-download-command-contribution.js +3 -3
  4. package/lib/browser/download/file-download-command-contribution.js.map +1 -1
  5. package/lib/browser/download/file-download-frontend-module.d.ts.map +1 -1
  6. package/lib/browser/download/file-download-frontend-module.js +2 -1
  7. package/lib/browser/download/file-download-frontend-module.js.map +1 -1
  8. package/lib/browser/download/file-download-service.d.ts +2 -10
  9. package/lib/browser/download/file-download-service.d.ts.map +1 -1
  10. package/lib/browser/download/file-download-service.js +8 -7
  11. package/lib/browser/download/file-download-service.js.map +1 -1
  12. package/lib/browser/file-tree/file-tree-widget.d.ts +1 -1
  13. package/lib/browser/file-tree/file-tree-widget.d.ts.map +1 -1
  14. package/lib/browser/file-tree/file-tree-widget.js +3 -3
  15. package/lib/browser/file-tree/file-tree-widget.js.map +1 -1
  16. package/lib/browser/filesystem-frontend-contribution.d.ts +2 -2
  17. package/lib/browser/filesystem-frontend-contribution.d.ts.map +1 -1
  18. package/lib/browser/filesystem-frontend-contribution.js +3 -3
  19. package/lib/browser/filesystem-frontend-contribution.js.map +1 -1
  20. package/lib/browser/filesystem-frontend-module.d.ts.map +1 -1
  21. package/lib/browser/filesystem-frontend-module.js +3 -2
  22. package/lib/browser/filesystem-frontend-module.js.map +1 -1
  23. package/lib/browser/{file-upload-service.d.ts → upload/file-upload-service-impl.d.ts} +16 -52
  24. package/lib/browser/upload/file-upload-service-impl.d.ts.map +1 -0
  25. package/lib/browser/{file-upload-service.js → upload/file-upload-service-impl.js} +27 -27
  26. package/lib/browser/upload/file-upload-service-impl.js.map +1 -0
  27. package/lib/browser-only/browser-only-filesystem-frontend-module.d.ts.map +1 -1
  28. package/lib/browser-only/browser-only-filesystem-frontend-module.js +8 -0
  29. package/lib/browser-only/browser-only-filesystem-frontend-module.js.map +1 -1
  30. package/lib/browser-only/download/file-download-command-contribution.d.ts +15 -0
  31. package/lib/browser-only/download/file-download-command-contribution.d.ts.map +1 -0
  32. package/lib/browser-only/download/file-download-command-contribution.js +55 -0
  33. package/lib/browser-only/download/file-download-command-contribution.js.map +1 -0
  34. package/lib/browser-only/download/file-download-frontend-module.d.ts +4 -0
  35. package/lib/browser-only/download/file-download-frontend-module.d.ts.map +1 -0
  36. package/lib/browser-only/download/file-download-frontend-module.js +27 -0
  37. package/lib/browser-only/download/file-download-frontend-module.js.map +1 -0
  38. package/lib/browser-only/download/file-download-service.d.ts +86 -0
  39. package/lib/browser-only/download/file-download-service.d.ts.map +1 -0
  40. package/lib/browser-only/download/file-download-service.js +551 -0
  41. package/lib/browser-only/download/file-download-service.js.map +1 -0
  42. package/lib/browser-only/file-search.d.ts +38 -0
  43. package/lib/browser-only/file-search.d.ts.map +1 -0
  44. package/lib/browser-only/file-search.js +153 -0
  45. package/lib/browser-only/file-search.js.map +1 -0
  46. package/lib/browser-only/opfs-filesystem-initialization.d.ts +4 -2
  47. package/lib/browser-only/opfs-filesystem-initialization.d.ts.map +1 -1
  48. package/lib/browser-only/opfs-filesystem-initialization.js +4 -1
  49. package/lib/browser-only/opfs-filesystem-initialization.js.map +1 -1
  50. package/lib/browser-only/opfs-filesystem-provider.d.ts +89 -12
  51. package/lib/browser-only/opfs-filesystem-provider.d.ts.map +1 -1
  52. package/lib/browser-only/opfs-filesystem-provider.js +345 -181
  53. package/lib/browser-only/opfs-filesystem-provider.js.map +1 -1
  54. package/lib/browser-only/upload/file-upload-service-impl.d.ts +67 -0
  55. package/lib/browser-only/upload/file-upload-service-impl.d.ts.map +1 -0
  56. package/lib/browser-only/upload/file-upload-service-impl.js +328 -0
  57. package/lib/browser-only/upload/file-upload-service-impl.js.map +1 -0
  58. package/lib/common/download/file-download.d.ts +17 -0
  59. package/lib/common/download/file-download.d.ts.map +1 -0
  60. package/lib/common/download/{file-download-data.js → file-download.js} +3 -2
  61. package/lib/common/download/file-download.js.map +1 -0
  62. package/lib/common/files.d.ts +8 -1
  63. package/lib/common/files.d.ts.map +1 -1
  64. package/lib/common/files.js +35 -1
  65. package/lib/common/files.js.map +1 -1
  66. package/lib/common/io.js +7 -1
  67. package/lib/common/io.js.map +1 -1
  68. package/lib/common/upload/file-upload.d.ts +45 -0
  69. package/lib/common/upload/file-upload.d.ts.map +1 -0
  70. package/{src/common/download/file-download-data.ts → lib/common/upload/file-upload.js} +6 -13
  71. package/lib/common/upload/file-upload.js.map +1 -0
  72. package/lib/node/disk-file-system-provider.d.ts.map +1 -1
  73. package/lib/node/disk-file-system-provider.js +2 -4
  74. package/lib/node/disk-file-system-provider.js.map +1 -1
  75. package/lib/node/download/file-download-handler.js +2 -2
  76. package/lib/node/download/file-download-handler.js.map +1 -1
  77. package/lib/node/filesystem-backend-module.js +1 -1
  78. package/lib/node/filesystem-backend-module.js.map +1 -1
  79. package/lib/node/parcel-watcher/parcel-filesystem-service.d.ts +2 -2
  80. package/lib/node/parcel-watcher/parcel-filesystem-service.d.ts.map +1 -1
  81. package/lib/node/parcel-watcher/parcel-filesystem-service.js.map +1 -1
  82. package/lib/node/upload/node-file-upload-service.d.ts.map +1 -0
  83. package/lib/node/{node-file-upload-service.js → upload/node-file-upload-service.js} +1 -1
  84. package/lib/node/upload/node-file-upload-service.js.map +1 -0
  85. package/package.json +10 -5
  86. package/src/browser/download/file-download-command-contribution.ts +1 -1
  87. package/src/browser/download/file-download-frontend-module.ts +3 -2
  88. package/src/browser/download/file-download-service.ts +7 -12
  89. package/src/browser/file-tree/file-tree-widget.tsx +1 -1
  90. package/src/browser/filesystem-frontend-contribution.ts +2 -2
  91. package/src/browser/filesystem-frontend-module.ts +3 -2
  92. package/src/browser/{file-upload-service.ts → upload/file-upload-service-impl.ts} +31 -72
  93. package/src/browser-only/browser-only-filesystem-frontend-module.ts +10 -0
  94. package/src/browser-only/download/file-download-command-contribution.ts +56 -0
  95. package/src/browser-only/download/file-download-frontend-module.ts +26 -0
  96. package/src/browser-only/download/file-download-service.ts +726 -0
  97. package/src/browser-only/file-search.ts +170 -0
  98. package/src/browser-only/opfs-filesystem-initialization.ts +7 -4
  99. package/src/browser-only/opfs-filesystem-provider.ts +402 -189
  100. package/src/browser-only/upload/file-upload-service-impl.ts +408 -0
  101. package/src/common/download/file-download.ts +40 -0
  102. package/src/common/files.ts +42 -1
  103. package/src/common/io.ts +6 -1
  104. package/src/common/upload/file-upload.ts +65 -0
  105. package/src/node/disk-file-system-provider.ts +3 -4
  106. package/src/node/download/file-download-handler.ts +1 -1
  107. package/src/node/filesystem-backend-module.ts +1 -1
  108. package/src/node/parcel-watcher/parcel-filesystem-service.ts +2 -2
  109. package/src/node/{node-file-upload-service.ts → upload/node-file-upload-service.ts} +1 -1
  110. package/lib/browser/file-upload-service.d.ts.map +0 -1
  111. package/lib/browser/file-upload-service.js.map +0 -1
  112. package/lib/common/download/file-download-data.d.ts +0 -7
  113. package/lib/common/download/file-download-data.d.ts.map +0 -1
  114. package/lib/common/download/file-download-data.js.map +0 -1
  115. package/lib/node/node-file-upload-service.d.ts.map +0 -1
  116. package/lib/node/node-file-upload-service.js.map +0 -1
  117. /package/lib/node/{node-file-upload-service.d.ts → upload/node-file-upload-service.d.ts} +0 -0
package/package.json CHANGED
@@ -1,20 +1,24 @@
1
1
  {
2
2
  "name": "@theia/filesystem",
3
- "version": "1.65.0-next.55+d141c3601",
3
+ "version": "1.65.0",
4
4
  "description": "Theia - FileSystem Extension",
5
5
  "dependencies": {
6
- "@theia/core": "1.65.0-next.55+d141c3601",
6
+ "@theia/core": "1.65.0",
7
7
  "@types/body-parser": "^1.17.0",
8
8
  "@types/multer": "^1.4.7",
9
9
  "@types/tar-fs": "^1.16.1",
10
+ "@types/tar-stream": "^3.1.4",
10
11
  "async-mutex": "^0.3.1",
11
12
  "body-parser": "^1.18.3",
12
13
  "http-status-codes": "^1.3.0",
13
- "minimatch": "^5.1.0",
14
+ "ignore": "^6.0.0",
15
+ "minimatch": "^10.0.3",
14
16
  "multer": "^2.0.1",
17
+ "opfs-worker": "1.3.1",
15
18
  "rimraf": "^5.0.0",
16
19
  "stat-mode": "^1.0.0",
17
20
  "tar-fs": "^3.0.9",
21
+ "tar-stream": "^3.1.7",
18
22
  "trash": "^7.2.0",
19
23
  "tslib": "^2.6.2",
20
24
  "vscode-languageserver-textdocument": "^1.0.1"
@@ -37,6 +41,7 @@
37
41
  },
38
42
  {
39
43
  "frontend": "lib/browser/download/file-download-frontend-module",
44
+ "frontendOnly": "lib/browser-only/download/file-download-frontend-module",
40
45
  "backend": "lib/node/download/file-download-backend-module"
41
46
  },
42
47
  {
@@ -72,10 +77,10 @@
72
77
  "watch": "theiaext watch"
73
78
  },
74
79
  "devDependencies": {
75
- "@theia/ext-scripts": "1.64.0"
80
+ "@theia/ext-scripts": "1.65.0"
76
81
  },
77
82
  "nyc": {
78
83
  "extends": "../../configs/nyc.json"
79
84
  },
80
- "gitHead": "d141c3601e8c3d9cd254468790fed3566aa23305"
85
+ "gitHead": "500dfc80cee94fd2a623b5fb59b22d5a575247c2"
81
86
  }
@@ -21,7 +21,7 @@ import { environment } from '@theia/core/shared/@theia/application-package/lib/e
21
21
  import { SelectionService } from '@theia/core/lib/common/selection-service';
22
22
  import { Command, CommandContribution, CommandRegistry } from '@theia/core/lib/common/command';
23
23
  import { UriAwareCommandHandler } from '@theia/core/lib/common/uri-command-handler';
24
- import { FileDownloadService } from './file-download-service';
24
+ import { FileDownloadService } from '../../common/download/file-download';
25
25
  import { CommonCommands } from '@theia/core/lib/browser';
26
26
 
27
27
  @injectable()
@@ -16,10 +16,11 @@
16
16
 
17
17
  import { ContainerModule } from '@theia/core/shared/inversify';
18
18
  import { CommandContribution } from '@theia/core/lib/common/command';
19
- import { FileDownloadService } from './file-download-service';
19
+ import { FileDownloadService } from '../../common/download/file-download';
20
+ import { FileDownloadServiceImpl } from './file-download-service';
20
21
  import { FileDownloadCommandContribution } from './file-download-command-contribution';
21
22
 
22
23
  export default new ContainerModule(bind => {
23
- bind(FileDownloadService).toSelf().inSingletonScope();
24
+ bind(FileDownloadService).to(FileDownloadServiceImpl).inSingletonScope();
24
25
  bind(CommandContribution).to(FileDownloadCommandContribution).inSingletonScope();
25
26
  });
@@ -14,22 +14,23 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { inject, injectable } from '@theia/core/shared/inversify';
17
+ import { inject, injectable, named } from '@theia/core/shared/inversify';
18
18
  import URI from '@theia/core/lib/common/uri';
19
19
  import { ILogger } from '@theia/core/lib/common/logger';
20
20
  import { Endpoint } from '@theia/core/lib/browser/endpoint';
21
- import { FileDownloadData } from '../../common/download/file-download-data';
22
21
  import { MessageService } from '@theia/core/lib/common/message-service';
23
22
  import { addClipboardListener } from '@theia/core/lib/browser/widgets';
24
23
  import { nls } from '@theia/core';
24
+ import type { FileDownloadData, FileDownloadService } from '../../common/download/file-download';
25
25
 
26
26
  @injectable()
27
- export class FileDownloadService {
27
+ export class FileDownloadServiceImpl implements FileDownloadService {
28
28
 
29
29
  protected anchor: HTMLAnchorElement | undefined;
30
30
  protected downloadCounter: number = 0;
31
31
 
32
32
  @inject(ILogger)
33
+ @named('file-download')
33
34
  protected readonly logger: ILogger;
34
35
 
35
36
  @inject(MessageService)
@@ -49,10 +50,13 @@ export class FileDownloadService {
49
50
 
50
51
  async download(uris: URI[], options?: FileDownloadService.DownloadOptions): Promise<void> {
51
52
  let cancel = false;
53
+
52
54
  if (uris.length === 0) {
53
55
  return;
54
56
  }
57
+
55
58
  const copyLink = options && options.copyLink ? true : false;
59
+
56
60
  try {
57
61
  const text: string = copyLink ?
58
62
  nls.localize('theia/filesystem/prepareDownloadLink', 'Preparing download link...') :
@@ -168,12 +172,3 @@ export class FileDownloadService {
168
172
  }
169
173
 
170
174
  }
171
-
172
- export namespace FileDownloadService {
173
- export interface DownloadOptions {
174
- /**
175
- * `true` if the download link has to be copied to the clipboard. This will not trigger the actual download. Defaults to `false`.
176
- */
177
- readonly copyLink?: boolean;
178
- }
179
- }
@@ -21,13 +21,13 @@ import URI from '@theia/core/lib/common/uri';
21
21
  import { UriSelection } from '@theia/core/lib/common/selection';
22
22
  import { isCancelled } from '@theia/core/lib/common/cancellation';
23
23
  import { ContextMenuRenderer, NodeProps, TreeProps, TreeNode, CompositeTreeNode, CompressedTreeWidget, CompressedNodeProps } from '@theia/core/lib/browser';
24
- import { FileUploadService } from '../file-upload-service';
25
24
  import { DirNode, FileStatNode, FileStatNodeData } from './file-tree';
26
25
  import { FileTreeModel } from './file-tree-model';
27
26
  import { IconThemeService } from '@theia/core/lib/browser/icon-theme-service';
28
27
  import { ApplicationShell } from '@theia/core/lib/browser/shell';
29
28
  import { FileStat, FileType } from '../../common/files';
30
29
  import { isOSX } from '@theia/core';
30
+ import { FileUploadService } from '../../common/upload/file-upload';
31
31
 
32
32
  export const FILE_TREE_CLASS = 'theia-FileTree';
33
33
  export const FILE_STAT_NODE_CLASS = 'theia-FileStatNode';
@@ -41,8 +41,8 @@ import { FileChangeType, FileChangesEvent, FileOperation } from '../common/files
41
41
  import { FileDialogService, SaveFileDialogProps } from './file-dialog';
42
42
  import { FileSelection } from './file-selection';
43
43
  import { FileService, UserFileOperationEvent } from './file-service';
44
- import { FileUploadResult, FileUploadService } from './file-upload-service';
45
44
  import { FileSystemPreferences } from '../common/filesystem-preferences';
45
+ import { FileUploadService } from '../common/upload/file-upload';
46
46
 
47
47
  export namespace FileSystemCommands {
48
48
 
@@ -161,7 +161,7 @@ export class FileSystemFrontendContribution implements FrontendApplicationContri
161
161
  });
162
162
  }
163
163
 
164
- protected async upload(selection: FileSelection): Promise<FileUploadResult | undefined> {
164
+ protected async upload(selection: FileSelection): Promise<FileUploadService.UploadResult | undefined> {
165
165
  try {
166
166
  const source = TreeWidgetSelection.getSource(this.selectionService.selection);
167
167
  const fileUploadResult = await this.uploadService.upload(selection.fileStat.isDirectory ? selection.fileStat.resource : selection.fileStat.resource.parent);
@@ -22,7 +22,6 @@ import { WebSocketConnectionProvider, FrontendApplicationContribution, LabelProv
22
22
  import { FileResourceResolver } from './file-resource';
23
23
  import { bindFileSystemPreferences } from '../common/filesystem-preferences';
24
24
  import { FileSystemFrontendContribution } from './filesystem-frontend-contribution';
25
- import { FileUploadService } from './file-upload-service';
26
25
  import { FileTreeDecoratorAdapter, FileTreeLabelProvider } from './file-tree';
27
26
  import { FileService, FileServiceContribution } from './file-service';
28
27
  import { RemoteFileSystemProvider, RemoteFileSystemServer, remoteFileSystemPath, RemoteFileSystemProxyFactory } from '../common/remote-file-system-provider';
@@ -34,6 +33,8 @@ import { BreadcrumbsFileTreeWidget, createFileTreeBreadcrumbsWidget } from './br
34
33
  import { FilesystemSaveableService } from './filesystem-saveable-service';
35
34
  import { SaveableService } from '@theia/core/lib/browser/saveable-service';
36
35
  import { VSCodeFileServiceContribution, VSCodeFileSystemProvider } from './vscode-file-service-contribution';
36
+ import { FileUploadService } from '../common/upload/file-upload';
37
+ import { FileUploadServiceImpl } from './upload/file-upload-service-impl';
37
38
 
38
39
  export default new ContainerModule((bind, unbind, isBound, rebind) => {
39
40
  bindFileSystemPreferences(bind);
@@ -55,7 +56,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
55
56
 
56
57
  bindFileResource(bind);
57
58
 
58
- bind(FileUploadService).toSelf().inSingletonScope();
59
+ bind(FileUploadService).to(FileUploadServiceImpl).inSingletonScope();
59
60
 
60
61
  bind(FileSystemFrontendContribution).toSelf().inSingletonScope();
61
62
  bind(CommandContribution).toService(FileSystemFrontendContribution);
@@ -24,41 +24,27 @@ import { MessageService } from '@theia/core/lib/common/message-service';
24
24
  import { Progress } from '@theia/core/lib/common/message-service-protocol';
25
25
  import { Endpoint } from '@theia/core/lib/browser/endpoint';
26
26
  import throttle = require('@theia/core/shared/lodash.throttle');
27
- import { HTTP_FILE_UPLOAD_PATH } from '../common/file-upload';
27
+ import { HTTP_FILE_UPLOAD_PATH } from '../../common/file-upload';
28
28
  import { Semaphore } from 'async-mutex';
29
- import { FileSystemPreferences } from '../common/filesystem-preferences';
30
- import { FileService } from './file-service';
29
+ import { FileSystemPreferences } from '../../common/filesystem-preferences';
30
+ import { FileService } from '../file-service';
31
31
  import { ConfirmDialog, Dialog } from '@theia/core/lib/browser';
32
32
  import { nls } from '@theia/core/lib/common/nls';
33
33
  import { Emitter, Event } from '@theia/core/lib/common/event';
34
-
35
- export const HTTP_UPLOAD_URL: string = new Endpoint({ path: HTTP_FILE_UPLOAD_PATH }).getRestUrl().toString(true);
36
-
37
- export type CustomDataTransfer = Iterable<readonly [string, CustomDataTransferItem]>;
38
-
39
- export interface CustomDataTransferItem {
40
- asFile(): {
41
- readonly id: string;
42
- readonly name: string;
43
- data(): Promise<Uint8Array>;
44
- } | undefined
45
- }
46
- export interface FileUploadParams {
47
- source?: DataTransfer | CustomDataTransfer
48
- progress?: FileUploadProgressParams
49
- onDidUpload?: (uri: string) => void;
50
- leaveInTemp?: boolean // dont move file out of the initial tmp directory
51
- }
52
- export interface FileUploadProgressParams {
53
- text: string
34
+ import type { CustomDataTransfer, FileUploadService } from '../../common/upload/file-upload';
35
+
36
+ interface UploadFilesParams {
37
+ source: FileUploadService.Source,
38
+ progress: Progress,
39
+ token: CancellationToken,
40
+ leaveInTemp?: boolean,
41
+ onDidUpload?: (uri: string) => void,
54
42
  }
55
43
 
56
- export interface FileUploadResult {
57
- uploaded: string[]
58
- }
44
+ export const HTTP_UPLOAD_URL: string = new Endpoint({ path: HTTP_FILE_UPLOAD_PATH }).getRestUrl().toString(true);
59
45
 
60
46
  @injectable()
61
- export class FileUploadService {
47
+ export class FileUploadServiceImpl implements FileUploadService {
62
48
 
63
49
  static TARGET = 'target';
64
50
  static UPLOAD = 'upload';
@@ -70,7 +56,7 @@ export class FileUploadService {
70
56
  }
71
57
 
72
58
  protected uploadForm: FileUploadService.Form;
73
- protected deferredUpload?: Deferred<FileUploadResult>;
59
+ protected deferredUpload?: Deferred<FileUploadService.UploadResult>;
74
60
 
75
61
  @inject(MessageService)
76
62
  protected readonly messageService: MessageService;
@@ -95,13 +81,13 @@ export class FileUploadService {
95
81
  const targetInput = document.createElement('input');
96
82
  targetInput.type = 'text';
97
83
  targetInput.spellcheck = false;
98
- targetInput.name = FileUploadService.TARGET;
84
+ targetInput.name = FileUploadServiceImpl.TARGET;
99
85
  targetInput.classList.add('theia-input');
100
86
 
101
87
  const fileInput = document.createElement('input');
102
88
  fileInput.type = 'file';
103
89
  fileInput.classList.add('theia-input');
104
- fileInput.name = FileUploadService.UPLOAD;
90
+ fileInput.name = FileUploadServiceImpl.UPLOAD;
105
91
  fileInput.multiple = true;
106
92
 
107
93
  const form = document.createElement('form');
@@ -117,34 +103,32 @@ export class FileUploadService {
117
103
  const source: FileUploadService.Source = new FormData(form);
118
104
  // clean up to allow upload to the same folder twice
119
105
  fileInput.value = '';
120
- const targetUri = new URI(<string>source.get(FileUploadService.TARGET));
106
+ const targetUri = new URI(<string>source.get(FileUploadServiceImpl.TARGET));
121
107
  const { resolve, reject } = this.deferredUpload;
122
108
  this.deferredUpload = undefined;
123
109
  const { onDidUpload } = this.uploadForm;
124
110
  this.withProgress(
125
- (progress, token) => this.uploadAll(targetUri, { source, progress, token, onDidUpload }),
126
- this.uploadForm.progress
111
+ (progress, token) => this.uploadAll(targetUri, { source, progress, token, onDidUpload })
127
112
  ).then(resolve, reject);
128
113
  }
129
114
  });
130
115
  return { targetInput, fileInput };
131
116
  }
132
117
 
133
- async upload(targetUri: string | URI, params: FileUploadParams = {}): Promise<FileUploadResult> {
134
- const { source, onDidUpload, leaveInTemp } = params;
118
+ async upload(targetUri: string | URI, params: FileUploadService.UploadParams): Promise<FileUploadService.UploadResult> {
119
+ const { source, onDidUpload, leaveInTemp } = params || {};
120
+
135
121
  if (source) {
136
122
  return this.withProgress(
137
123
  (progress, token) => this.uploadAll(
138
124
  typeof targetUri === 'string' ? new URI(targetUri) : targetUri,
139
125
  { source, progress, token, leaveInTemp, onDidUpload }
140
- ),
141
- params.progress,
126
+ )
142
127
  );
143
128
  }
144
- this.deferredUpload = new Deferred<FileUploadResult>();
129
+ this.deferredUpload = new Deferred<FileUploadService.UploadResult>();
145
130
  this.uploadForm.targetInput.value = String(targetUri);
146
131
  this.uploadForm.fileInput.click();
147
- this.uploadForm.progress = params.progress;
148
132
  this.uploadForm.onDidUpload = params.onDidUpload;
149
133
  return this.deferredUpload.promise;
150
134
  }
@@ -153,14 +137,14 @@ export class FileUploadService {
153
137
  return HTTP_UPLOAD_URL;
154
138
  }
155
139
 
156
- protected async uploadAll(targetUri: URI, params: FileUploadService.UploadParams): Promise<FileUploadResult> {
140
+ protected async uploadAll(targetUri: URI, params: UploadFilesParams): Promise<FileUploadService.UploadResult> {
157
141
  const responses: Promise<void>[] = [];
158
142
  const status = new Map<File, {
159
143
  total: number
160
144
  done: number
161
145
  uploaded?: boolean
162
146
  }>();
163
- const result: FileUploadResult = {
147
+ const result: FileUploadService.UploadResult = {
164
148
  uploaded: []
165
149
  };
166
150
  /**
@@ -351,7 +335,7 @@ export class FileUploadService {
351
335
  resolve();
352
336
  } else if (xhr.status === 500 && xhr.statusText !== xhr.response) {
353
337
  // internal error with cause message
354
- // see packages/filesystem/src/node/node-file-upload-service.ts
338
+ // see packages/filesystem/src/node/upload/node-file-upload-service.ts
355
339
  reject(new Error(`Internal server error: ${xhr.response}`));
356
340
  } else {
357
341
  reject(new Error(`POST request failed: ${xhr.status} ${xhr.statusText}`));
@@ -387,11 +371,11 @@ export class FileUploadService {
387
371
  }
388
372
 
389
373
  protected async withProgress<T>(
390
- cb: (progress: Progress, token: CancellationToken) => Promise<T>,
391
- { text }: FileUploadProgressParams = { text: nls.localize('theia/filesystem/uploadFiles', 'Uploading Files') }
374
+ cb: (progress: Progress, token: CancellationToken) => Promise<T>
392
375
  ): Promise<T> {
393
376
  const cancellationSource = new CancellationTokenSource();
394
377
  const { token } = cancellationSource;
378
+ const text = nls.localize('theia/filesystem/uploadFiles', 'Uploading Files');
395
379
  const progress = await this.messageService.showProgress(
396
380
  { text, options: { cancelable: true } },
397
381
  () => cancellationSource.cancel()
@@ -414,7 +398,7 @@ export class FileUploadService {
414
398
  }
415
399
 
416
400
  protected async indexFormData(targetUri: URI, formData: FormData, context: FileUploadService.Context): Promise<void> {
417
- for (const entry of formData.getAll(FileUploadService.UPLOAD)) {
401
+ for (const entry of formData.getAll(FileUploadServiceImpl.UPLOAD)) {
418
402
  if (entry instanceof File) {
419
403
  await this.indexFile(targetUri, entry, context);
420
404
  }
@@ -433,8 +417,9 @@ export class FileUploadService {
433
417
  protected async indexCustomDataTransfer(targetUri: URI, dataTransfer: CustomDataTransfer, context: FileUploadService.Context): Promise<void> {
434
418
  for (const [_, item] of dataTransfer) {
435
419
  const fileInfo = item.asFile();
420
+
436
421
  if (fileInfo) {
437
- await this.indexFile(targetUri, new File([await fileInfo.data()], fileInfo.id), context);
422
+ await this.indexFile(targetUri, new File([await fileInfo.data() as BlobPart], fileInfo.id), context);
438
423
  }
439
424
  }
440
425
  }
@@ -524,29 +509,3 @@ export class FileUploadService {
524
509
  }
525
510
 
526
511
  }
527
-
528
- export namespace FileUploadService {
529
- export type Source = FormData | DataTransfer | CustomDataTransfer;
530
- export interface UploadEntry {
531
- file: File
532
- uri: URI
533
- }
534
- export interface Context {
535
- progress: Progress
536
- token: CancellationToken
537
- accept: (entry: UploadEntry) => Promise<void>
538
- }
539
- export interface Form {
540
- targetInput: HTMLInputElement
541
- fileInput: HTMLInputElement
542
- progress?: FileUploadProgressParams
543
- onDidUpload?: (uri: string) => void
544
- }
545
- export interface UploadParams {
546
- source: FileUploadService.Source,
547
- progress: Progress,
548
- token: CancellationToken,
549
- onDidUpload?: (uri: string) => void,
550
- leaveInTemp?: boolean
551
- }
552
- }
@@ -20,16 +20,26 @@ import { OPFSFileSystemProvider } from './opfs-filesystem-provider';
20
20
  import { RemoteFileSystemProvider, RemoteFileSystemServer } from '../common/remote-file-system-provider';
21
21
  import { OPFSInitialization, DefaultOPFSInitialization } from './opfs-filesystem-initialization';
22
22
  import { BrowserOnlyFileSystemProviderServer } from './browser-only-filesystem-provider-server';
23
+ import { FileUploadService } from '../common/upload/file-upload';
24
+ import { FileUploadServiceImpl } from './upload/file-upload-service-impl';
23
25
 
24
26
  export default new ContainerModule((bind, _unbind, isBound, rebind) => {
25
27
  bind(DefaultOPFSInitialization).toSelf();
26
28
  bind(OPFSFileSystemProvider).toSelf();
27
29
  bind(OPFSInitialization).toService(DefaultOPFSInitialization);
30
+
31
+ if (isBound(FileUploadService)) {
32
+ rebind(FileUploadService).to(FileUploadServiceImpl).inSingletonScope();
33
+ } else {
34
+ bind(FileUploadService).to(FileUploadServiceImpl).inSingletonScope();
35
+ }
36
+
28
37
  if (isBound(FileSystemProvider)) {
29
38
  rebind(FileSystemProvider).to(OPFSFileSystemProvider).inSingletonScope();
30
39
  } else {
31
40
  bind(FileSystemProvider).to(OPFSFileSystemProvider).inSingletonScope();
32
41
  }
42
+
33
43
  if (isBound(RemoteFileSystemProvider)) {
34
44
  rebind(RemoteFileSystemServer).to(BrowserOnlyFileSystemProviderServer).inSingletonScope();
35
45
  } else {
@@ -0,0 +1,56 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2025 Maksim Kachurin and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { inject, injectable } from '@theia/core/shared/inversify';
18
+ import URI from '@theia/core/lib/common/uri';
19
+ import { SelectionService } from '@theia/core/lib/common/selection-service';
20
+ import { CommandContribution, CommandRegistry } from '@theia/core/lib/common/command';
21
+ import { UriAwareCommandHandler } from '@theia/core/lib/common/uri-command-handler';
22
+ import { FileDownloadService } from '../../common/download/file-download';
23
+ import { FileDownloadCommands } from '../../browser/download/file-download-command-contribution';
24
+
25
+ @injectable()
26
+ export class FileDownloadCommandContribution implements CommandContribution {
27
+
28
+ @inject(FileDownloadService)
29
+ protected readonly downloadService: FileDownloadService;
30
+
31
+ @inject(SelectionService)
32
+ protected readonly selectionService: SelectionService;
33
+
34
+ registerCommands(registry: CommandRegistry): void {
35
+ registry.registerCommand(
36
+ FileDownloadCommands.DOWNLOAD,
37
+ UriAwareCommandHandler.MultiSelect(this.selectionService, {
38
+ execute: uris => this.executeDownload(uris),
39
+ isEnabled: uris => this.isDownloadEnabled(uris),
40
+ isVisible: uris => this.isDownloadVisible(uris),
41
+ })
42
+ );
43
+ }
44
+
45
+ protected async executeDownload(uris: URI[], options?: { copyLink?: boolean }): Promise<void> {
46
+ this.downloadService.download(uris, options);
47
+ }
48
+
49
+ protected isDownloadEnabled(uris: URI[]): boolean {
50
+ return uris.length > 0 && uris.every(u => u.scheme === 'file');
51
+ }
52
+
53
+ protected isDownloadVisible(uris: URI[]): boolean {
54
+ return this.isDownloadEnabled(uris);
55
+ }
56
+ }
@@ -0,0 +1,26 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2025 Maksim Kachurin and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { ContainerModule } from '@theia/core/shared/inversify';
18
+ import { FileDownloadService } from '../../common/download/file-download';
19
+ import { FileDownloadServiceImpl } from './file-download-service';
20
+ import { CommandContribution } from '@theia/core/lib/common';
21
+ import { FileDownloadCommandContribution } from './file-download-command-contribution';
22
+
23
+ export default new ContainerModule(bind => {
24
+ bind(FileDownloadService).to(FileDownloadServiceImpl).inSingletonScope();
25
+ bind(CommandContribution).to(FileDownloadCommandContribution).inSingletonScope();
26
+ });