Skip to content

Commit fcb62cf

Browse files
committed
[dashboard] start with options by default
1 parent dda547c commit fcb62cf

12 files changed

+435
-52
lines changed

components/dashboard/src/app/AppRoutes.tsx

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import SelectIDEModal from "../user-settings/SelectIDEModal";
1010
import { StartPage, StartPhase } from "../start/StartPage";
1111
import { getURLHash, isGitpodIo, isLocalPreview } from "../utils";
1212
import { shouldSeeWhatsNew, WhatsNew } from "../whatsnew/WhatsNew";
13-
import { Redirect, Route, Switch } from "react-router";
13+
import { Redirect, Route, Switch, useLocation } from "react-router";
1414
import Menu from "../menu/Menu";
1515
import { parseProps } from "../start/StartWorkspace";
1616
import { AppNotifications } from "../AppNotifications";
@@ -41,9 +41,9 @@ import { Blocked } from "./Blocked";
4141
import { BlockedRepositories } from "../admin/BlockedRepositories";
4242
import PersonalAccessTokenCreateView from "../user-settings/PersonalAccessTokensCreateView";
4343
import { StartWorkspaceModalContext } from "../workspaces/start-workspace-modal-context";
44-
import { StartWorkspaceOptions } from "../start/start-workspace-options";
4544
import { WebsocketClients } from "./WebsocketClients";
4645
import { OrgRequiredRoute } from "./OrgRequiredRoute";
46+
import { CreateWorkspacePage, useNewCreateWorkspacePage } from "../workspaces/CreateWorkspacePage";
4747

