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 d4a4e11

Browse files
author
Akos Kitta
committed
feat: introduced cloud state in sketchbook view
Closes #1879 Closes #1876 Closes #1899 Closes #1878 Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
1 parent 24dc0bb commit d4a4e11

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1457
-489
lines changed

‎arduino-ide-extension/arduino-icons.json‎

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

‎arduino-ide-extension/package.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
"glob": "^7.1.6",
7878
"google-protobuf": "^3.20.1",
7979
"hash.js": "^1.1.7",
80+
"is-online": "^9.0.1",
8081
"js-yaml": "^3.13.1",
8182
"just-diff": "^5.1.1",
8283
"jwt-decode": "^3.1.2",

‎arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ import { EditorCommandContribution as TheiaEditorCommandContribution } from '@th
9090
import {
9191
FrontendConnectionStatusService,
9292
ApplicationConnectionStatusContribution,
93+
DaemonPort,
94+
IsOnline,
9395
} from './theia/core/connection-status-service';
9496
import {
9597
FrontendConnectionStatusService as TheiaFrontendConnectionStatusService,
@@ -350,6 +352,7 @@ import { CreateFeatures } from './create/create-features';
350352
import { Account } from './contributions/account';
351353
import { SidebarBottomMenuWidget } from './theia/core/sidebar-bottom-menu-widget';
352354
import { SidebarBottomMenuWidget as TheiaSidebarBottomMenuWidget } from '@theia/core/lib/browser/shell/sidebar-bottom-menu-widget';
355+
import { CreateCloudCopy } from './contributions/create-cloud-copy';
353356

354357
export default new ContainerModule((bind, unbind, isBound, rebind) => {
355358
// Commands and toolbar items
@@ -738,6 +741,8 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
738741
Contribution.configure(bind, ValidateSketch);
739742
Contribution.configure(bind, RenameCloudSketch);
740743
Contribution.configure(bind, Account);
744+
Contribution.configure(bind, CloudSketchbookContribution);
745+
Contribution.configure(bind, CreateCloudCopy);
741746

742747
bindContributionProvider(bind, StartupTaskProvider);
743748
bind(StartupTaskProvider).toService(BoardsServiceProvider); // to reuse the boards config in another window
@@ -916,8 +921,6 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
916921
bind(CreateFsProvider).toSelf().inSingletonScope();
917922
bind(FrontendApplicationContribution).toService(CreateFsProvider);
918923
bind(FileServiceContribution).toService(CreateFsProvider);
919-
bind(CloudSketchbookContribution).toSelf().inSingletonScope();
920-
bind(CommandContribution).toService(CloudSketchbookContribution);
921924
bind(LocalCacheFsProvider).toSelf().inSingletonScope();
922925
bind(FileServiceContribution).toService(LocalCacheFsProvider);
923926
bind(CloudSketchbookCompositeWidget).toSelf();
@@ -1021,4 +1024,8 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
10211024

10221025
bind(SidebarBottomMenuWidget).toSelf();
10231026
rebind(TheiaSidebarBottomMenuWidget).toService(SidebarBottomMenuWidget);
1027+
bind(DaemonPort).toSelf().inSingletonScope();
1028+
bind(FrontendApplicationContribution).toService(DaemonPort);
1029+
bind(IsOnline).toSelf().inSingletonScope();
1030+
bind(FrontendApplicationContribution).toService(IsOnline);
10241031
});

‎arduino-ide-extension/src/browser/contributions/account.ts‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { inject, injectable } from '@theia/core/shared/inversify';
88
import { CloudUserCommands, LEARN_MORE_URL } from '../auth/cloud-user-commands';
99
import { CreateFeatures } from '../create/create-features';
1010
import { ArduinoMenus } from '../menu/arduino-menus';
11+
import { ApplicationConnectionStatusContribution } from '../theia/core/connection-status-service';
1112
import {
1213
Command,
1314
CommandRegistry,
@@ -29,6 +30,8 @@ export class Account extends Contribution {
2930
private readonly windowService: WindowService;
3031
@inject(CreateFeatures)
3132
private readonly createFeatures: CreateFeatures;
33+
@inject(ApplicationConnectionStatusContribution)
34+
private readonly connectionStatus: ApplicationConnectionStatusContribution;
3235

3336
private readonly toDispose = new DisposableCollection();
3437
private app: FrontendApplication;
@@ -50,21 +53,28 @@ export class Account extends Contribution {
5053
override registerCommands(registry: CommandRegistry): void {
5154
const openExternal = (url: string) =>
5255
this.windowService.openNewWindow(url, { external: true });
56+
const loggedIn = () => Boolean(this.createFeatures.session);
57+
const loggedInWithInternetConnection = () =>
58+
loggedIn() && this.connectionStatus.offlineStatus !== 'internet';
5359
registry.registerCommand(Account.Commands.LEARN_MORE, {
5460
execute: () => openExternal(LEARN_MORE_URL),
55-
isEnabled: () => !Boolean(this.createFeatures.session),
61+
isEnabled: () => !loggedIn(),
62+
isVisible: () => !loggedIn(),
5663
});
5764
registry.registerCommand(Account.Commands.GO_TO_PROFILE, {
5865
execute: () => openExternal('https://id.arduino.cc/'),
59-
isEnabled: () => Boolean(this.createFeatures.session),
66+
isEnabled: () => loggedInWithInternetConnection(),
67+
isVisible: () => loggedIn(),
6068
});
6169
registry.registerCommand(Account.Commands.GO_TO_CLOUD_EDITOR, {
6270
execute: () => openExternal('https://create.arduino.cc/editor'),
63-
isEnabled: () => Boolean(this.createFeatures.session),
71+
isEnabled: () => loggedInWithInternetConnection(),
72+
isVisible: () => loggedIn(),
6473
});
6574
registry.registerCommand(Account.Commands.GO_TO_IOT_CLOUD, {
6675
execute: () => openExternal('https://create.arduino.cc/iot/'),
67-
isEnabled: () => Boolean(this.createFeatures.session),
76+
isEnabled: () => loggedInWithInternetConnection(),
77+
isVisible: () => loggedIn(),
6878
});
6979
}
7080

‎arduino-ide-extension/src/browser/contributions/cloud-contribution.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export abstract class CloudSketchContribution extends SketchContribution {
9393
);
9494
}
9595
try {
96-
await treeModel.sketchbookTree().pull({ node });
96+
await treeModel.sketchbookTree().pull({ node },true);
9797
return node;
9898
} catch (err) {
9999
if (isNotFound(err)) {

‎arduino-ide-extension/src/browser/contributions/contribution.ts‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import { EditorManager } from '@theia/editor/lib/browser/editor-manager';
1414
import { MessageService } from '@theia/core/lib/common/message-service';
1515
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
1616
import { open, OpenerService } from '@theia/core/lib/browser/opener-service';
17-
1817
import {
1918
MenuModelRegistry,
2019
MenuContribution,
@@ -58,7 +57,7 @@ import { ClipboardService } from '@theia/core/lib/browser/clipboard-service';
5857
import { ExecuteWithProgress } from '../../common/protocol/progressible';
5958
import { BoardsServiceProvider } from '../boards/boards-service-provider';
6059
import { BoardsDataStore } from '../boards/boards-data-store';
61-
import { NotificationManager } from '../theia/messages/notifications-manager';
60+
import { NotificationManager } from '@theia/messages/lib/browser/notifications-manager';
6261
import { MessageType } from '@theia/core/lib/common/message-service-protocol';
6362
import { WorkspaceService } from '../theia/workspace/workspace-service';
6463
import { MainMenuManager } from '../../common/main-menu-manager';
@@ -295,7 +294,7 @@ export abstract class CoreServiceContribution extends SketchContribution {
295294
}
296295

297296
private notificationId(message: string, ...actions: string[]): string {
298-
return this.notificationManager.getMessageId({
297+
return this.notificationManager['getMessageId']({
299298
text: message,
300299
actions,
301300
type: MessageType.Error,
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import { FrontendApplication } from '@theia/core/lib/browser/frontend-application';
2+
import { ApplicationShell } from '@theia/core/lib/browser/shell';
3+
import type { Command, CommandRegistry } from '@theia/core/lib/common/command';
4+
import { Progress } from '@theia/core/lib/common/message-service-protocol';
5+
import { nls } from '@theia/core/lib/common/nls';
6+
import { inject, injectable } from '@theia/core/shared/inversify';
7+
import { Create } from '../create/typings';
8+
import { ApplicationConnectionStatusContribution } from '../theia/core/connection-status-service';
9+
import { CloudSketchbookTree } from '../widgets/cloud-sketchbook/cloud-sketchbook-tree';
10+
import { SketchbookTree } from '../widgets/sketchbook/sketchbook-tree';
11+
import { SketchbookTreeModel } from '../widgets/sketchbook/sketchbook-tree-model';
12+
import { CloudSketchContribution, pushingSketch } from './cloud-contribution';
13+
import {
14+
CreateNewCloudSketchCallback,
15+
NewCloudSketch,
16+
NewCloudSketchParams,
17+
} from './new-cloud-sketch';
18+
import { saveOntoCopiedSketch } from './save-as-sketch';
19+
20+
interface CreateCloudCopyParams {
21+
readonly model: SketchbookTreeModel;
22+
readonly node: SketchbookTree.SketchDirNode;
23+
}
24+
function isCreateCloudCopyParams(arg: unknown): arg is CreateCloudCopyParams {
25+
return (
26+
typeof arg === 'object' &&
27+
(<CreateCloudCopyParams>arg).model !== undefined &&
28+
(<CreateCloudCopyParams>arg).model instanceof SketchbookTreeModel &&
29+
(<CreateCloudCopyParams>arg).node !== undefined &&
30+
SketchbookTree.SketchDirNode.is((<CreateCloudCopyParams>arg).node)
31+
);
32+
}
33+
34+
@injectable()
35+
export class CreateCloudCopy extends CloudSketchContribution {
36+
@inject(ApplicationConnectionStatusContribution)
37+
private readonly connectionStatus: ApplicationConnectionStatusContribution;
38+
39+
private shell: ApplicationShell;
40+
41+
override onStart(app: FrontendApplication): void {
42+
this.shell = app.shell;
43+
}
44+
45+
override registerCommands(registry: CommandRegistry): void {
46+
registry.registerCommand(CreateCloudCopy.Commands.CREATE_CLOUD_COPY, {
47+
execute: (args: CreateCloudCopyParams) => this.createCloudCopy(args),
48+
isEnabled: (args: unknown) =>
49+
Boolean(this.createFeatures.session) && isCreateCloudCopyParams(args),
50+
isVisible: (args: unknown) =>
51+
Boolean(this.createFeatures.enabled) &&
52+
Boolean(this.createFeatures.session) &&
53+
this.connectionStatus.offlineStatus !== 'internet' &&
54+
isCreateCloudCopyParams(args),
55+
});
56+
}
57+
58+
/**
59+
* - creates new cloud sketch with the name of the params sketch,
60+
* - pulls the cloud sketch,
61+
* - copies files from params sketch to pulled cloud sketch in the cache folder,
62+
* - pushes the cloud sketch, and
63+
* - opens in new window.
64+
*/
65+
private async createCloudCopy(params: CreateCloudCopyParams): Promise<void> {
66+
const sketch = await this.sketchesService.loadSketch(
67+
params.node.fileStat.resource.toString()
68+
);
69+
const callback: CreateNewCloudSketchCallback = async (
70+
newSketch: Create.Sketch,
71+
newNode: CloudSketchbookTree.CloudSketchDirNode,
72+
progress: Progress
73+
) => {
74+
const treeModel = await this.treeModel();
75+
if (!treeModel) {
76+
throw new Error('Could not retrieve the cloud sketchbook tree model.');
77+
}
78+
79+
progress.report({
80+
message: nls.localize(
81+
'arduino/createCloudCopy/copyingSketchFilesMessage',
82+
'Copying local sketch files...'
83+
),
84+
});
85+
const localCacheFolderUri = newNode.uri.toString();
86+
await this.sketchesService.copy(sketch, {
87+
destinationUri: localCacheFolderUri,
88+
onlySketchFiles: true,
89+
});
90+
await saveOntoCopiedSketch(
91+
sketch,
92+
localCacheFolderUri,
93+
this.shell,
94+
this.editorManager
95+
);
96+
97+
progress.report({ message: pushingSketch(newSketch.name) });
98+
await treeModel.sketchbookTree().push(newNode, true);
99+
};
100+
return this.commandService.executeCommand(
101+
NewCloudSketch.Commands.NEW_CLOUD_SKETCH.id,
102+
<NewCloudSketchParams>{
103+
initialValue: params.node.fileStat.name,
104+
callback,
105+
skipShowErrorMessageOnOpen: false,
106+
}
107+
);
108+
}
109+
}
110+
111+
export namespace CreateCloudCopy {
112+
export namespace Commands {
113+
export const CREATE_CLOUD_COPY: Command = {
114+
id: 'arduino-create-cloud-copy',
115+
iconClass: 'fa fa-arduino-cloud-upload',
116+
};
117+
}
118+
}

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

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Progress } from '@theia/core/lib/common/message-service-protocol';
66
import { nls } from '@theia/core/lib/common/nls';
77
import { injectable } from '@theia/core/shared/inversify';
88
import { CreateUri } from '../create/create-uri';
9-
import { isConflict } from '../create/typings';
9+
import { Create,isConflict } from '../create/typings';
1010
import { ArduinoMenus } from '../menu/arduino-menus';
1111
import {
1212
TaskFactoryImpl,
@@ -15,13 +15,36 @@ import {
1515
import { CloudSketchbookTree } from '../widgets/cloud-sketchbook/cloud-sketchbook-tree';
1616
import { CloudSketchbookTreeModel } from '../widgets/cloud-sketchbook/cloud-sketchbook-tree-model';
1717
import { SketchbookCommands } from '../widgets/sketchbook/sketchbook-commands';
18-
import { Command, CommandRegistry, Sketch } from './contribution';
1918
import {
2019
CloudSketchContribution,
2120
pullingSketch,
2221
sketchAlreadyExists,
2322
synchronizingSketchbook,
2423
} from './cloud-contribution';
24+
import { Command, CommandRegistry, Sketch } from './contribution';
25+
26+
export interface CreateNewCloudSketchCallback {
27+
(
28+
newSketch: Create.Sketch,
29+
newNode: CloudSketchbookTree.CloudSketchDirNode,
30+
progress: Progress
31+
): Promise<void>;
32+
}
33+
34+
export interface NewCloudSketchParams {
35+
/**
36+
* Value to populate the dialog `<input>` when it opens.
37+
*/
38+
readonly initialValue?: string | undefined;
39+
/**
40+
* Additional callback to call when the new cloud sketch has been created.
41+
*/
42+
readonly callback?: CreateNewCloudSketchCallback;
43+
/**
44+
* If `true`, the validation error message will not be visible in the input dialog, but the `OK` button will be disabled. Defaults to `true`.
45+
*/
46+
readonly skipShowErrorMessageOnOpen?: boolean;
47+
}
2548

2649
@injectable()
2750
export class NewCloudSketch extends CloudSketchContribution {
@@ -43,7 +66,12 @@ export class NewCloudSketch extends CloudSketchContribution {
4366

4467
override registerCommands(registry: CommandRegistry): void {
4568
registry.registerCommand(NewCloudSketch.Commands.NEW_CLOUD_SKETCH, {
46-
execute: () => this.createNewSketch(true),
69+
execute: (params: NewCloudSketchParams) =>
70+
this.createNewSketch(
71+
params?.skipShowErrorMessageOnOpen === false ? false : true,
72+
params?.initialValue,
73+
params?.callback
74+
),
4775
isEnabled: () => Boolean(this.createFeatures.session),
4876
isVisible: () => this.createFeatures.enabled,
4977
});
@@ -66,7 +94,8 @@ export class NewCloudSketch extends CloudSketchContribution {
6694

6795
private async createNewSketch(
6896
skipShowErrorMessageOnOpen: boolean,
69-
initialValue?: string | undefined
97+
initialValue?: string | undefined,
98+
callback?: CreateNewCloudSketchCallback
7099
): Promise<void> {
71100
const treeModel = await this.treeModel();
72101
if (treeModel) {
@@ -75,7 +104,8 @@ export class NewCloudSketch extends CloudSketchContribution {
75104
rootNode,
76105
treeModel,
77106
skipShowErrorMessageOnOpen,
78-
initialValue
107+
initialValue,
108+
callback
79109
);
80110
}
81111
}
@@ -84,13 +114,14 @@ export class NewCloudSketch extends CloudSketchContribution {
84114
rootNode: CompositeTreeNode,
85115
treeModel: CloudSketchbookTreeModel,
86116
skipShowErrorMessageOnOpen: boolean,
87-
initialValue?: string | undefined
117+
initialValue?: string | undefined,
118+
callback?: CreateNewCloudSketchCallback
88119
): Promise<void> {
89120
const existingNames = rootNode.children
90121
.filter(CloudSketchbookTree.CloudSketchDirNode.is)
91122
.map(({ fileStat }) => fileStat.name);
92123
const taskFactory = new TaskFactoryImpl((value) =>
93-
this.createNewSketchWithProgress(treeModel, value)
124+
this.createNewSketchWithProgress(treeModel, value,callback)
94125
);
95126
try {
96127
const dialog = new WorkspaceInputDialogWithProgress(
@@ -118,15 +149,20 @@ export class NewCloudSketch extends CloudSketchContribution {
118149
} catch (err) {
119150
if (isConflict(err)) {
120151
await treeModel.refresh();
121-
return this.createNewSketch(false, taskFactory.value ?? initialValue);
152+
return this.createNewSketch(
153+
false,
154+
taskFactory.value ?? initialValue,
155+
callback
156+
);
122157
}
123158
throw err;
124159
}
125160
}
126161

127162
private createNewSketchWithProgress(
128163
treeModel: CloudSketchbookTreeModel,
129-
value: string
164+
value: string,
165+
callback?: CreateNewCloudSketchCallback
130166
): (
131167
progress: Progress
132168
) => Promise<CloudSketchbookTree.CloudSketchDirNode | undefined> {
@@ -143,6 +179,9 @@ export class NewCloudSketch extends CloudSketchContribution {
143179
await treeModel.refresh();
144180
progress.report({ message: pullingSketch(sketch.name) });
145181
const node = await this.pull(sketch);
182+
if (callback && node) {
183+
await callback(sketch, node, progress);
184+
}
146185
return node;
147186
};
148187
}
@@ -152,7 +191,7 @@ export class NewCloudSketch extends CloudSketchContribution {
152191
): Promise<void> {
153192
return this.commandService.executeCommand(
154193
SketchbookCommands.OPEN_NEW_WINDOW.id,
155-
{ node }
194+
{ node,treeWidgetId: 'cloud-sketchbook-composite-widget' }
156195
);
157196
}
158197
}

0 commit comments

Comments
(0)

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