+
-
+
)
case backendModule.ProjectState.opened:
@@ -368,15 +398,22 @@ export default function ProjectIcon(props: ProjectIconProps) {
onClick={async clickEvent => {
clickEvent.stopPropagation()
unsetModal()
- await closeProject()
+ await closeProject(!isRunningInBackground)
}}
>
-
+
-
+
- {!isOtherUserUsingProject && (
+ {!isOtherUserUsingProject && !isRunningInBackground && (
)}
diff --git a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/projectNameColumn.tsx b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/projectNameColumn.tsx
index c36ad4f1b1..7178492599 100644
--- a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/projectNameColumn.tsx
+++ b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/projectNameColumn.tsx
@@ -129,6 +129,7 @@ export default function ProjectNameColumn(props: ProjectNameColumnProps) {
type: assetEventModule.AssetEventType.openProject,
id: createdProject.projectId,
shouldAutomaticallySwitchPage: true,
+ runInBackground: false,
})
} catch (error) {
dispatchAssetListEvent({
@@ -225,12 +226,20 @@ export default function ProjectNameColumn(props: ProjectNameColumnProps) {
onClick={event => {
if (rowState.isEditingName || isOtherUserUsingProject) {
// The project should neither be edited nor opened in these cases.
- } else if (eventModule.isDoubleClick(event)) {
+ } else if (shortcuts.matchesMouseAction(shortcutsModule.MouseAction.open, event)) {
// It is a double click; open the project.
dispatchAssetEvent({
type: assetEventModule.AssetEventType.openProject,
id: asset.id,
shouldAutomaticallySwitchPage: true,
+ runInBackground: false,
+ })
+ } else if (shortcuts.matchesMouseAction(shortcutsModule.MouseAction.run, event)) {
+ dispatchAssetEvent({
+ type: assetEventModule.AssetEventType.openProject,
+ id: asset.id,
+ shouldAutomaticallySwitchPage: false,
+ runInBackground: true,
})
} else if (
!isRunning &&
diff --git a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/events/assetEvent.ts b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/events/assetEvent.ts
index 412aa584c0..edd31f775e 100644
--- a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/events/assetEvent.ts
+++ b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/events/assetEvent.ts
@@ -86,6 +86,7 @@ export interface AssetNewSecretEvent extends AssetBaseEvent
{
id: backendModule.ProjectId
shouldAutomaticallySwitchPage: boolean
+ runInBackground: boolean
}
/** A signal to close the specified project. */
diff --git a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/remoteBackend.ts b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/remoteBackend.ts
index cd42040991..193b6c7cc7 100644
--- a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/remoteBackend.ts
+++ b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/remoteBackend.ts
@@ -23,6 +23,7 @@ const STATUS_SERVER_ERROR = 500
/** Default HTTP body for an "open project" request. */
const DEFAULT_OPEN_PROJECT_BODY: backendModule.OpenProjectRequestBody = {
forceCreate: false,
+ executeAsync: false,
}
// ============================
diff --git a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/shortcuts.tsx b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/shortcuts.tsx
index 46fc124546..03b17c08e7 100644
--- a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/shortcuts.tsx
+++ b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/shortcuts.tsx
@@ -16,6 +16,7 @@ import DuplicateIcon from 'enso-assets/duplicate.svg'
import OpenIcon from 'enso-assets/open.svg'
import PenIcon from 'enso-assets/pen.svg'
import PeopleIcon from 'enso-assets/people.svg'
+import Play2Icon from 'enso-assets/play2.svg'
import ScissorsIcon from 'enso-assets/scissors.svg'
import SignInIcon from 'enso-assets/sign_in.svg'
import SignOutIcon from 'enso-assets/sign_out.svg'
@@ -39,6 +40,9 @@ export const ICON_SIZE_PX = 16
/** All possible mouse actions for which shortcuts can be registered. */
export enum MouseAction {
+ open = 'open',
+ /** Run without opening the editor. */
+ run = 'run',
editName = 'edit-name',
selectAdditional = 'select-additional',
selectRange = 'select-range',
@@ -48,6 +52,8 @@ export enum MouseAction {
/** All possible keyboard actions for which shortcuts can be registered. */
export enum KeyboardAction {
open = 'open',
+ /** Run without opening the editor. */
+ run = 'run',
close = 'close',
uploadToCloud = 'upload-to-cloud',
rename = 'rename',
@@ -103,6 +109,7 @@ export interface KeyboardShortcut extends Modifiers {
export interface MouseShortcut extends Modifiers {
button: MouseButton
action: MouseAction
+ clicks: number
}
/** All possible modifier keys. */
@@ -146,6 +153,7 @@ export function isTextInputEvent(event: KeyboardEvent | React.KeyboardEvent) {
function makeKeyboardActionMap(make: () => T): Record {
return {
[KeyboardAction.open]: make(),
+ [KeyboardAction.run]: make(),
[KeyboardAction.close]: make(),
[KeyboardAction.uploadToCloud]: make(),
[KeyboardAction.rename]: make(),
@@ -279,7 +287,11 @@ export class ShortcutRegistry {
shortcut: MouseShortcut,
event: MouseEvent | React.MouseEvent
) {
- return shortcut.button === event.button && modifiersMatchEvent(shortcut, event)
+ return (
+ shortcut.button === event.button &&
+ event.detail >= shortcut.clicks &&
+ modifiersMatchEvent(shortcut, event)
+ )
}
/** Return `true` if the action is being triggered by the keyboard event. */
@@ -387,11 +399,13 @@ function keybind(action: KeyboardAction, modifiers: ModifierKey[], key: string):
function mousebind(
action: MouseAction,
modifiers: ModifierKey[],
- button: MouseButton
+ button: MouseButton,
+ clicks: number
): MouseShortcut {
return {
button,
action,
+ clicks,
ctrl: modifiers.includes('Ctrl'),
alt: modifiers.includes('Alt'),
shift: modifiers.includes('Shift'),
@@ -412,6 +426,7 @@ const DELETE = detect.isOnMacOS() ? 'Backspace' : 'Delete'
/** The default keyboard shortcuts. */
const DEFAULT_KEYBOARD_SHORTCUTS: Record = {
[KeyboardAction.open]: [keybind(KeyboardAction.open, [], 'Enter')],
+ [KeyboardAction.run]: [keybind(KeyboardAction.run, ['Shift'], 'Enter')],
[KeyboardAction.close]: [],
[KeyboardAction.uploadToCloud]: [],
[KeyboardAction.rename]: [keybind(KeyboardAction.rename, [CTRL], 'R')],
@@ -440,6 +455,7 @@ const DEFAULT_KEYBOARD_SHORTCUTS: Record = {
/** The default UI data for every keyboard shortcut. */
const DEFAULT_KEYBOARD_SHORTCUT_INFO: Record = {
[KeyboardAction.open]: { name: 'Open', icon: OpenIcon },
+ [KeyboardAction.run]: { name: 'Run', icon: Play2Icon },
[KeyboardAction.close]: { name: 'Close', icon: CloseIcon },
[KeyboardAction.uploadToCloud]: { name: 'Upload To Cloud', icon: CloudToIcon },
[KeyboardAction.rename]: { name: 'Rename', icon: PenIcon },
@@ -474,12 +490,14 @@ const DEFAULT_KEYBOARD_SHORTCUT_INFO: Record = {
/** The default mouse shortcuts. */
const DEFAULT_MOUSE_SHORTCUTS: Record = {
- [MouseAction.editName]: [mousebind(MouseAction.editName, [CTRL], MouseButton.left)],
+ [MouseAction.open]: [mousebind(MouseAction.open, [], MouseButton.left, 2)],
+ [MouseAction.run]: [mousebind(MouseAction.run, ['Shift'], MouseButton.left, 2)],
+ [MouseAction.editName]: [mousebind(MouseAction.editName, [CTRL], MouseButton.left, 1)],
[MouseAction.selectAdditional]: [
- mousebind(MouseAction.selectAdditional, [CTRL], MouseButton.left),
+ mousebind(MouseAction.selectAdditional, [CTRL], MouseButton.left, 1),
],
- [MouseAction.selectRange]: [mousebind(MouseAction.selectRange, ['Shift'], MouseButton.left)],
+ [MouseAction.selectRange]: [mousebind(MouseAction.selectRange, ['Shift'], MouseButton.left, 1)],
[MouseAction.selectAdditionalRange]: [
- mousebind(MouseAction.selectAdditionalRange, [CTRL, 'Shift'], MouseButton.left),
+ mousebind(MouseAction.selectAdditionalRange, [CTRL, 'Shift'], MouseButton.left, 1),
],
}
diff --git a/app/ide-desktop/lib/dashboard/tailwind.config.ts b/app/ide-desktop/lib/dashboard/tailwind.config.ts
index 6295983b79..ac1e43ad3c 100644
--- a/app/ide-desktop/lib/dashboard/tailwind.config.ts
+++ b/app/ide-desktop/lib/dashboard/tailwind.config.ts
@@ -35,6 +35,7 @@ export const theme = {
cloud: '#0666be',
share: '#64b526',
inversed: '#ffffff',
+ green: '#3e8b29',
delete: 'rgba(243, 24, 10, 0.87)',
v3: '#252423',
youtube: '#c62421',