Skip to content

Commit 72df8c1

Browse files
author
Akos Kitta
committed
fix: local sketch deletion + rename
Ref: #1825 Signed-off-by: Akos Kitta <[email protected]>
1 parent 2aea3df commit 72df8c1

File tree

7 files changed

+157
-107
lines changed

7 files changed

+157
-107
lines changed

Diff for: arduino-ide-extension/src/browser/contributions/sketch-control.ts

+6-51
Original file line numberDiff line numberDiff line change
@@ -18,33 +18,19 @@ import {
1818
open,
1919
} from './contribution';
2020
import { ArduinoMenus, PlaceholderMenuNode } from '../menu/arduino-menus';
21-
import { EditorManager } from '@theia/editor/lib/browser/editor-manager';
22-
import {
23-
CurrentSketch,
24-
SketchesServiceClientImpl,
25-
} from '../../common/protocol/sketches-service-client-impl';
26-
import { LocalCacheFsProvider } from '../local-cache/local-cache-fs-provider';
21+
import { CurrentSketch } from '../../common/protocol/sketches-service-client-impl';
2722
import { nls } from '@theia/core/lib/common';
2823

2924
@injectable()
3025
export class SketchControl extends SketchContribution {
3126
@inject(ApplicationShell)
32-
protected readonly shell: ApplicationShell;
27+
private readonly shell: ApplicationShell;
3328

3429
@inject(MenuModelRegistry)
35-
protected readonly menuRegistry: MenuModelRegistry;
30+
private readonly menuRegistry: MenuModelRegistry;
3631

3732
@inject(ContextMenuRenderer)
38-
protected readonly contextMenuRenderer: ContextMenuRenderer;
39-
40-
@inject(EditorManager)
41-
protected override readonly editorManager: EditorManager;
42-
43-
@inject(SketchesServiceClientImpl)
44-
protected readonly sketchesServiceClient: SketchesServiceClientImpl;
45-
46-
@inject(LocalCacheFsProvider)
47-
protected readonly localCacheFsProvider: LocalCacheFsProvider;
33+
private readonly contextMenuRenderer: ContextMenuRenderer;
4834

4935
protected readonly toDisposeBeforeCreateNewContextMenu =
5036
new DisposableCollection();
@@ -84,12 +70,7 @@ export class SketchControl extends SketchContribution {
8470
);
8571

8672
// if the current file is in the current opened sketch, show extra menus
87-
if (
88-
sketch &&
89-
parentSketch &&
90-
parentSketch.uri === sketch.uri &&
91-
this.allowRename(parentSketch.uri)
92-
) {
73+
if (sketch && parentSketch && parentSketch.uri === sketch.uri) {
9374
this.menuRegistry.registerMenuAction(
9475
ArduinoMenus.SKETCH_CONTROL__CONTEXT__MAIN_GROUP,
9576
{
@@ -121,12 +102,7 @@ export class SketchControl extends SketchContribution {
121102
);
122103
}
123104

124-
if (
125-
sketch &&
126-
parentSketch &&
127-
parentSketch.uri === sketch.uri &&
128-
this.allowDelete(parentSketch.uri)
129-
) {
105+
if (sketch && parentSketch && parentSketch.uri === sketch.uri) {
130106
this.menuRegistry.registerMenuAction(
131107
ArduinoMenus.SKETCH_CONTROL__CONTEXT__MAIN_GROUP,
132108
{
@@ -249,27 +225,6 @@ export class SketchControl extends SketchContribution {
249225
command: SketchControl.Commands.OPEN_SKETCH_CONTROL__TOOLBAR.id,
250226
});
251227
}
252-
253-
protected isCloudSketch(uri: string): boolean {
254-
try {
255-
const cloudCacheLocation = this.localCacheFsProvider.from(new URI(uri));
256-
257-
if (cloudCacheLocation) {
258-
return true;
259-
}
260-
return false;
261-
} catch {
262-
return false;
263-
}
264-
}
265-
266-
protected allowRename(uri: string): boolean {
267-
return !this.isCloudSketch(uri);
268-
}
269-
270-
protected allowDelete(uri: string): boolean {
271-
return !this.isCloudSketch(uri);
272-
}
273228
}
274229

275230
export namespace SketchControl {

Diff for: arduino-ide-extension/src/browser/create/create-api.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export namespace ResponseResultProvider {
1515
export const JSON: ResponseResultProvider = (response) => response.json();
1616
}
1717

18+
// TODO: check if this is still needed: https://github.com/electron/electron/issues/18733
19+
// The original issue was reported for Electron 5.x and 6.x. Theia uses 15.x
1820
export function Utf8ArrayToStr(array: Uint8Array): string {
1921
let out, i, c;
2022
let char2, char3;
@@ -381,7 +383,7 @@ export class CreateApi {
381383
return;
382384
}
383385

384-
// do not upload "do_not_sync" files/directoris and their descendants
386+
// do not upload "do_not_sync" files/directories and their descendants
385387
const segments = posixPath.split(posix.sep) || [];
386388
if (
387389
segments.some((segment) => Create.do_not_sync_files.includes(segment))
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,28 @@
1-
import { inject, injectable } from '@theia/core/shared/inversify';
1+
import type { Widget } from '@phosphor/widgets';
22
import * as remote from '@theia/core/electron-shared/@electron/remote';
3+
import { Dialog } from '@theia/core/lib/browser/dialogs';
4+
import { NavigatableWidget } from '@theia/core/lib/browser/navigatable-types';
5+
import { WindowService } from '@theia/core/lib/browser/window/window-service';
6+
import { nls } from '@theia/core/lib/common';
7+
import type { MaybeArray } from '@theia/core/lib/common/types';
38
import URI from '@theia/core/lib/common/uri';
9+
import { inject, injectable } from '@theia/core/shared/inversify';
410
import { WorkspaceDeleteHandler as TheiaWorkspaceDeleteHandler } from '@theia/workspace/lib/browser/workspace-delete-handler';
11+
import { SketchesService } from '../../../common/protocol';
512
import {
613
CurrentSketch,
714
SketchesServiceClientImpl,
815
} from '../../../common/protocol/sketches-service-client-impl';
9-
import { nls } from '@theia/core/lib/common';
16+
import { Sketch } from '../../contributions/contribution';
1017

1118
@injectable()
1219
export class WorkspaceDeleteHandler extends TheiaWorkspaceDeleteHandler {
20+
@inject(WindowService)
21+
private readonly windowService: WindowService;
22+
@inject(SketchesService)
23+
private readonly sketchesService: SketchesService;
1324
@inject(SketchesServiceClientImpl)
14-
protected readonly sketchesServiceClient: SketchesServiceClientImpl;
25+
private readonly sketchesServiceClient: SketchesServiceClientImpl;
1526

1627
override async execute(uris: URI[]): Promise<void> {
1728
const sketch = await this.sketchesServiceClient.currentSketch();
@@ -27,29 +38,48 @@ export class WorkspaceDeleteHandler extends TheiaWorkspaceDeleteHandler {
2738
const { response } = await remote.dialog.showMessageBox({
2839
title: nls.localize('vscode/fileActions/delete', 'Delete'),
2940
type: 'question',
30-
buttons: [
31-
nls.localize('vscode/issueMainService/cancel', 'Cancel'),
32-
nls.localize('vscode/issueMainService/ok', 'OK'),
33-
],
41+
buttons: [Dialog.CANCEL, Dialog.OK],
3442
message: nls.localize(
3543
'theia/workspace/deleteCurrentSketch',
3644
'Do you want to delete the current sketch?'
3745
),
3846
});
3947
if (response === 1) {
4048
// OK
41-
await Promise.all(
42-
[
43-
...sketch.additionalFileUris,
44-
...sketch.otherSketchFileUris,
45-
sketch.mainFileUri,
46-
].map((uri) => this.closeWithoutSaving(new URI(uri)))
47-
);
48-
await this.fileService.delete(new URI(sketch.uri));
49-
window.close();
49+
await Promise.all([
50+
...Sketch.uris(sketch).map((uri) =>
51+
this.closeWithoutSaving(new URI(uri))
52+
),
53+
]);
54+
this.windowService.setSafeToShutDown();
55+
this.sketchesService.deleteSketch(sketch);
56+
return window.close();
5057
}
51-
return;
5258
}
5359
return super.execute(uris);
5460
}
61+
62+
// https://github.com/eclipse-theia/theia/issues/12107
63+
protected override async closeWithoutSaving(uri: URI): Promise<void> {
64+
const affected = getAffected(this.shell.widgets, uri);
65+
const toClose = [...affected].map(([, widget]) => widget);
66+
await this.shell.closeMany(toClose, { save: false });
67+
}
68+
}
69+
70+
export function getAffected<T extends Widget>(
71+
widgets: Iterable<T>,
72+
context: MaybeArray<URI>
73+
): [URI, T & NavigatableWidget][] {
74+
const uris = Array.isArray(context) ? context : [context];
75+
const result: [URI, T & NavigatableWidget][] = [];
76+
for (const widget of widgets) {
77+
if (NavigatableWidget.is(widget)) {
78+
const resourceUri = widget.getResourceUri();
79+
if (resourceUri && uris.some((uri) => uri.isEqualOrParent(resourceUri))) {
80+
result.push([resourceUri, widget]);
81+
}
82+
}
83+
}
84+
return result;
5585
}

Diff for: arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-tree.ts

+18-26
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { SketchCache } from './cloud-sketch-cache';
22
import { inject, injectable } from '@theia/core/shared/inversify';
33
import URI from '@theia/core/lib/common/uri';
44
import { MaybePromise } from '@theia/core/lib/common/types';
5-
import { FileService } from '@theia/filesystem/lib/browser/file-service';
65
import { FileStatNode } from '@theia/filesystem/lib/browser/file-tree';
76
import { Command } from '@theia/core/lib/common/command';
87
import { WidgetDecoration } from '@theia/core/lib/browser/widget-decoration';
@@ -28,8 +27,6 @@ import { CloudSketchbookCommands } from './cloud-sketchbook-contributions';
2827
import { DoNotAskAgainConfirmDialog } from '../../dialogs/do-not-ask-again-dialog';
2928
import { SketchbookTree } from '../sketchbook/sketchbook-tree';
3029
import { firstToUpperCase } from '../../../common/utils';
31-
import { ArduinoPreferences } from '../../arduino-preferences';
32-
import { SketchesServiceClientImpl } from '../../../common/protocol/sketches-service-client-impl';
3330
import { FileStat } from '@theia/filesystem/lib/common/files';
3431
import { WorkspaceNode } from '@theia/navigator/lib/browser/navigator-tree';
3532
import { posix, splitSketchPath } from '../../create/create-paths';
@@ -46,29 +43,20 @@ type FilesToSync = {
4643
};
4744
@injectable()
4845
export class CloudSketchbookTree extends SketchbookTree {
49-
@inject(FileService)
50-
protected override readonly fileService: FileService;
51-
5246
@inject(LocalCacheFsProvider)
53-
protected readonly localCacheFsProvider: LocalCacheFsProvider;
47+
private readonly localCacheFsProvider: LocalCacheFsProvider;
5448

5549
@inject(SketchCache)
56-
protected readonly sketchCache: SketchCache;
57-
58-
@inject(ArduinoPreferences)
59-
protected override readonly arduinoPreferences: ArduinoPreferences;
50+
private readonly sketchCache: SketchCache;
6051

6152
@inject(PreferenceService)
62-
protected readonly preferenceService: PreferenceService;
53+
private readonly preferenceService: PreferenceService;
6354

6455
@inject(MessageService)
65-
protected readonly messageService: MessageService;
66-
67-
@inject(SketchesServiceClientImpl)
68-
protected readonly sketchServiceClient: SketchesServiceClientImpl;
56+
private readonly messageService: MessageService;
6957

7058
@inject(CreateApi)
71-
protected readonly createApi: CreateApi;
59+
private readonly createApi: CreateApi;
7260

7361
async pushPublicWarn(
7462
node: CloudSketchbookTree.CloudSketchDirNode
@@ -93,15 +81,13 @@ export class CloudSketchbookTree extends SketchbookTree {
9381
PreferenceScope.User
9482
),
9583
}).open();
96-
if (!ok) {
97-
return false;
98-
}
99-
return true;
84+
return Boolean(ok);
10085
} else {
10186
return true;
10287
}
10388
}
10489

90+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
10591
async pull(arg: any): Promise<void> {
10692
const {
10793
// model,
@@ -136,6 +122,7 @@ export class CloudSketchbookTree extends SketchbookTree {
136122
return;
137123
}
138124
}
125+
// this.sketchCache.init();
139126
return this.runWithState(node, 'pulling', async (node) => {
140127
const commandsCopy = node.commands;
141128
node.commands = [];
@@ -229,7 +216,7 @@ export class CloudSketchbookTree extends SketchbookTree {
229216
});
230217
}
231218

232-
async recursiveURIs(uri: URI): Promise<URI[]> {
219+
private async recursiveURIs(uri: URI): Promise<URI[]> {
233220
// remote resources can be fetched one-shot via api
234221
if (CreateUri.is(uri)) {
235222
const resources = await this.createApi.readDirectory(
@@ -286,15 +273,15 @@ export class CloudSketchbookTree extends SketchbookTree {
286273
}, {});
287274
}
288275

289-
async getUrisMap(uri: URI) {
276+
private async getUrisMap(uri: URI): Promise<Record<string, URI>> {
290277
const basepath = uri.toString();
291278
const exists = await this.fileService.exists(uri);
292279
const uris =
293280
(exists && this.URIsToMap(await this.recursiveURIs(uri), basepath)) || {};
294281
return uris;
295282
}
296283

297-
async treeDiff(source: URI, dest: URI): Promise<FilesToSync> {
284+
private async treeDiff(source: URI, dest: URI): Promise<FilesToSync> {
298285
const [sourceURIs, destURIs] = await Promise.all([
299286
this.getUrisMap(source),
300287
this.getUrisMap(dest),
@@ -356,7 +343,7 @@ export class CloudSketchbookTree extends SketchbookTree {
356343
}
357344
}
358345

359-
async sync(source: URI, dest: URI) {
346+
private async sync(source: URI, dest: URI): Promise<void> {
360347
const { filesToWrite, filesToDelete } = await this.treeDiff(source, dest);
361348
await Promise.all(
362349
filesToWrite.map(async ({ source, dest }) => {
@@ -375,7 +362,9 @@ export class CloudSketchbookTree extends SketchbookTree {
375362
);
376363
}
377364

378-
override async resolveChildren(parent: CompositeTreeNode): Promise<TreeNode[]> {
365+
override async resolveChildren(
366+
parent: CompositeTreeNode
367+
): Promise<TreeNode[]> {
379368
return (await super.resolveChildren(parent)).sort((a, b) => {
380369
if (
381370
WorkspaceNode.is(parent) &&
@@ -453,6 +442,7 @@ export class CloudSketchbookTree extends SketchbookTree {
453442
if (!CreateUri.is(childFs.resource)) {
454443
let refUri = node.fileStat.resource;
455444
if (node.fileStat.hasOwnProperty('remoteUri')) {
445+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
456446
refUri = (node.fileStat as any).remoteUri;
457447
}
458448
remoteUri = refUri.resolve(childFs.name);
@@ -471,6 +461,7 @@ export class CloudSketchbookTree extends SketchbookTree {
471461
}
472462

473463
protected override toNode(
464+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
474465
fileStat: any,
475466
parent: CompositeTreeNode
476467
): FileNode | DirNode {
@@ -621,6 +612,7 @@ export class CloudSketchbookTree extends SketchbookTree {
621612
if (DecoratedTreeNode.is(node)) {
622613
for (const property of Object.keys(decorationData)) {
623614
if (node.decorationData.hasOwnProperty(property)) {
615+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
624616
delete (node.decorationData as any)[property];
625617
}
626618
}

Diff for: arduino-ide-extension/src/node/arduino-ide-backend-module.ts

+1
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
196196
// Shared sketches service
197197
bind(SketchesServiceImpl).toSelf().inSingletonScope();
198198
bind(SketchesService).toService(SketchesServiceImpl);
199+
bind(BackendApplicationContribution).toService(SketchesServiceImpl);
199200
bind(ConnectionHandler)
200201
.toDynamicValue(
201202
(context) =>

Diff for: arduino-ide-extension/src/node/boards-service-impl.ts

+5-9
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
BoardsPackage,
88
Board,
99
BoardDetails,
10-
Tool,
1110
ConfigOption,
1211
ConfigValue,
1312
Programmer,
@@ -97,14 +96,11 @@ export class BoardsServiceImpl
9796

9897
const debuggingSupported = detailsResp.getDebuggingSupported();
9998

100-
const requiredTools = detailsResp.getToolsDependenciesList().map(
101-
(t) =>
102-
<Tool>{
103-
name: t.getName(),
104-
packager: t.getPackager(),
105-
version: t.getVersion(),
106-
}
107-
);
99+
const requiredTools = detailsResp.getToolsDependenciesList().map((t) => ({
100+
name: t.getName(),
101+
packager: t.getPackager(),
102+
version: t.getVersion(),
103+
}));
108104

109105
const configOptions = detailsResp.getConfigOptionsList().map(
110106
(c) =>

0 commit comments

Comments
 (0)