Path: blob/main/components/dashboard/src/app/AppRoutes.tsx
2499 views
/**1* Copyright (c) 2022 Gitpod GmbH. All rights reserved.2* Licensed under the GNU Affero General Public License (AGPL).3* See License.AGPL.txt in the project root for license information.4*/56import React from "react";7import { Redirect, Route, Switch, useLocation } from "react-router";8import OAuthClientApproval from "../OauthClientApproval";9import Menu from "../menu/Menu";10import { parseProps } from "../start/StartWorkspace";11import {12settingsPathAccount,13settingsPathIntegrations,14settingsPathMain,15settingsPathNotifications,16settingsPathPersonalAccessTokenCreate,17settingsPathPersonalAccessTokenEdit,18settingsPathPersonalAccessTokens,19settingsPathPlans,20settingsPathPreferences,21settingsPathSSHKeys,22settingsPathVariables,23switchToPAYGPathMain,24usagePathMain,25} from "../user-settings/settings.routes";26import { getURLHash, isGitpodIo } from "../utils";27import { workspacesPathMain } from "../workspaces/workspaces.routes";28import { AdminRoute } from "./AdminRoute";29import { Blocked } from "./Blocked";3031// TODO: Can we bundle-split/lazy load these like other pages?32import { BlockedRepositories } from "../admin/BlockedRepositories";33import PersonalAccessTokenCreateView from "../user-settings/PersonalAccessTokensCreateView";34import { CreateWorkspacePage } from "../workspaces/CreateWorkspacePage";35import { BlockedEmailDomains } from "../admin/BlockedEmailDomains";36import { AppNotifications } from "../AppNotifications";37import { projectsPathInstallGitHubApp } from "../projects/projects.routes";38import { Heading1, Subheading } from "@podkit/typography/Headings";39import { PrebuildDetailPage } from "../prebuilds/detail/PrebuildDetailPage";4041const Workspaces = React.lazy(() => import(/* webpackPrefetch: true */ "../workspaces/Workspaces"));42const Account = React.lazy(() => import(/* webpackPrefetch: true */ "../user-settings/Account"));43const Notifications = React.lazy(() => import(/* webpackPrefetch: true */ "../user-settings/Notifications"));44const EnvironmentVariables = React.lazy(45() => import(/* webpackPrefetch: true */ "../user-settings/EnvironmentVariables"),46);47const SSHKeys = React.lazy(() => import(/* webpackPrefetch: true */ "../user-settings/SSHKeys"));48const Integrations = React.lazy(() => import(/* webpackPrefetch: true */ "../user-settings/Integrations"));49const Preferences = React.lazy(() => import(/* webpackPrefetch: true */ "../user-settings/Preferences"));50const PersonalAccessTokens = React.lazy(51() => import(/* webpackPrefetch: true */ "../user-settings/PersonalAccessTokens"),52);53const StartWorkspace = React.lazy(() => import(/* webpackPrefetch: true */ "../start/StartWorkspace"));54const NewTeam = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/NewTeam"));55const JoinTeam = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/JoinTeam"));56const Members = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/Members"));57const TeamSettings = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/TeamSettings"));58const TeamUsageBasedBilling = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/TeamUsageBasedBilling"));59const SSO = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/SSO"));60const TeamGitIntegrations = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/GitIntegrationsPage"));61const TeamPolicies = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/TeamPolicies"));62const TeamOnboarding = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/TeamOnboarding"));63const TeamNetworking = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/TeamNetworking"));64const TeamAuthentication = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/TeamAuthentication"));65const InstallGitHubApp = React.lazy(() => import(/* webpackPrefetch: true */ "../projects/InstallGitHubApp"));66const FromReferrer = React.lazy(() => import(/* webpackPrefetch: true */ "../FromReferrer"));67const UserSearch = React.lazy(() => import(/* webpackPrefetch: true */ "../admin/UserSearch"));68const WorkspacesSearch = React.lazy(() => import(/* webpackPrefetch: true */ "../admin/WorkspacesSearch"));69const ProjectsSearch = React.lazy(() => import(/* webpackPrefetch: true */ "../admin/ProjectsSearch"));70const TeamsSearch = React.lazy(() => import(/* webpackPrefetch: true */ "../admin/TeamsSearch"));71const Usage = React.lazy(() => import(/* webpackPrefetch: true */ "../Usage"));72const Insights = React.lazy(() => import(/* webpackPrefetch: true */ "../Insights"));73const ConfigurationListPage = React.lazy(74() => import(/* webpackPrefetch: true */ "../repositories/list/RepositoryList"),75);76const ConfigurationDetailPage = React.lazy(77() => import(/* webpackPrefetch: true */ "../repositories/detail/ConfigurationDetailPage"),78);7980const PrebuildListPage = React.lazy(() => import(/* webpackPrefetch: true */ "../prebuilds/list/PrebuildListPage"));81const AdminPage = React.lazy(() => import(/* webpackPrefetch: true */ "../org-admin/AdminPage"));8283export const AppRoutes = () => {84const hash = getURLHash();85const location = useLocation();8687// TODO: Add a Route for this instead of inspecting location manually88if (location.pathname.startsWith("/blocked")) {89return <Blocked />;90}9192// TODO: Add a Route for this instead of inspecting location manually93if (location.pathname.startsWith("/oauth-approval")) {94return <OAuthClientApproval />;95}9697// TODO: Try and encapsulate this in a route for "/" (check for hash in route component, render or redirect accordingly)98const isCreation = location.pathname === "/" && hash !== "";99if (isCreation) {100return <Redirect to={"/new" + location.pathname + location.search + location.hash} />;101}102103// TODO: Try and make this a <Route/> entry instead104const isWsStart = /\/start\/?/.test(window.location.pathname) && hash !== "";105if (isWsStart) {106return <StartWorkspace {...parseProps(hash, window.location.search)} />;107}108109// TODO: Add some context to what this logic is for110if (/^(github|gitlab)\.com\/.+?/i.test(window.location.pathname)) {111let url = new URL(window.location.href);112url.hash = url.pathname;113url.pathname = "/";114window.location.replace(url);115return <div></div>;116}117118return (119<Route>120<Switch>121<Route path="/new" exact component={CreateWorkspacePage} />122<Route path="*">123<div className="container">124<Menu />125<AppNotifications />126<Switch>127<Route path="/open">128<Redirect to="/new" />129</Route>130<Route131path={[132switchToPAYGPathMain,133settingsPathPlans,134"/old-team-plans",135"/teams",136"/subscription",137"/upgrade-subscription",138"/plans",139]}140exact141>142<Redirect to={"/billing"} />143</Route>144<Route path={workspacesPathMain} exact component={Workspaces} />145<Route path={settingsPathAccount} exact component={Account} />146<Route path={usagePathMain} exact component={Usage} />147<Route path={"/insights"} exact component={Insights} />148<Route path={settingsPathIntegrations} exact component={Integrations} />149<Route path={settingsPathNotifications} exact component={Notifications} />150<Route path={settingsPathVariables} exact component={EnvironmentVariables} />151<Route path={settingsPathSSHKeys} exact component={SSHKeys} />152<Route path={settingsPathPersonalAccessTokens} exact component={PersonalAccessTokens} />153<Route154path={settingsPathPersonalAccessTokenCreate}155exact156component={PersonalAccessTokenCreateView}157/>158<Route159path={settingsPathPersonalAccessTokenEdit + "/:tokenId"}160exact161component={PersonalAccessTokenCreateView}162/>163<Route path={settingsPathPreferences} exact component={Preferences} />164<Route path={projectsPathInstallGitHubApp} exact component={InstallGitHubApp} />165<Route path="/from-referrer" exact component={FromReferrer} />166167<AdminRoute path="/admin/users" component={UserSearch} />168<AdminRoute path="/admin/orgs" component={TeamsSearch} />169<AdminRoute path="/admin/workspaces" component={WorkspacesSearch} />170<AdminRoute path="/admin/projects" component={ProjectsSearch} />171<AdminRoute path="/admin/blocked-repositories" component={BlockedRepositories} />172<AdminRoute path="/admin/blocked-email-domains" component={BlockedEmailDomains} />173174<Route path={["/", "/login", "/login/:orgSlug"]} exact>175<Redirect to={workspacesPathMain} />176</Route>177<Route path={[settingsPathMain]} exact>178<Redirect to={settingsPathAccount} />179</Route>180<Route path={["/access-control"]} exact>181<Redirect to={settingsPathIntegrations} />182</Route>183<Route path={["/admin"]} exact>184<Redirect to="/admin/users" />185</Route>186<Route path="/sorry" exact>187<div className="mt-48 text-center">188<Heading1>Oh, no! Something went wrong!</Heading1>189<Subheading className="mt-4 text-gitpod-red">190{decodeURIComponent(getURLHash())}191</Subheading>192</div>193</Route>194<Route exact path="/orgs/new" component={NewTeam} />195<Route exact path="/orgs/join" component={JoinTeam} />196197{/* These routes that require a selected organization, otherwise they redirect to "/" */}198<Route exact path="/members" component={Members} />199<Route exact path="/settings" component={TeamSettings} />200<Route exact path="/settings/git" component={TeamGitIntegrations} />201<Route exact path="/settings/policy" component={TeamPolicies} />202<Route exact path="/settings/onboarding" component={TeamOnboarding} />203<Route exact path="/settings/networking" component={TeamNetworking} />204<Route exact path="/settings/auth" component={TeamAuthentication} />205{/* TODO: migrate other org settings pages underneath /settings prefix so we can utilize nested routes */}206<Route exact path="/billing" component={TeamUsageBasedBilling} />207<Route exact path="/sso" component={SSO} />208<Route exact path="/org-admin" component={AdminPage} />209210<Route exact path={`/prebuilds`} component={PrebuildListPage} />211<Route path="/prebuilds/:prebuildId" component={PrebuildDetailPage} />212<Route exact path="/repositories" component={ConfigurationListPage} />213{/* Handles all /repositories/:id/* routes in a nested router */}214<Route path="/repositories/:id" component={ConfigurationDetailPage} />215216{/* basic redirect for old team slugs */}217<Route path={"/t/"} exact>218<Redirect to="/repositories" />219</Route>220<Route path={"/projects/"}>221<Redirect to="/repositories" />222</Route>223{/* redirect for old user settings slugs */}224<Route path="/account" exact>225<Redirect to={settingsPathAccount} />226</Route>227<Route path="/integrations" exact>228<Redirect to={settingsPathIntegrations} />229</Route>230<Route path="/notifications" exact>231<Redirect to={settingsPathNotifications} />232</Route>233<Route path="/user/billing" exact>234<Redirect to={"/billing"} />235</Route>236<Route path="/preferences" exact>237<Redirect to={settingsPathPreferences} />238</Route>239<Route path="/variables" exact>240<Redirect to={settingsPathVariables} />241</Route>242<Route path="/tokens" exact>243<Redirect to={settingsPathPersonalAccessTokens} />244</Route>245<Route path="/tokens/create" exact>246<Redirect to={settingsPathPersonalAccessTokenCreate} />247</Route>248<Route path="/keys" exact>249<Redirect to={settingsPathSSHKeys} />250</Route>251<Route252path="*"253render={(_match) => {254// delegate to our website to handle the request255if (isGitpodIo()) {256window.location.host = "www.gitpod.io";257}258259return (260<div className="mt-48 text-center">261<Heading1>404</Heading1>262<Subheading className="mt-4">Page not found.</Subheading>263</div>264);265}}266/>267</Switch>268</div>269</Route>270</Switch>271</Route>272);273};274275276