Skip to content

Commit f41c79c

Browse files
committed
[dashboard] start with options by default
1 parent 994debf commit f41c79c

9 files changed

+418
-43
lines changed

components/dashboard/src/app/AppRoutes.tsx

Lines changed: 10 additions & 18 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"));
@@ -97,6 +97,8 @@ export const AppRoutes: FunctionComponent<AppRoutesProps> = ({ user, teams }) =>
9797
const hash = getURLHash();
9898
const { startWorkspaceModalProps, setStartWorkspaceModalProps } = useContext(StartWorkspaceModalContext);
9999
const [isWhatsNewShown, setWhatsNewShown] = useState(shouldSeeWhatsNew(user));
100+
const newCreateWsPage = useNewCreateWorkspacePage();
101+
const location = useLocation();
100102

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

107109
// TODO: Add a Route for this instead of inspecting location manually
108-
if (window.location.pathname.startsWith("/blocked")) {
110+
if (location.pathname.startsWith("/blocked")) {
109111
return <Blocked />;
110112
}
111113

112114
// TODO: Add a Route for this instead of inspecting location manually
113-
if (window.location.pathname.startsWith("/oauth-approval")) {
115+
if (location.pathname.startsWith("/oauth-approval")) {
114116
return <OAuthClientApproval />;
115117
}
116118

@@ -119,27 +121,16 @@ export const AppRoutes: FunctionComponent<AppRoutesProps> = ({ user, teams }) =>
119121
}
120122

121123
// 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 !== "";
124+
const isCreation = location.pathname === "/" && hash !== "";
123125
if (isCreation) {
124126
if (showUserIdePreference) {
125127
return (
126128
<StartPage phase={StartPhase.Checking}>
127129
<SelectIDEModal location="workspace_start" onClose={() => setShowUserIdePreference(false)} />
128130
</StartPage>
129131
);
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-
);
132+
} else if (new URLSearchParams(location.search).has("showOptions") || newCreateWsPage) {
133+
return <Redirect to={"/new" + location.pathname + location.search + location.hash} />;
143134
} else {
144135
return <CreateWorkspace contextUrl={hash} />;
145136
}
@@ -167,6 +158,7 @@ export const AppRoutes: FunctionComponent<AppRoutesProps> = ({ user, teams }) =>
167158
{isLocalPreview() && <LocalPreviewAlert />}
168159
<AppNotifications />
169160
<Switch>
161+
<Route path="/new" exact component={CreateWorkspacePage} />
170162
<Route path={projectsPathNew} exact component={NewProject} />
171163
<Route path="/open" exact component={Open} />
172164
<Route path="/setup" exact component={Setup} />

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/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.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)