Skip to content

Commit c566c5b

Browse files
committed
[dashboard] Enable the 'New Workspace' modal on all dashboard pages (Cmd/Ctrl+O)
1 parent 2802901 commit c566c5b

File tree

5 files changed

+54
-31
lines changed

5 files changed

+54
-31
lines changed

components/dashboard/src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { workspacesPathMain } from './workspaces/workspaces.routes';
2626
import { settingsPathAccount, settingsPathIntegrations, settingsPathMain, settingsPathNotifications, settingsPathPlans, settingsPathPreferences, settingsPathTeams, settingsPathTeamsJoin, settingsPathTeamsNew, settingsPathVariables } from './settings/settings.routes';
2727
import { projectsPathInstallGitHubApp, projectsPathMain, projectsPathMainWithParams, projectsPathNew } from './projects/projects.routes';
2828
import { refreshSearchData } from './components/RepositoryFinder';
29+
import { StartWorkspaceModal } from './workspaces/StartWorkspaceModal';
2930

3031
const Setup = React.lazy(() => import(/* webpackPrefetch: true */ './Setup'));
3132
const Workspaces = React.lazy(() => import(/* webpackPrefetch: true */ './workspaces/Workspaces'));
@@ -392,6 +393,7 @@ function App() {
392393
}}>
393394
</Route>
394395
</Switch>
396+
<StartWorkspaceModal />
395397
</div>
396398
</Route>;
397399

components/dashboard/src/index.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { AdminContextProvider } from './admin-context';
1212
import { TeamsContextProvider } from './teams/teams-context';
1313
import { ProjectContextProvider } from './projects/project-context';
1414
import { ThemeContextProvider } from './theme-context';
15+
import { StartWorkspaceModalContextProvider } from './workspaces/start-workspace-modal-context';
1516
import { BrowserRouter } from 'react-router-dom';
1617

