Skip to content

feat: moved login entry point to the side-bar #1881

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@ import {
MenuContribution,
MenuModelRegistry,
} from '@theia/core';
import {
FrontendApplication,
FrontendApplicationContribution,
} from '@theia/core/lib/browser';
import { FrontendApplicationContribution } from '@theia/core/lib/browser';
import { ColorContribution } from '@theia/core/lib/browser/color-application-contribution';
import { ColorRegistry } from '@theia/core/lib/browser/color-registry';
import { CommonMenus } from '@theia/core/lib/browser/common-frontend-contribution';
Expand Down Expand Up @@ -77,7 +74,7 @@ export class ArduinoFrontendContribution
}
}

onStart(app: FrontendApplication): void {
onStart(): void {
this.electronWindowPreferences.onPreferenceChanged((event) => {
if (event.newValue !== event.oldValue) {
switch (event.preferenceName) {
Expand All @@ -98,8 +95,6 @@ export class ArduinoFrontendContribution
webContents.setZoomLevel(zoomLevel);
})
);
// Removes the _Settings_ (cog) icon from the left sidebar
app.shell.leftPanelHandler.removeBottomMenu('settings-menu');
}

registerToolbarItems(registry: TabBarToolbarRegistry): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,9 @@ import { ConfigServiceClient } from './config/config-service-client';
import { ValidateSketch } from './contributions/validate-sketch';
import { RenameCloudSketch } from './contributions/rename-cloud-sketch';
import { CreateFeatures } from './create/create-features';
import { Account } from './contributions/account';
import { SidebarBottomMenuWidget } from './theia/core/sidebar-bottom-menu-widget';
import { SidebarBottomMenuWidget as TheiaSidebarBottomMenuWidget } from '@theia/core/lib/browser/shell/sidebar-bottom-menu-widget';

export default new ContainerModule((bind, unbind, isBound, rebind) => {
// Commands and toolbar items
Expand Down Expand Up @@ -734,6 +737,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
Contribution.configure(bind, NewCloudSketch);
Contribution.configure(bind, ValidateSketch);
Contribution.configure(bind, RenameCloudSketch);
Contribution.configure(bind, Account);

bindContributionProvider(bind, StartupTaskProvider);
bind(StartupTaskProvider).toService(BoardsServiceProvider); // to reuse the boards config in another window
Expand Down Expand Up @@ -1014,4 +1018,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
},
}))
.inSingletonScope();

bind(SidebarBottomMenuWidget).toSelf();
rebind(TheiaSidebarBottomMenuWidget).toService(SidebarBottomMenuWidget);
});
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,13 @@ export class AuthenticationClientService
registerCommands(registry: CommandRegistry): void {
registry.registerCommand(CloudUserCommands.LOGIN, {
execute: () => this.service.login(),
isEnabled: () => !this._session,
isVisible: () => !this._session,
});
registry.registerCommand(CloudUserCommands.LOGOUT, {
execute: () => this.service.logout(),
isEnabled: () => !!this._session,
isVisible: () => !!this._session,
});
}

Expand Down
8 changes: 3 additions & 5 deletions arduino-ide-extension/src/browser/auth/cloud-user-commands.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { Command } from '@theia/core/lib/common/command';

export const LEARN_MORE_URL =
'https://docs.arduino.cc/software/ide-v2/tutorials/ide-v2-cloud-sketch-sync';