4848
const Setup = React.lazy(() => import(/* webpackPrefetch: true */ "../Setup"));
4949
const Workspaces = React.lazy(() => import(/* webpackPrefetch: true */ "../workspaces/Workspaces"));
@@ -61,7 +61,6 @@ const Preferences = React.lazy(() => import(/* webpackPrefetch: true */ "../user
6161
const PersonalAccessTokens = React.lazy(
6262
() => import(/* webpackPrefetch: true */ "../user-settings/PersonalAccessTokens"),
6363
);
64-
const Open = React.lazy(() => import(/* webpackPrefetch: true */ "../start/Open"));
6564
const StartWorkspace = React.lazy(() => import(/* webpackPrefetch: true */ "../start/StartWorkspace"));
6665
const CreateWorkspace = React.lazy(() => import(/* webpackPrefetch: true */ "../start/CreateWorkspace"));
6766
const NewTeam = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/NewTeam"));
@@ -97,6 +96,8 @@ export const AppRoutes: FunctionComponent<AppRoutesProps> = ({ user, teams }) =>
9796
const hash = getURLHash();
9897
const { startWorkspaceModalProps, setStartWorkspaceModalProps } = useContext(StartWorkspaceModalContext);
9998
const [isWhatsNewShown, setWhatsNewShown] = useState(shouldSeeWhatsNew(user));
99+
const newCreateWsPage = useNewCreateWorkspacePage();
100+
const location = useLocation();
100101

101102
// Prefix with `/#referrer` will specify an IDE for workspace
102103
// We don't need to show IDE preference in this case
@@ -105,12 +106,12 @@ export const AppRoutes: FunctionComponent<AppRoutesProps> = ({ user, teams }) =>
105106
);
106107

107108
// TODO: Add a Route for this instead of inspecting location manually
108-
if (window.location.pathname.startsWith("/blocked")) {
109+
if (location.pathname.startsWith("/blocked")) {
109110
return <Blocked />;
110111
}
111112

112113
// TODO: Add a Route for this instead of inspecting location manually
113-
if (window.location.pathname.startsWith("/oauth-approval")) {
114+
if (location.pathname.startsWith("/oauth-approval")) {
114115
return <OAuthClientApproval />;
115116
}
116117

@@ -119,27 +120,16 @@ export const AppRoutes: FunctionComponent<AppRoutesProps> = ({ user, teams }) =>
119120
}
120121

121122
// TODO: Try and encapsulate this in a route for "/" (check for hash in route component, render or redirect accordingly)
122-
const isCreation = window.location.pathname === "/" && hash !== "";
123+
const isCreation = location.pathname === "/" && hash !== "";
123124
if (isCreation) {
124125
if (showUserIdePreference) {
125126
return (
126127
<StartPage phase={StartPhase.Checking}>
127128
<SelectIDEModal location="workspace_start" onClose={() => setShowUserIdePreference(false)} />
128129
</StartPage>
129130
);
130-
} else if (new URLSearchParams(window.location.search).has("showOptions")) {
131-
const props = StartWorkspaceOptions.parseSearchParams(window.location.search);
132-
return (
133-
<StartWorkspaceModal
134-
{...{
135-
contextUrl: hash,
136-
ide: props?.ideSettings?.defaultIde,
137-
uselatestIde: props?.ideSettings?.useLatestVersion,
138-
workspaceClass: props.workspaceClass,
139-
onClose: undefined,
140-
}}
141-
/>
142-
);
131+
} else if (new URLSearchParams(location.search).has("showOptions") || newCreateWsPage) {
132+
return <Redirect to={"/new" + location.pathname + location.search + location.hash} />;
143133
} else {
144134
return <CreateWorkspace contextUrl={hash} />;
145135
}
@@ -167,8 +157,11 @@ export const AppRoutes: FunctionComponent<AppRoutesProps> = ({ user, teams }) =>
167157
{isLocalPreview() && <LocalPreviewAlert />}
168158
<AppNotifications />
169159
<Switch>
160+
<Route path="/new" exact component={CreateWorkspacePage} />
170161
<Route path={projectsPathNew} exact component={NewProject} />
171-
<Route path="/open" exact component={Open} />
162+
<Route path="/open">
163+
<Redirect to="/new" />
164+
</Route>
172165
<Route path="/setup" exact component={Setup} />
173166
<Route path={workspacesPathMain} exact component={Workspaces} />
174167
<Route path={settingsPathAccount} exact component={Account} />

components/dashboard/src/contexts/FeatureFlagContext.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ interface FeatureFlagConfig {
1515
}
1616

1717
const FeatureFlagContext = createContext<{
18+
startWithOptions: boolean;
1819
showUsageView: boolean;
1920
isUsageBasedBillingEnabled: boolean;
2021
showUseLastSuccessfulPrebuild: boolean;
@@ -23,6 +24,7 @@ const FeatureFlagContext = createContext<{
2324
oidcServiceEnabled: boolean;
2425
orgGitAuthProviders: boolean;
2526
}>({
27+
startWithOptions: false,
2628
showUsageView: false,
2729
isUsageBasedBillingEnabled: false,
2830
showUseLastSuccessfulPrebuild: false,
@@ -37,6 +39,7 @@ const FeatureFlagContextProvider: React.FC = ({ children }) => {
3739
const teams = useTeams();
3840
const { project } = useContext(ProjectContext);
3941
const team = useCurrentTeam();
42+
const [startWithOptions, setStartWithOptions] = useState<boolean>(false);
4043
const [showUsageView, setShowUsageView] = useState<boolean>(false);
4144
const [isUsageBasedBillingEnabled, setIsUsageBasedBillingEnabled] = useState<boolean>(false);
4245
const [showUseLastSuccessfulPrebuild, setShowUseLastSuccessfulPrebuild] = useState<boolean>(false);
@@ -49,6 +52,7 @@ const FeatureFlagContextProvider: React.FC = ({ children }) => {
4952
if (!user) return;
5053
(async () => {
5154
const featureFlags: FeatureFlagConfig = {
55+
start_with_options: { defaultValue: false, setter: setStartWithOptions },
5256
usage_view: { defaultValue: false, setter: setShowUsageView },
5357
isUsageBasedBillingEnabled: { defaultValue: false, setter: setIsUsageBasedBillingEnabled },
5458
showUseLastSuccessfulPrebuild: { defaultValue: false, setter: setShowUseLastSuccessfulPrebuild },
@@ -98,6 +102,7 @@ const FeatureFlagContextProvider: React.FC = ({ children }) => {
98102
return (
99103
<FeatureFlagContext.Provider
100104
value={{
105+
startWithOptions,
101106
showUsageView,
102107
isUsageBasedBillingEnabled,
103108
showUseLastSuccessfulPrebuild,

components/dashboard/src/projects/NewProject.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import exclamation from "../images/exclamation.svg";
2121
import ErrorMessage from "../components/ErrorMessage";
2222
import Spinner from "../icons/Spinner.svg";
2323
import { useRefreshProjects } from "../data/projects/list-projects-query";
24+
import { projectsPathNew } from "./projects.routes";
2425

2526
export default function NewProject() {
2627
const currentTeam = useCurrentTeam();
@@ -625,7 +626,7 @@ function GitProviders(props: {
625626

626627
async function openReconfigureWindow(params: { account?: string; onSuccess: (p: any) => void }) {
627628
const { account, onSuccess } = params;
628-
const state = btoa(JSON.stringify({ from: "/reconfigure", next: "/new" }));
629+
const state = btoa(JSON.stringify({ from: "/reconfigure", next: projectsPathNew }));
629630
const url = gitpodHostUrl
630631
.withApi({
631632
pathname: "/apps/github/reconfigure",

components/dashboard/src/projects/Project.tsx

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import NoAccess from "../icons/NoAccess.svg";
1616
import { ReactComponent as Spinner } from "../icons/Spinner.svg";
1717
import { openAuthorizeWindow } from "../provider-utils";
1818
import { getGitpodService, gitpodHostUrl } from "../service/service";
19+
import { useNewCreateWorkspacePage } from "../workspaces/CreateWorkspacePage";
1920
import { StartWorkspaceModalContext } from "../workspaces/start-workspace-modal-context";
2021
import { prebuildStatusIcon, prebuildStatusLabel } from "./Prebuilds";
2122
import { useCurrentProject } from "./project-context";
@@ -39,6 +40,8 @@ export default function ProjectsPage() {
3940

4041
const [showAuthBanner, setShowAuthBanner] = useState<{ host: string } | undefined>(undefined);
4142

43+
const isNewCreateWsPage = useNewCreateWorkspacePage();
44+
4245
useEffect(() => {
4346
// project changed, reset state
4447
setBranches([]);
@@ -375,15 +378,19 @@ export default function ProjectsPage() {
375378
<ItemFieldContextMenu
376379
className="py-0.5"
377380
menuEntries={[
378-
{
379-
title: "New Workspace ...",
380-
onClick: () =>
381-
setStartWorkspaceModalProps({
382-
contextUrl: branch.url,
383-
allowContextUrlChange: true,
384-
}),
385-
separator: true,
386-
},
381+
...(isNewCreateWsPage
382+
? []
383+
: [
384+
{
385+
title: "New Workspace ...",
386+
onClick: () =>
387+
setStartWorkspaceModalProps({
388+
contextUrl: branch.url,
389+
allowContextUrlChange: true,
390+
}),
391+
separator: true,
392+
},
393+
]),
387394
prebuild?.status === "queued" ||
388395
prebuild?.status === "building"
389396
? {

components/dashboard/src/projects/ProjectListItem.tsx

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { prebuildStatusIcon } from "./Prebuilds";
1515
import { gitpodHostUrl } from "../service/service";
1616
import { useLatestProjectPrebuildQuery } from "../data/prebuilds/latest-project-prebuild-query";
1717
import { StartWorkspaceModalContext } from "../workspaces/start-workspace-modal-context";
18+
import { useNewCreateWorkspacePage } from "../workspaces/CreateWorkspacePage";
1819

1920
type ProjectListItemProps = {
2021
project: Project;
@@ -25,6 +26,7 @@ export const ProjectListItem: FunctionComponent<ProjectListItemProps> = ({ proje
2526
const [showRemoveModal, setShowRemoveModal] = useState(false);
2627
const { data: prebuild, isLoading } = useLatestProjectPrebuildQuery({ projectId: project.id });
2728
const { setStartWorkspaceModalProps } = useContext(StartWorkspaceModalContext);
29+
const isNewCreateWsPage = useNewCreateWorkspacePage();
2830

2931
return (
3032
<div key={`project-${project.id}`} className="h-52">
@@ -41,15 +43,19 @@ export const ProjectListItem: FunctionComponent<ProjectListItemProps> = ({ proje
4143
href: gitpodHostUrl.withContext(`${project.cloneUrl}`).toString(),
4244
separator: true,
4345
},
44-
{
45-
title: "New Workspace ...",
46-
onClick: () =>
47-
setStartWorkspaceModalProps({
48-
contextUrl: project.cloneUrl,
49-
allowContextUrlChange: true,
50-
}),
51-
separator: true,
52-
},
46+
...(isNewCreateWsPage
47+
? []
48+
: [
49+
{
50+
title: "New Workspace ...",
51+
onClick: () =>
52+
setStartWorkspaceModalProps({
53+
contextUrl: project.cloneUrl,
54+
allowContextUrlChange: true,
55+
}),
56+
separator: true,
57+
},
58+
]),
5359
{
5460
title: "Remove Project",
5561
customFontStyle:

components/dashboard/src/projects/Projects.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,18 @@ import Alert from "../components/Alert";
1717
import { ProjectListItem } from "./ProjectListItem";
1818
import { SpinnerLoader } from "../components/Loader";
1919
import { useListProjectsQuery } from "../data/projects/list-projects-query";
20+
import { projectsPathNew } from "./projects.routes";
2021

2122
export default function ProjectsPage() {
2223
const history = useHistory();
2324
const team = useCurrentTeam();
2425
const { data, isLoading, isError, refetch } = useListProjectsQuery();
2526
const { isDark } = useContext(ThemeContext);
2627
const [searchFilter, setSearchFilter] = useState<string | undefined>();
27-
const newProjectUrl = `/new`;
2828

2929
const onNewProject = useCallback(() => {
30-
history.push(newProjectUrl);
31-
}, [history, newProjectUrl]);
30+
history.push(projectsPathNew);
31+
}, [history]);
3232

3333
const filteredProjects = useMemo(() => {
3434
const filter = (project: Project) => {
@@ -80,7 +80,7 @@ export default function ProjectsPage() {
8080
</a>
8181
</p>
8282
<div className="flex space-x-2 justify-center mt-7">
83-
<Link to={newProjectUrl}>
83+
<Link to={projectsPathNew}>
8484
<button>New Project</button>
8585
</Link>
8686
{team && (
@@ -135,7 +135,7 @@ export default function ProjectsPage() {
135135
key="new-project"
136136
className="h-52 border-dashed border-2 border-gray-100 dark:border-gray-800 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-xl focus:bg-gitpod-kumquat-light transition ease-in-out group"
137137
>
138-
<Link to={newProjectUrl} data-analytics='{"button_type":"card"}'>
138+
<Link to={projectsPathNew} data-analytics='{"button_type":"card"}'>
139139
<div className="flex h-full">
140140
<div className="m-auto text-gray-400 dark:text-gray-600">New Project</div>
141141
</div>

components/dashboard/src/projects/projects.routes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export const projectsPathMain = "/projects";
1111
export const projectsPathMainWithParams = [projectsPathMain, ":projectName", ":resourceOrPrebuild?"].join("/");
1212

1313
export const projectsPathInstallGitHubApp = "/install-github-app";
14-
export const projectsPathNew = "/new";
14+
export const projectsPathNew = "/projects/new";
1515

1616
export function getProjectTabs(project: Project | undefined): TabEntry[] {
1717
if (!project) {

components/dashboard/src/start/CreateWorkspace.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ export function CreateWorkspace({ contextUrl }: CreateWorkspaceProps) {
325325
);
326326
}
327327

328-
function SelectCostCenterModal(props: { onSelected?: () => void }) {
328+
export function SelectCostCenterModal(props: { onSelected?: () => void }) {
329329
return (
330330
<Modal visible={true} closeable={false} onClose={() => {}}>
331331
<h3>Choose Billing Organization</h3>
@@ -334,7 +334,7 @@ function SelectCostCenterModal(props: { onSelected?: () => void }) {
334334
);
335335
}
336336

337-
function LimitReachedModal(p: { children: React.ReactNode }) {
337+
export function LimitReachedModal(p: { children: React.ReactNode }) {
338338
const { user } = useContext(UserContext);
339339
return (
340340
// TODO: Use title and buttons props
@@ -358,7 +358,7 @@ function LimitReachedModal(p: { children: React.ReactNode }) {
358358
);
359359
}
360360

361-
function LimitReachedParallelWorkspacesModal() {
361+
export function LimitReachedParallelWorkspacesModal() {
362362
return (
363363
<LimitReachedModal>
364364
<p className="mt-1 mb-2 text-base dark:text-gray-400">
@@ -369,7 +369,7 @@ function LimitReachedParallelWorkspacesModal() {
369369
);
370370
}
371371

372-
function LimitReachedOutOfHours() {
372+
export function LimitReachedOutOfHours() {
373373
return (
374374
<LimitReachedModal>
375375
<p className="mt-1 mb-2 text-base dark:text-gray-400">
@@ -380,7 +380,7 @@ function LimitReachedOutOfHours() {
380380
);
381381
}
382382

383-
function RepositoryNotFoundView(p: { error: StartWorkspaceError }) {
383+
export function RepositoryNotFoundView(p: { error: StartWorkspaceError }) {
384384
const [statusMessage, setStatusMessage] = useState<React.ReactNode>();
385385
const { host, owner, repoName, userIsOwner, userScopes, lastUpdate } = p.error.data;
386386
const repoFullName = owner && repoName ? `${owner}/${repoName}` : "";

0 commit comments

Comments
 (0)