Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 5b7a045

Browse files
author
Akos Kitta
committed
fix: disabled rename/delete cloud sketch folder if not logged in
Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
1 parent 30ddd95 commit 5b7a045

File tree

5 files changed

+192
-91
lines changed

5 files changed

+192
-91
lines changed

‎arduino-ide-extension/src/browser/contributions/sketch-control.ts‎

Lines changed: 47 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,32 @@
1-
import { inject, injectable } from '@theia/core/shared/inversify';
21
import { CommonCommands } from '@theia/core/lib/browser/common-frontend-contribution';
3-
import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell';
4-
import { WorkspaceCommands } from '@theia/workspace/lib/browser';
52
import { ContextMenuRenderer } from '@theia/core/lib/browser/context-menu-renderer';
3+
import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell';
64
import {
75
Disposable,
86
DisposableCollection,
97
} from '@theia/core/lib/common/disposable';
8+
import { nls } from '@theia/core/lib/common/nls';
9+
import { inject, injectable } from '@theia/core/shared/inversify';
10+
import { WorkspaceCommands } from '@theia/workspace/lib/browser/workspace-commands';
11+
import { ArduinoMenus } from '../menu/arduino-menus';
12+
import { CurrentSketch } from '../sketches-service-client-impl';
1013
import {
11-
URI,
12-
SketchContribution,
1314
Command,
1415
CommandRegistry,
15-
MenuModelRegistry,
1616
KeybindingRegistry,
17-
TabBarToolbarRegistry,
17+
MenuModelRegistry,
1818
open,
19+
SketchContribution,
20+
TabBarToolbarRegistry,
21+
URI,
1922
} from './contribution';
20-
import { ArduinoMenus, PlaceholderMenuNode } from '../menu/arduino-menus';
21-
import { CurrentSketch } from '../sketches-service-client-impl';
22-
import { nls } from '@theia/core/lib/common';
2323