export namespace CloudUserCommands {
export const LOGIN = Command.toLocalizedCommand(
{
Expand All @@ -16,9 +19,4 @@ export namespace CloudUserCommands {
},
'arduino/cloud/signOut'
);

export const OPEN_PROFILE_CONTEXT_MENU: Command = {
id: 'arduino-cloud-sketchbook--open-profile-menu',
label: 'Contextual menu',
};
}
145 changes: 145 additions & 0 deletions arduino-ide-extension/src/browser/contributions/account.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { FrontendApplication } from '@theia/core/lib/browser/frontend-application';
import { SidebarMenu } from '@theia/core/lib/browser/shell/sidebar-menu-widget';
import { WindowService } from '@theia/core/lib/browser/window/window-service';
import { DisposableCollection } from '@theia/core/lib/common/disposable';
import { MenuPath } from '@theia/core/lib/common/menu';
import { nls } from '@theia/core/lib/common/nls';
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 {
Command,
CommandRegistry,
Contribution,
MenuModelRegistry,
} from './contribution';

export const accountMenu: SidebarMenu = {
id: 'arduino-accounts-menu',
iconClass: 'codicon codicon-account',
title: nls.localize('arduino/account/menuTitle', 'Arduino Cloud'),
menuPath: ArduinoMenus.ARDUINO_ACCOUNT__CONTEXT,
order: 0,
};

@injectable()
export class Account extends Contribution {
@inject(WindowService)
private readonly windowService: WindowService;
@inject(CreateFeatures)
private readonly createFeatures: CreateFeatures;

private readonly toDispose = new DisposableCollection();
private app: FrontendApplication;

override onStart(app: FrontendApplication): void {
this.app = app;
this.updateSidebarCommand();
this.toDispose.push(
this.createFeatures.onDidChangeEnabled((enabled) =>
this.updateSidebarCommand(enabled)
)
);
}

onStop(): void {
this.toDispose.dispose();
}

override registerCommands(registry: CommandRegistry): void {
const openExternal = (url: string) =>
this.windowService.openNewWindow(url, { external: true });
registry.registerCommand(Account.Commands.LEARN_MORE, {
execute: () => openExternal(LEARN_MORE_URL),
isEnabled: () => !Boolean(this.createFeatures.session),
});
registry.registerCommand(Account.Commands.GO_TO_PROFILE, {
execute: () => openExternal('https://id.arduino.cc/'),
isEnabled: () => Boolean(this.createFeatures.session),
});
registry.registerCommand(Account.Commands.GO_TO_CLOUD_EDITOR, {
execute: () => openExternal('https://create.arduino.cc/editor'),
isEnabled: () => Boolean(this.createFeatures.session),
});
registry.registerCommand(Account.Commands.GO_TO_IOT_CLOUD, {
execute: () => openExternal('https://create.arduino.cc/iot/'),
isEnabled: () => Boolean(this.createFeatures.session),
});
}

override registerMenus(registry: MenuModelRegistry): void {
const register = (
menuPath: MenuPath,
...commands: (Command | [command: Command, menuLabel: string])[]
) =>
commands.forEach((command, index) => {
const commandId = Array.isArray(command) ? command[0].id : command.id;
const label = Array.isArray(command) ? command[1] : command.label;
registry.registerMenuAction(menuPath, {
label,
commandId,
order: String(index),
});
});

register(ArduinoMenus.ARDUINO_ACCOUNT__CONTEXT__SIGN_IN_GROUP, [
CloudUserCommands.LOGIN,
nls.localize('arduino/cloud/signInToCloud', 'Sign in to Arduino Cloud'),
]);
register(ArduinoMenus.ARDUINO_ACCOUNT__CONTEXT__LEARN_MORE_GROUP, [
Account.Commands.LEARN_MORE,
nls.localize('arduino/cloud/learnMore', 'Learn more'),
]);
register(
ArduinoMenus.ARDUINO_ACCOUNT__CONTEXT__GO_TO_GROUP,
[
Account.Commands.GO_TO_PROFILE,
nls.localize('arduino/account/goToProfile', 'Go to Profile'),
],
[
Account.Commands.GO_TO_CLOUD_EDITOR,
nls.localize('arduino/account/goToCloudEditor', 'Go to Cloud Editor'),
],
[
Account.Commands.GO_TO_IOT_CLOUD,
nls.localize('arduino/account/goToIoTCloud', 'Go to IoT Cloud'),
]
);
register(
ArduinoMenus.ARDUINO_ACCOUNT__CONTEXT__SIGN_OUT_GROUP,
CloudUserCommands.LOGOUT
);
}

private updateSidebarCommand(
visible: boolean = this.preferences['arduino.cloud.enabled']
): void {
if (!this.app) {
return;
}
const handler = this.app.shell.leftPanelHandler;
if (visible) {
handler.addBottomMenu(accountMenu);
} else {
handler.removeBottomMenu(accountMenu.id);
}
}
}

export namespace Account {
export namespace Commands {
export const GO_TO_PROFILE: Command = {
id: 'arduino-go-to-profile',
};
export const GO_TO_CLOUD_EDITOR: Command = {
id: 'arduino-go-to-cloud-editor',
};
export const GO_TO_IOT_CLOUD: Command = {
id: 'arduino-go-to-iot-cloud',
};
export const LEARN_MORE: Command = {
id: 'arduino-learn-more',
};
}
}
19 changes: 19 additions & 0 deletions arduino-ide-extension/src/browser/menu/arduino-menus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,25 @@ export namespace ArduinoMenus {
'2_resources',
];

// -- Account
export const ARDUINO_ACCOUNT__CONTEXT = ['arduino-account--context'];
export const ARDUINO_ACCOUNT__CONTEXT__SIGN_IN_GROUP = [
...ARDUINO_ACCOUNT__CONTEXT,
'0_sign_in',
];
export const ARDUINO_ACCOUNT__CONTEXT__LEARN_MORE_GROUP = [
...ARDUINO_ACCOUNT__CONTEXT,
'1_learn_more',
];
export const ARDUINO_ACCOUNT__CONTEXT__GO_TO_GROUP = [
...ARDUINO_ACCOUNT__CONTEXT,
'2_go_to',
];
export const ARDUINO_ACCOUNT__CONTEXT__SIGN_OUT_GROUP = [
...ARDUINO_ACCOUNT__CONTEXT,
'3_sign_out',
];

// -- ROOT SSL CERTIFICATES
export const ROOT_CERTIFICATES__CONTEXT = [
'arduino-root-certificates--context',
Expand Down
4 changes: 2 additions & 2 deletions arduino-ide-extension/src/browser/style/cloud-sketchbook.css
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@

.account-icon {
background: url("./account-icon.svg") center center no-repeat;
width: var(--theia-icon-size);
height: var(--theia-icon-size);
width: var(--theia-private-sidebar-icon-size);
height: var(--theia-private-sidebar-icon-size);
border-radius: 50%;
overflow: hidden;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { SidebarBottomMenuWidget as TheiaSidebarBottomMenuWidget } from '@theia/core/lib/browser/shell/sidebar-bottom-menu-widget';
import type { SidebarMenu } from '@theia/core/lib/browser/shell/sidebar-menu-widget';
import type { MenuPath } from '@theia/core/lib/common/menu';
import { nls } from '@theia/core/lib/common/nls';
import {
inject,
injectable,
postConstruct,
} from '@theia/core/shared/inversify';
import * as React from '@theia/core/shared/react';
import { accountMenu } from '../../contributions/account';
import { CreateFeatures } from '../../create/create-features';

@injectable()
export class SidebarBottomMenuWidget extends TheiaSidebarBottomMenuWidget {
@inject(CreateFeatures)
private readonly createFeatures: CreateFeatures;

@postConstruct()
protected init(): void {
this.toDispose.push(
this.createFeatures.onDidChangeSession(() => this.update())
);
}

protected override onClick(
e: React.MouseEvent<HTMLElement, MouseEvent>,
menuPath: MenuPath
): void {
const button = e.currentTarget.getBoundingClientRect();
this.contextMenuRenderer.render({
menuPath,
includeAnchorArg: false,
anchor: {
x: button.left + button.width,
// Bogus y coordinate?
// https://github.com/eclipse-theia/theia/discussions/12170
y: button.top,
},
});
}

protected override render(): React.ReactNode {
return (
<React.Fragment>
{this.menus.map((menu) => this.renderMenu(menu))}
</React.Fragment>
);
}

private renderMenu(menu: SidebarMenu): React.ReactNode {
// Removes the _Settings_ (cog) icon from the left sidebar
if (menu.id === 'settings-menu') {
return undefined;
}
const arduinoAccount = menu.id === accountMenu.id;
const picture =
arduinoAccount && this.createFeatures.session?.account.picture;
const className = typeof picture === 'string' ? undefined : menu.iconClass;
return (
<i
key={menu.id}
className={className}
title={menu.title}
onClick={(e) => this.onClick(e, menu.menuPath)}
onMouseDown={this.onMouseDown}
onMouseOut={this.onMouseOut}
>
{picture && (
<div className="account-icon">
<img
src={picture}
alt={nls.localize(
'arduino/cloud/profilePicture',
'Profile picture'
)}
/>
</div>
)}
</i>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
injectable,
postConstruct,
} from '@theia/core/shared/inversify';
import { UserStatus } from './cloud-user-status';
import { CloudStatus } from './cloud-user-status';
import { nls } from '@theia/core/lib/common/nls';
import { CloudSketchbookTreeWidget } from './cloud-sketchbook-tree-widget';
import { AuthenticationClientService } from '../../auth/authentication-client-service';
Expand Down Expand Up @@ -61,7 +61,7 @@ export class CloudSketchbookCompositeWidget extends BaseSketchbookCompositeWidge
onClick={this.onDidClickCreateNew}
/>
)}
<UserStatus
<CloudStatus
model={
this.cloudSketchbookTreeWidget.model as CloudSketchbookTreeModel
}
Expand Down
Loading