Skip to content

Commit

Permalink
feat: introduced cloud state in sketchbook view
Browse files Browse the repository at this point in the history
Closes #1879
Closes #1899

Signed-off-by: Akos Kitta <[email protected]>
  • Loading branch information
Akos Kitta committed Mar 9, 2023
1 parent 24dc0bb commit feb39eb
Show file tree
Hide file tree
Showing 37 changed files with 1,073 additions and 390 deletions.
2 changes: 1 addition & 1 deletion arduino-ide-extension/arduino-icons.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions arduino-ide-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"glob": "^7.1.6",
"google-protobuf": "^3.20.1",
"hash.js": "^1.1.7",
"is-online": "^9.0.1",
"js-yaml": "^3.13.1",
"just-diff": "^5.1.1",
"jwt-decode": "^3.1.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ import { EditorCommandContribution as TheiaEditorCommandContribution } from '@th
import {
FrontendConnectionStatusService,
ApplicationConnectionStatusContribution,
DaemonPort,
IsOnline,
} from './theia/core/connection-status-service';
import {
FrontendConnectionStatusService as TheiaFrontendConnectionStatusService,
Expand Down Expand Up @@ -738,6 +740,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
Contribution.configure(bind, ValidateSketch);
Contribution.configure(bind, RenameCloudSketch);
Contribution.configure(bind, Account);
Contribution.configure(bind, CloudSketchbookContribution);

bindContributionProvider(bind, StartupTaskProvider);
bind(StartupTaskProvider).toService(BoardsServiceProvider); // to reuse the boards config in another window
Expand Down Expand Up @@ -916,8 +919,6 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(CreateFsProvider).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).toService(CreateFsProvider);
bind(FileServiceContribution).toService(CreateFsProvider);
bind(CloudSketchbookContribution).toSelf().inSingletonScope();
bind(CommandContribution).toService(CloudSketchbookContribution);
bind(LocalCacheFsProvider).toSelf().inSingletonScope();
bind(FileServiceContribution).toService(LocalCacheFsProvider);
bind(CloudSketchbookCompositeWidget).toSelf();
Expand Down Expand Up @@ -1021,4 +1022,8 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {

bind(SidebarBottomMenuWidget).toSelf();
rebind(TheiaSidebarBottomMenuWidget).toService(SidebarBottomMenuWidget);
bind(DaemonPort).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).toService(DaemonPort);
bind(IsOnline).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).toService(IsOnline);
});
18 changes: 14 additions & 4 deletions arduino-ide-extension/src/browser/contributions/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { inject, injectable } from '@theia/core/shared/inversify';
import { CloudUserCommands, LEARN_MORE_URL } from '../auth/cloud-user-commands';
import { CreateFeatures } from '../create/create-features';
import { ArduinoMenus } from '../menu/arduino-menus';
import { ApplicationConnectionStatusContribution } from '../theia/core/connection-status-service';
import {
Command,
CommandRegistry,
Expand All @@ -29,6 +30,8 @@ export class Account extends Contribution {
private readonly windowService: WindowService;
@inject(CreateFeatures)
private readonly createFeatures: CreateFeatures;
@inject(ApplicationConnectionStatusContribution)
private readonly connectionStatus: ApplicationConnectionStatusContribution;

private readonly toDispose = new DisposableCollection();
private app: FrontendApplication;
Expand All @@ -50,21 +53,28 @@ export class Account extends Contribution {
override registerCommands(registry: CommandRegistry): void {
const openExternal = (url: string) =>
this.windowService.openNewWindow(url, { external: true });
const loggedIn = () => Boolean(this.createFeatures.session);
const loggedInWithInternetConnection = () =>
loggedIn() && this.connectionStatus.offlineStatus !== 'internet';
registry.registerCommand(Account.Commands.LEARN_MORE, {
execute: () => openExternal(LEARN_MORE_URL),
isEnabled: () => !Boolean(this.createFeatures.session),
isEnabled: () => !loggedIn(),
isVisible: () => !loggedIn(),
});
registry.registerCommand(Account.Commands.GO_TO_PROFILE, {
execute: () => openExternal('https://id.arduino.cc/'),
isEnabled: () => Boolean(this.createFeatures.session),
isEnabled: () => loggedInWithInternetConnection(),
isVisible: () => loggedIn(),
});
registry.registerCommand(Account.Commands.GO_TO_CLOUD_EDITOR, {
execute: () => openExternal('https://create.arduino.cc/editor'),
isEnabled: () => Boolean(this.createFeatures.session),
isEnabled: () => loggedInWithInternetConnection(),
isVisible: () => loggedIn(),
});
registry.registerCommand(Account.Commands.GO_TO_IOT_CLOUD, {
execute: () => openExternal('https://create.arduino.cc/iot/'),
isEnabled: () => Boolean(this.createFeatures.session),
isEnabled: () => loggedInWithInternetConnection(),
isVisible: () => loggedIn(),
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export abstract class CloudSketchContribution extends SketchContribution {
);
}
try {
await treeModel.sketchbookTree().pull({ node });
await treeModel.sketchbookTree().pull({ node }, true);
return node;
} catch (err) {
if (isNotFound(err)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { EditorManager } from '@theia/editor/lib/browser/editor-manager';
import { MessageService } from '@theia/core/lib/common/message-service';
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
import { open, OpenerService } from '@theia/core/lib/browser/opener-service';

import {
MenuModelRegistry,
MenuContribution,
Expand Down Expand Up @@ -58,7 +57,7 @@ import { ClipboardService } from '@theia/core/lib/browser/clipboard-service';
import { ExecuteWithProgress } from '../../common/protocol/progressible';
import { BoardsServiceProvider } from '../boards/boards-service-provider';
import { BoardsDataStore } from '../boards/boards-data-store';
import { NotificationManager } from '../theia/messages/notifications-manager';
import { NotificationManager } from '@theia/messages/lib/browser/notifications-manager';
import { MessageType } from '@theia/core/lib/common/message-service-protocol';
import { WorkspaceService } from '../theia/workspace/workspace-service';
import { MainMenuManager } from '../../common/main-menu-manager';
Expand Down Expand Up @@ -295,7 +294,7 @@ export abstract class CoreServiceContribution extends SketchContribution {
}

private notificationId(message: string, ...actions: string[]): string {
return this.notificationManager.getMessageId({
return this.notificationManager['getMessageId']({
text: message,
actions,
type: MessageType.Error,
Expand Down
11 changes: 5 additions & 6 deletions arduino-ide-extension/src/browser/create/create-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ import { MaybePromise } from '@theia/core/lib/common/types';
import { inject, injectable } from '@theia/core/shared/inversify';
import { fetch } from 'cross-fetch';
import { SketchesService } from '../../common/protocol';
import { unit8ArrayToString } from '../../common/utils';
import { uint8ArrayToString } from '../../common/utils';
import { ArduinoPreferences } from '../arduino-preferences';
import { AuthenticationClientService } from '../auth/authentication-client-service';
import { SketchCache } from '../widgets/cloud-sketchbook/cloud-sketch-cache';
import * as createPaths from './create-paths';
import { posix } from './create-paths';
import { Create, CreateError } from './typings';

export interface ResponseResultProvider {
interface ResponseResultProvider {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(response: Response): Promise<any>;
}
export namespace ResponseResultProvider {
namespace ResponseResultProvider {
export const NOOP: ResponseResultProvider = async () => undefined;
export const TEXT: ResponseResultProvider = (response) => response.text();
export const JSON: ResponseResultProvider = (response) => response.json();
Expand Down Expand Up @@ -288,10 +288,9 @@ export class CreateApi {
if (sketch) {
const url = new URL(`${this.domain()}/sketches/${sketch.id}`);
const headers = await this.headers();

// parse the secret file
const secrets = (
typeof content === 'string' ? content : unit8ArrayToString(content)
typeof content === 'string' ? content : uint8ArrayToString(content)
)
.split(/\r?\n/)
.reduce((prev, curr) => {
Expand Down Expand Up @@ -355,7 +354,7 @@ export class CreateApi {
const headers = await this.headers();

let data: string =
typeof content === 'string' ? content : unit8ArrayToString(content);
typeof content === 'string' ? content : uint8ArrayToString(content);
data = await this.toggleSecretsInclude(posixPath, data, 'remove');

const payload = { data: btoa(data) };
Expand Down
64 changes: 60 additions & 4 deletions arduino-ide-extension/src/browser/create/create-features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import { AuthenticationSession } from '../../node/auth/types';
import { ArduinoPreferences } from '../arduino-preferences';
import { AuthenticationClientService } from '../auth/authentication-client-service';
import { LocalCacheFsProvider } from '../local-cache/local-cache-fs-provider';
import { CreateUri } from './create-uri';

export type CloudSketchState = 'push' | 'pull';

@injectable()
export class CreateFeatures implements FrontendApplicationContribution {
Expand All @@ -18,13 +21,22 @@ export class CreateFeatures implements FrontendApplicationContribution {
@inject(LocalCacheFsProvider)
private readonly localCacheFsProvider: LocalCacheFsProvider;

/**
* The keys are the Create URI of the sketches.
*/
private readonly _cloudSketchStates = new Map<string, CloudSketchState>();
private readonly onDidChangeSessionEmitter = new Emitter<
AuthenticationSession | undefined
>();
private readonly onDidChangeEnabledEmitter = new Emitter<boolean>();
private readonly onDidChangeCloudSketchStateEmitter = new Emitter<{
uri: URI;
state: CloudSketchState | undefined;
}>();
private readonly toDispose = new DisposableCollection(
this.onDidChangeSessionEmitter,
this.onDidChangeEnabledEmitter
this.onDidChangeEnabledEmitter,
this.onDidChangeCloudSketchStateEmitter
);
private _enabled: boolean;
private _session: AuthenticationSession | undefined;
Expand Down Expand Up @@ -64,14 +76,55 @@ export class CreateFeatures implements FrontendApplicationContribution {
return this.onDidChangeEnabledEmitter.event;
}

get enabled(): boolean {
return this._enabled;
get onDidChangeCloudSketchState(): Event<{
uri: URI;
state: CloudSketchState | undefined;
}> {
return this.onDidChangeCloudSketchStateEmitter.event;
}

get session(): AuthenticationSession | undefined {
return this._session;
}

get enabled(): boolean {
return this._enabled;
}

get cloudSketchStates(): {
uri: URI;
state: CloudSketchState | undefined;
}[] {
return Array.from(this._cloudSketchStates.entries()).map(
([uri, state]) => ({ uri: new URI(uri), state })
);
}

cloudSketchState(uri: URI): CloudSketchState | undefined {
return this._cloudSketchStates.get(uri.toString());
}

setCloudSketchState(uri: URI, state: CloudSketchState | undefined): void {
if (uri.scheme !== CreateUri.scheme) {
throw new Error(
`Expected a URI with '${uri.scheme}' scheme. Got: ${uri.toString()}`
);
}
const key = uri.toString();
if (!state) {
if (!this._cloudSketchStates.delete(key)) {
console.warn(
`Could not reset the cloud sketch state of ${key}. No state existed for the the cloud sketch.`
);
} else {
this.onDidChangeCloudSketchStateEmitter.fire({ uri, state: undefined });
}
} else {
this._cloudSketchStates.set(key, state);
this.onDidChangeCloudSketchStateEmitter.fire({ uri, state });
}
}

/**
* `true` if the sketch is under `directories.data/RemoteSketchbook`. Otherwise, `false`.
* Returns with `undefined` if `dataDirUri` is `undefined`.
Expand All @@ -83,7 +136,10 @@ export class CreateFeatures implements FrontendApplicationContribution {
);
return undefined;
}
return dataDirUri.isEqualOrParent(new URI(sketch.uri));
return dataDirUri
.resolve('RemoteSketchbook')
.resolve('ArduinoCloud')
.isEqualOrParent(new URI(sketch.uri));
}

cloudUri(sketch: Sketch): URI | undefined {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions arduino-ide-extension/src/browser/icons/arduino-cloud.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion arduino-ide-extension/src/browser/style/account-icon.svg

This file was deleted.

Loading

0 comments on commit feb39eb

Please sign in to comment.