2424
@injectable()
2525
export class SketchControl extends SketchContribution {
2626
@inject(ApplicationShell)
2727
private readonly shell: ApplicationShell;
28-
2928
@inject(MenuModelRegistry)
3029
private readonly menuRegistry: MenuModelRegistry;
31-
3230
@inject(ContextMenuRenderer)
3331
private readonly contextMenuRenderer: ContextMenuRenderer;
3432

@@ -43,97 +41,57 @@ export class SketchControl extends SketchContribution {
4341
this.shell.getWidgets('main').indexOf(widget) !== -1,
4442
execute: async () => {
4543
this.toDisposeBeforeCreateNewContextMenu.dispose();
46-
const sketch = await this.sketchServiceClient.currentSketch();
47-
if (!CurrentSketch.isValid(sketch)) {
48-
return;
49-
}
5044

45+
let parentElement: HTMLElement | undefined = undefined;
5146
const target = document.getElementById(
5247
SketchControl.Commands.OPEN_SKETCH_CONTROL__TOOLBAR.id
5348
);
54-
if (!(target instanceof HTMLElement)) {
55-
return;
49+
if (target instanceof HTMLElement) {
50+
parentElement=target.parentElement??undefined;
5651
}
57-
const { parentElement } = target;
5852
if (!parentElement) {
5953
return;
6054
}
6155

62-
const { mainFileUri, rootFolderFileUris } = sketch;
63-
const uris = [mainFileUri, ...rootFolderFileUris];
56+
const sketch = await this.sketchServiceClient.currentSketch();
57+
if (!CurrentSketch.isValid(sketch)) {
58+
return;
59+
}
6460

65-
const parentSketchUri = this.editorManager.currentEditor
66-
?.getResourceUri()
67-
?.toString();
68-
const parentSketch = await this.sketchesService.getSketchFolder(
69-
parentSketchUri || ''
61+
this.menuRegistry.registerMenuAction(
62+
ArduinoMenus.SKETCH_CONTROL__CONTEXT__MAIN_GROUP,
63+
{
64+
commandId: WorkspaceCommands.FILE_RENAME.id,
65+
label: nls.localize('vscode/fileActions/rename', 'Rename'),
66+
order: '1',
67+
}
7068
);
71-
72-
// if the current file is in the current opened sketch, show extra menus
73-
if (sketch && parentSketch && parentSketch.uri === sketch.uri) {
74-
this.menuRegistry.registerMenuAction(
75-
ArduinoMenus.SKETCH_CONTROL__CONTEXT__MAIN_GROUP,
76-
{
77-
commandId: WorkspaceCommands.FILE_RENAME.id,
78-
label: nls.localize('vscode/fileActions/rename', 'Rename'),
79-
order: '1',
80-
}
81-
);
82-
this.toDisposeBeforeCreateNewContextMenu.push(
83-
Disposable.create(() =>
84-
this.menuRegistry.unregisterMenuAction(
85-
WorkspaceCommands.FILE_RENAME
86-
)
69+
this.toDisposeBeforeCreateNewContextMenu.push(
70+
Disposable.create(() =>
71+
this.menuRegistry.unregisterMenuAction(
72+
WorkspaceCommands.FILE_RENAME
8773
)
88-
);
89-
} else {
90-
const renamePlaceholder = new PlaceholderMenuNode(
91-
ArduinoMenus.SKETCH_CONTROL__CONTEXT__MAIN_GROUP,
92-
nls.localize('vscode/fileActions/rename', 'Rename')
93-
);
94-
this.menuRegistry.registerMenuNode(
95-
ArduinoMenus.SKETCH_CONTROL__CONTEXT__MAIN_GROUP,
96-
renamePlaceholder
97-
);
98-
this.toDisposeBeforeCreateNewContextMenu.push(
99-
Disposable.create(() =>
100-
this.menuRegistry.unregisterMenuNode(renamePlaceholder.id)
101-
)
102-
);
103-
}
74+
)
75+
);
10476

105-
if (sketch && parentSketch && parentSketch.uri === sketch.uri) {
106-
this.menuRegistry.registerMenuAction(
107-
ArduinoMenus.SKETCH_CONTROL__CONTEXT__MAIN_GROUP,
108-
{
109-
commandId: WorkspaceCommands.FILE_DELETE.id, // TODO: customize delete. Wipe sketch if deleting main file. Close window.
110-
label: nls.localize('vscode/fileActions/delete', 'Delete'),
111-
order: '2',
112-
}
113-
);
114-
this.toDisposeBeforeCreateNewContextMenu.push(
115-
Disposable.create(() =>
116-
this.menuRegistry.unregisterMenuAction(
117-
WorkspaceCommands.FILE_DELETE
118-
)
119-
)
120-
);
121-
} else {
122-
const deletePlaceholder = new PlaceholderMenuNode(
123-
ArduinoMenus.SKETCH_CONTROL__CONTEXT__MAIN_GROUP,
124-
nls.localize('vscode/fileActions/delete', 'Delete')
125-
);
126-
this.menuRegistry.registerMenuNode(
127-
ArduinoMenus.SKETCH_CONTROL__CONTEXT__MAIN_GROUP,
128-
deletePlaceholder
129-
);
130-
this.toDisposeBeforeCreateNewContextMenu.push(
131-
Disposable.create(() =>
132-
this.menuRegistry.unregisterMenuNode(deletePlaceholder.id)
77+
this.menuRegistry.registerMenuAction(
78+
ArduinoMenus.SKETCH_CONTROL__CONTEXT__MAIN_GROUP,
79+
{
80+
commandId: WorkspaceCommands.FILE_DELETE.id,
81+
label: nls.localize('vscode/fileActions/delete', 'Delete'),
82+
order: '2',
83+
}
84+
);
85+
this.toDisposeBeforeCreateNewContextMenu.push(
86+
Disposable.create(() =>
87+
this.menuRegistry.unregisterMenuAction(
88+
WorkspaceCommands.FILE_DELETE
13389
)
134-
);
135-
}
90+
)
91+
);
13692

93+
const { mainFileUri, rootFolderFileUris } = sketch;
94+
const uris = [mainFileUri, ...rootFolderFileUris];
13795
for (let i = 0; i < uris.length; i++) {
13896
const uri = new URI(uris[i]);
13997

@@ -169,6 +127,7 @@ export class SketchControl extends SketchContribution {
169127
parentElement.getBoundingClientRect().top +
170128
parentElement.offsetHeight,
171129
},
130+
showDisabled: true,
172131
};
173132
this.contextMenuRenderer.render(options);
174133
},

‎arduino-ide-extension/src/browser/theia/workspace/workspace-commands.ts‎

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,9 @@ export class WorkspaceCommandContribution extends TheiaWorkspaceCommandContribut
251251
delegate,
252252
this.selectionService,
253253
this.shell,
254+
this.sketchesServiceClient,
255+
this.configServiceClient,
256+
this.createFeatures,
254257
{ multi }
255258
);
256259
}
@@ -356,6 +359,9 @@ class UriAwareCommandHandlerWithCurrentEditorFallback<
356359
delegate: UriCommandHandler<T>,
357360
selectionService: SelectionService,
358361
private readonly shell: ApplicationShell,
362+
private readonly sketchesServiceClient: SketchesServiceClientImpl,
363+
private readonly configServiceClient: ConfigServiceClient,
364+
private readonly createFeatures: CreateFeatures,
359365
options?: UriAwareCommandHandler.Options
360366
) {
361367
super(selectionService, delegate, options);
@@ -373,6 +379,24 @@ class UriAwareCommandHandlerWithCurrentEditorFallback<
373379
return uri;
374380
}
375381

382+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
383+
override isEnabled(...args: any[]): boolean {
384+
const [uri, ...others] = this.getArgsWithUri(...args);
385+
if (uri) {
386+
if (!this.isInSketch(uri)) {
387+
return false;
388+
}
389+
if (this.affectsCloudSketchFolderWhenSignedOut(uri)) {
390+
return false;
391+
}
392+
if (this.handler.isEnabled) {
393+
return this.handler.isEnabled(uri, ...others);
394+
}
395+
return true;
396+
}
397+
return false;
398+
}
399+
376400
// The `currentEditor` is broken after a rename. (https://github.com/eclipse-theia/theia/issues/12139)
377401
// `ApplicationShell#currentWidget` might provide a wrong result just as the `getFocusedCodeEditor` and `getFocusedCodeEditor` of the `MonacoEditorService`
378402
// Try to extract the URI from the current title of the main panel if it's an editor widget.
@@ -382,4 +406,58 @@ class UriAwareCommandHandlerWithCurrentEditorFallback<
382406
? owner.editor.getResourceUri()
383407
: undefined;
384408
}
409+
410+
private isInSketch(uri: T | undefined): boolean {
411+
if (!uri) {
412+
return false;
413+
}
414+
const sketch = this.sketchesServiceClient.tryGetCurrentSketch();
415+
if (!CurrentSketch.isValid(sketch)) {
416+
return false;
417+
}
418+
if (this.isMulti() && Array.isArray(uri)) {
419+
return uri.every((u) => Sketch.isInSketch(u, sketch));
420+
}
421+
if (!this.isMulti() && uri instanceof URI) {
422+
return Sketch.isInSketch(uri, sketch);
423+
}
424+
return false;
425+
}
426+
427+
/**
428+
* If the user is not logged in, deleting/renaming the main sketch file or the sketch folder of a cloud sketch is disabled.
429+
*/
430+
private affectsCloudSketchFolderWhenSignedOut(uri: T | undefined): boolean {
431+
return (
432+
!Boolean(this.createFeatures.session) &&
433+
Boolean(this.isCurrentSketchCloud()) &&
434+
this.affectsSketchFolder(uri)
435+
);
436+
}
437+
438+
private affectsSketchFolder(uri: T | undefined): boolean {
439+
if (!uri) {
440+
return false;
441+
}
442+
const sketch = this.sketchesServiceClient.tryGetCurrentSketch();
443+
if (!CurrentSketch.isValid(sketch)) {
444+
return false;
445+
}
446+
if (this.isMulti() && Array.isArray(uri)) {
447+
return uri.map((u) => u.toString()).includes(sketch.mainFileUri);
448+
}
449+
if (!this.isMulti()) {
450+
return sketch.mainFileUri === uri.toString();
451+
}
452+
return false;
453+
}
454+
455+
private isCurrentSketchCloud(): boolean | undefined {
456+
const sketch = this.sketchesServiceClient.tryGetCurrentSketch();
457+
if (!CurrentSketch.isValid(sketch)) {
458+
return false;
459+
}
460+
const dataDirUri = this.configServiceClient.tryGetDataDirUri();
461+
return this.createFeatures.isCloud(sketch, dataDirUri);
462+
}
385463
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { webFrame } from '@theia/core/electron-shared/electron/';
2+
import {
3+
ContextMenuAccess,
4+
coordinateFromAnchor,
5+
RenderContextMenuOptions,
6+
} from '@theia/core/lib/browser/context-menu-renderer';
7+
import {
8+
ElectronContextMenuAccess,
9+
ElectronContextMenuRenderer as TheiaElectronContextMenuRenderer,
10+
} from '@theia/core/lib/electron-browser/menu/electron-context-menu-renderer';
11+
import { injectable } from '@theia/core/shared/inversify';
12+
13+
@injectable()
14+
export class ElectronContextMenuRenderer extends TheiaElectronContextMenuRenderer {
15+
protected override doRender(
16+
options: RenderContextMenuOptions
17+
): ContextMenuAccess {
18+
if (this.useNativeStyle) {
19+
const { menuPath, anchor, args, onHide, context } = options;
20+
const menu = this['electronMenuFactory'].createElectronContextMenu(
21+
menuPath,
22+
args,
23+
context,
24+
this.showDisabled(options)
25+
);
26+
const { x, y } = coordinateFromAnchor(anchor);
27+
const zoom = webFrame.getZoomFactor();
28+
// TODO: Remove the offset once Electron fixes https://github.com/electron/electron/issues/31641
29+
const offset = process.platform === 'win32' ? 0 : 2;
30+
// x and y values must be Ints or else there is a conversion error
31+
menu.popup({
32+
x: Math.round(x * zoom) + offset,
33+
y: Math.round(y * zoom) + offset,
34+
});
35+
// native context menu stops the event loop, so there is no keyboard events
36+
this.context.resetAltPressed();
37+
if (onHide) {
38+
menu.once('menu-will-close', () => onHide());
39+
}
40+
return new ElectronContextMenuAccess(menu);
41+
} else {
42+
return super.doRender(options);
43+
}
44+
}
45+
46+
/**
47+
* Theia does not allow selectively control whether disabled menu items are visible or not. This is a workaround.
48+
* Attach the `showDisabled: true` to the `RenderContextMenuOptions` object, and you can control it.
49+
* https://github.com/eclipse-theia/theia/blob/d59d5279b93e5050c2cbdd4b6726cab40187c50e/packages/core/src/electron-browser/menu/electron-main-menu-factory.ts#L134.
50+
*/
51+
private showDisabled(options: RenderContextMenuOptions): boolean {
52+
if ('showDisabled' in options) {
53+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
54+
const object = options as any;
55+
return Boolean(object['showDisabled']);
56+
}
57+
return false;
58+
}
59+
}

‎arduino-ide-extension/src/electron-browser/theia/core/electron-main-menu-factory.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,12 @@ export class ElectronMainMenuFactory extends TheiaElectronMainMenuFactory {
7474
menuPath: MenuPath,
7575
// eslint-disable-next-line @typescript-eslint/no-explicit-any
7676
args?: any[],
77-
context?: HTMLElement
77+
context?: HTMLElement,
78+
showDisabled?: boolean
7879
): Electron.Menu {
7980
const menuModel = this.menuProvider.getMenu(menuPath);
8081
const template = this.fillMenuTemplate([], menuModel, args, {
81-
showDisabled: false,
82+
showDisabled,
8283
context,
8384
rootMenuPath: menuPath,
8485
});

‎arduino-ide-extension/src/electron-browser/theia/core/electron-menu-module.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
import { ContainerModule } from '@theia/core/shared/inversify';
1+
import { ContextMenuRenderer } from '@theia/core/lib/browser/context-menu-renderer';
22
import { ElectronMainMenuFactory as TheiaElectronMainMenuFactory } from '@theia/core/lib/electron-browser/menu/electron-main-menu-factory';
33
import { ElectronMenuContribution as TheiaElectronMenuContribution } from '@theia/core/lib/electron-browser/menu/electron-menu-contribution';
4+
import { ContainerModule } from '@theia/core/shared/inversify';
45
import { MainMenuManager } from '../../../common/main-menu-manager';
6+
import { ElectronContextMenuRenderer } from './electron-context-menu-renderer';
57
import { ElectronMainMenuFactory } from './electron-main-menu-factory';
68
import { ElectronMenuContribution } from './electron-menu-contribution';
79

810
export default new ContainerModule((bind, unbind, isBound, rebind) => {
911
bind(ElectronMenuContribution).toSelf().inSingletonScope();
1012
bind(MainMenuManager).toService(ElectronMenuContribution);
13+
bind(ElectronContextMenuRenderer).toSelf().inSingletonScope();
14+
rebind(ContextMenuRenderer).toService(ElectronContextMenuRenderer);
1115
rebind(TheiaElectronMenuContribution).toService(ElectronMenuContribution);
1216
bind(ElectronMainMenuFactory).toSelf().inSingletonScope();
1317
rebind(TheiaElectronMainMenuFactory).toService(ElectronMainMenuFactory);

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /