From 912b0fd606bb64fd9cf78f1e665e98861e949fc5 Mon Sep 17 00:00:00 2001 From: Sven Efftinge Date: Fri, 10 Feb 2023 13:29:51 +0000 Subject: [PATCH] [dashboard] redirect when no project is found --- components/dashboard/src/app/AppRoutes.tsx | 5 +- .../src/menu/OrganizationSelector.tsx | 4 +- components/dashboard/src/projects/Events.tsx | 7 ++- .../dashboard/src/projects/Prebuild.tsx | 8 +++- .../dashboard/src/projects/Prebuilds.tsx | 8 +++- components/dashboard/src/projects/Project.tsx | 10 ++-- .../src/projects/ProjectVariables.tsx | 7 ++- .../src/projects/project-context.tsx | 46 ++++++++++++++++--- 8 files changed, 77 insertions(+), 18 deletions(-) diff --git a/components/dashboard/src/app/AppRoutes.tsx b/components/dashboard/src/app/AppRoutes.tsx index 21fb9862f222e6..8f6c603793698a 100644 --- a/components/dashboard/src/app/AppRoutes.tsx +++ b/components/dashboard/src/app/AppRoutes.tsx @@ -269,9 +269,12 @@ export const AppRoutes: FunctionComponent = ({ user, teams }) => - + + + + diff --git a/components/dashboard/src/menu/OrganizationSelector.tsx b/components/dashboard/src/menu/OrganizationSelector.tsx index 0c36d9ea3c2502..e062e24bf9c78a 100644 --- a/components/dashboard/src/menu/OrganizationSelector.tsx +++ b/components/dashboard/src/menu/OrganizationSelector.tsx @@ -36,7 +36,7 @@ export default function OrganizationSelector(p: OrganizationSelectorProps) { ), active: team === undefined, separator: true, - link: `${location.pathname}?org=0`, + link: `/?org=0`, }, ] : []), @@ -55,7 +55,7 @@ export default function OrganizationSelector(p: OrganizationSelectorProps) { ), active: team?.id === t.id, separator: true, - link: `${location.pathname}?org=${t.id}`, + link: `/?org=${t.id}`, })) .sort((a, b) => (a.title.toLowerCase() > b.title.toLowerCase() ? 1 : -1)), { diff --git a/components/dashboard/src/projects/Events.tsx b/components/dashboard/src/projects/Events.tsx index 71d36a2d910045..0f7ba1e3775372 100644 --- a/components/dashboard/src/projects/Events.tsx +++ b/components/dashboard/src/projects/Events.tsx @@ -16,9 +16,10 @@ import { ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error"; import { openAuthorizeWindow } from "../provider-utils"; import { useCurrentProject } from "./project-context"; import { toRemoteURL } from "./render-utils"; +import { Redirect } from "react-router"; export default function () { - const project = useCurrentProject(); + const { project, loading } = useCurrentProject(); const [isLoadingEvents, setIsLoadingEvents] = useState(false); const [events, setEvents] = useState([]); @@ -102,6 +103,10 @@ export default function () { return event.status; }; + if (!loading && !project) { + return ; + } + return ( <>
(); @@ -25,6 +25,10 @@ export default function () { const [isRerunningPrebuild, setIsRerunningPrebuild] = useState(false); const [isCancellingPrebuild, setIsCancellingPrebuild] = useState(false); + if (!loading && !project) { + return ; + } + useEffect(() => { if (!project || !prebuildId) { return; diff --git a/components/dashboard/src/projects/Prebuilds.tsx b/components/dashboard/src/projects/Prebuilds.tsx index 2dab4f38b1412b..6b14852a8ad03e 100644 --- a/components/dashboard/src/projects/Prebuilds.tsx +++ b/components/dashboard/src/projects/Prebuilds.tsx @@ -18,14 +18,14 @@ import StatusPaused from "../icons/StatusPaused.svg"; import StatusRunning from "../icons/StatusRunning.svg"; import { getGitpodService } from "../service/service"; import { shortCommitMessage } from "./render-utils"; -import { Link } from "react-router-dom"; +import { Link, Redirect } from "react-router-dom"; import { Disposable } from "vscode-jsonrpc"; import { useCurrentProject } from "./project-context"; import { getProjectTabs } from "./projects.routes"; export default function (props: { project?: Project; isAdminDashboard?: boolean }) { const currentProject = useCurrentProject(); - const project = props.project || currentProject; + const project = props.project || currentProject.project; const [searchFilter, setSearchFilter] = useState(); const [statusFilter, setStatusFilter] = useState(); @@ -128,6 +128,10 @@ export default function (props: { project?: Project; isAdminDashboard?: boolean return date ? dayjs(date).fromNow() : ""; }; + if (!currentProject.loading && !project) { + return ; + } + return ( <> {!props.isAdminDashboard && ( diff --git a/components/dashboard/src/projects/Project.tsx b/components/dashboard/src/projects/Project.tsx index 83ef3a0e3ba7d1..fed0f619f24235 100644 --- a/components/dashboard/src/projects/Project.tsx +++ b/components/dashboard/src/projects/Project.tsx @@ -8,7 +8,7 @@ import { PrebuildWithStatus, Project } from "@gitpod/gitpod-protocol"; import { ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error"; import dayjs from "dayjs"; import { useCallback, useContext, useEffect, useState } from "react"; -import { useHistory } from "react-router"; +import { Redirect, useHistory } from "react-router"; import Alert from "../components/Alert"; import Header from "../components/Header"; import { Item, ItemField, ItemFieldContextMenu, ItemsList } from "../components/ItemsList"; @@ -24,7 +24,7 @@ import { shortCommitMessage, toRemoteURL } from "./render-utils"; export default function () { const history = useHistory(); - const project = useCurrentProject(); + const { project, loading } = useCurrentProject(); const { setStartWorkspaceModalProps } = useContext(StartWorkspaceModalContext); const [isLoading, setIsLoading] = useState(false); @@ -183,10 +183,14 @@ export default function () { } }; + if (!loading && !project) { + return ; + } + return ( <>
View recent active branches for{" "} diff --git a/components/dashboard/src/projects/ProjectVariables.tsx b/components/dashboard/src/projects/ProjectVariables.tsx index a08b643c1a48cc..5fd56644aefd6a 100644 --- a/components/dashboard/src/projects/ProjectVariables.tsx +++ b/components/dashboard/src/projects/ProjectVariables.tsx @@ -6,6 +6,7 @@ import { Project, ProjectEnvVar } from "@gitpod/gitpod-protocol"; import { useEffect, useState } from "react"; +import { Redirect } from "react-router"; import Alert from "../components/Alert"; import CheckBox from "../components/CheckBox"; import InfoBox from "../components/InfoBox"; @@ -16,7 +17,7 @@ import { useCurrentProject } from "./project-context"; import { ProjectSettingsPage } from "./ProjectSettings"; export default function () { - const project = useCurrentProject(); + const { project, loading } = useCurrentProject(); const [envVars, setEnvVars] = useState([]); const [showAddVariableModal, setShowAddVariableModal] = useState(false); @@ -39,6 +40,10 @@ export default function () { updateEnvVars(); }; + if (!loading && !project) { + return ; + } + return ( {showAddVariableModal && ( diff --git a/components/dashboard/src/projects/project-context.tsx b/components/dashboard/src/projects/project-context.tsx index afa46fe327e8f9..f01b707611a15d 100644 --- a/components/dashboard/src/projects/project-context.tsx +++ b/components/dashboard/src/projects/project-context.tsx @@ -6,10 +6,10 @@ import { Project } from "@gitpod/gitpod-protocol"; import React, { createContext, useContext, useEffect, useMemo, useState } from "react"; -import { useRouteMatch } from "react-router"; +import { useHistory, useLocation, useRouteMatch } from "react-router"; import { validate as uuidValidate } from "uuid"; import { listAllProjects } from "../service/public-api"; -import { useCurrentTeam } from "../teams/teams-context"; +import { useCurrentTeam, useTeams } from "../teams/teams-context"; import { useCurrentUser } from "../user-context"; export const ProjectContext = createContext<{ @@ -45,15 +45,26 @@ export function useProjectSlugs(): { projectSlug?: string; prebuildId?: string } }, [projectsRouteMatch?.params.projectSlug, projectsRouteMatch?.params.prebuildId]); } -export function useCurrentProject(): Project | undefined { +export function useCurrentProject(): { project: Project | undefined; loading: boolean } { const { project, setProject } = useContext(ProjectContext); + const [loading, setLoading] = useState(true); const user = useCurrentUser(); const team = useCurrentTeam(); + const teams = useTeams(); const slugs = useProjectSlugs(); + const location = useLocation(); + const history = useHistory(); useEffect(() => { - if (!user || !slugs.projectSlug) { + setLoading(true); + if (!user) { setProject(undefined); + // without a user we are still consider this loading + return; + } + if (!slugs.projectSlug) { + setProject(undefined); + setLoading(false); return; } (async () => { @@ -66,9 +77,32 @@ export function useCurrentProject(): Project | undefined { // Find project matching with slug, otherwise with name const project = projects.find((p) => Project.slug(p) === slugs.projectSlug); + if (!project && teams) { + // check other orgs + for (const t of teams) { + if (t.id === team?.id) { + continue; + } + const projects = await listAllProjects({ teamId: t.id }); + const project = projects.find((p) => Project.slug(p) === slugs.projectSlug); + if (project) { + // redirect to the other org + history.push(location.pathname + "?org=" + t.id); + } + } + + // check personal projects + const projects = await listAllProjects({ userId: user.id }); + const project = projects.find((p) => Project.slug(p) === slugs.projectSlug); + if (project) { + // redirect to the other org + history.push(location.pathname + "?org=0"); + } + } setProject(project); + setLoading(false); })(); - }, [slugs.projectSlug, setProject, team, user]); + }, [slugs.projectSlug, setProject, team, user, teams, location, history]); - return project; + return { project, loading }; }