1718
import "./index.css"
@@ -23,9 +24,11 @@ ReactDOM.render(
2324
<TeamsContextProvider>
2425
<ProjectContextProvider>
2526
<ThemeContextProvider>
26-
<BrowserRouter>
27-
<App />
28-
</BrowserRouter>
27+
<StartWorkspaceModalContextProvider>
28+
<BrowserRouter>
29+
<App />
30+
</BrowserRouter>
31+
</StartWorkspaceModalContextProvider>
2932
</ThemeContextProvider>
3033
</ProjectContextProvider>
3134
</TeamsContextProvider>

components/dashboard/src/workspaces/StartWorkspaceModal.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,16 @@
44
* See License-AGPL.txt in the project root for license information.
55
*/
66

7+
import { useContext } from "react";
78
import Modal from "../components/Modal";
89
import RepositoryFinder from "../components/RepositoryFinder";
10+
import { StartWorkspaceModalContext } from "./start-workspace-modal-context";
911

10-
interface StartWorkspaceModalProps {
11-
visible: boolean;
12-
onClose: () => void;
13-
}
12+
export function StartWorkspaceModal() {
13+
const { isStartWorkspaceModalVisible, setIsStartWorkspaceModalVisible } = useContext(StartWorkspaceModalContext);
1414

15-
export function StartWorkspaceModal(props: StartWorkspaceModalProps) {
16-
return <Modal onClose={props.onClose} onEnter={() => false} visible={props.visible}>
15+
return <Modal onClose={() => setIsStartWorkspaceModalVisible(false)} onEnter={() => false} visible={!!isStartWorkspaceModalVisible}>
1716
<h3 className="pb-2">New Workspace</h3>
18-
{/* separator */}
1917
<div className="border-t border-gray-200 dark:border-gray-800 mt-2 -mx-6 px-6 pt-4">
2018
<h4 className="text-base">Search or paste a repository URL</h4>
2119
<RepositoryFinder />

components/dashboard/src/workspaces/Workspaces.tsx

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ import DropDown from "../components/DropDown";
1111
import { WorkspaceModel } from "./workspace-model";
1212
import { WorkspaceEntry } from "./WorkspaceEntry";
1313
import { getGitpodService } from "../service/service";
14-
import { StartWorkspaceModal } from "./StartWorkspaceModal";
1514
import { ItemsList } from "../components/ItemsList";
1615
import { TeamsContext } from "../teams/teams-context";
1716
import { useLocation } from "react-router";
17+
import { StartWorkspaceModalContext, StartWorkspaceModalKeyBinding } from "./start-workspace-modal-context";
1818

1919
export interface WorkspacesProps {
2020
}
@@ -31,8 +31,8 @@ export default function () {
3131
const { teams } = useContext(TeamsContext);
3232
const [activeWorkspaces, setActiveWorkspaces] = useState<WorkspaceInfo[]>([]);
3333
const [inactiveWorkspaces, setInactiveWorkspaces] = useState<WorkspaceInfo[]>([]);
34-
const [isTemplateModelOpen, setIsTemplateModelOpen] = useState<boolean>(false);
3534
const [workspaceModel, setWorkspaceModel] = useState<WorkspaceModel>();
35+
const { setIsStartWorkspaceModalVisible } = useContext(StartWorkspaceModalContext);
3636

3737
useEffect(() => {
3838
(async () => {
@@ -41,22 +41,6 @@ export default function () {
4141
})();
4242
}, [teams, location]);
4343

44-
const showStartWSModal = () => setIsTemplateModelOpen(true);
45-
const hideStartWSModal = () => setIsTemplateModelOpen(false);
46-
47-
useEffect(() => {
48-
const onKeyDown = (event: KeyboardEvent) => {
49-
if ((event.metaKey || event.ctrlKey) && ['k', 'o', 'p'].includes(event.key)) {
50-
event.preventDefault();
51-
showStartWSModal();
52-
}
53-
};
54-
window.addEventListener('keydown', onKeyDown);
55-
return () => {
56-
window.removeEventListener('keydown', onKeyDown);
57-
}
58-
}, []);
59-
6044
return <>
6145
<Header title="Workspaces" subtitle="Manage recent and stopped workspaces." />
6246

@@ -85,7 +69,7 @@ export default function () {
8569
onClick: () => { if (workspaceModel) workspaceModel.limit = 200; }
8670
}]} />
8771
</div>
88-
<button onClick={showStartWSModal} className="ml-2">New Workspace</button>
72+
<button onClick={() => setIsStartWorkspaceModalVisible(true)} className="ml-2">New Workspace ({StartWorkspaceModalKeyBinding})</button>
8973
</div>
9074
<ItemsList className="app-container pb-40">
9175
<div className="border-t border-gray-200 dark:border-gray-800"></div>
@@ -115,14 +99,13 @@ export default function () {
11599
<h3 className="text-center pb-3 text-gray-500 dark:text-gray-400">No Workspaces</h3>
116100
<div className="text-center pb-6 text-gray-500">Prefix any Git repository URL with {window.location.host}/# or create a new workspace for a recently used project. <a className="gp-link" href="https://www.gitpod.io/docs/getting-started/">Learn more</a></div>
117101
<span>
118-
<button onClick={showStartWSModal}>New Workspace</button>
102+
<button onClick={() => setIsStartWorkspaceModalVisible(true)}>New Workspace ({StartWorkspaceModalKeyBinding})</button>
119103
</span>
120104
</>
121105
</div>
122106
</div>
123107
</div>
124108
)}
125-
<StartWorkspaceModal onClose={hideStartWSModal} visible={!!isTemplateModelOpen} />
126109
</>;
127110

128111
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* Copyright (c) 2022 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License-AGPL.txt in the project root for license information.
5+
*/
6+
7+
import React, { createContext, useEffect, useState } from 'react';
8+
9+
export const StartWorkspaceModalContext = createContext<{
10+
isStartWorkspaceModalVisible?: boolean,
11+
setIsStartWorkspaceModalVisible: React.Dispatch<boolean>,
12+
}>({
13+
setIsStartWorkspaceModalVisible: () => null,
14+
});
15+
16+
export const StartWorkspaceModalContextProvider: React.FC = ({ children }) => {
17+
const [ isStartWorkspaceModalVisible, setIsStartWorkspaceModalVisible ] = useState<boolean>(false);
18+
19+
useEffect(() => {
20+
const onKeyDown = (event: KeyboardEvent) => {
21+
if ((event.metaKey || event.ctrlKey) && event.key === 'o') {
22+
event.preventDefault();
23+
setIsStartWorkspaceModalVisible(true);
24+
}
25+
};
26+
window.addEventListener('keydown', onKeyDown);
27+
return () => {
28+
window.removeEventListener('keydown', onKeyDown);
29+
}
30+
}, []);
31+
32+
return <StartWorkspaceModalContext.Provider value={{ isStartWorkspaceModalVisible, setIsStartWorkspaceModalVisible }}>
33+
{children}
34+
</StartWorkspaceModalContext.Provider>;
35+
}
36+
37+
export const StartWorkspaceModalKeyBinding = `${/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform) ? '⌘' : 'Ctrl+'}O`;

0 commit comments

Comments
 (0)