diff --git a/components/dashboard/src/contexts/FeatureFlagContext.tsx b/components/dashboard/src/contexts/FeatureFlagContext.tsx index 93c117a21fac91..5fd868c1a58a60 100644 --- a/components/dashboard/src/contexts/FeatureFlagContext.tsx +++ b/components/dashboard/src/contexts/FeatureFlagContext.tsx @@ -107,3 +107,7 @@ const FeatureFlagContextProvider: React.FC = ({ children }) => { }; export { FeatureFlagContext, FeatureFlagContextProvider }; + +export const useFeatureFlags = () => { + return useContext(FeatureFlagContext); +}; diff --git a/components/dashboard/src/projects/ProjectSettings.tsx b/components/dashboard/src/projects/ProjectSettings.tsx index a4db5f58804ed3..3b6ec792d91a3c 100644 --- a/components/dashboard/src/projects/ProjectSettings.tsx +++ b/components/dashboard/src/projects/ProjectSettings.tsx @@ -4,8 +4,8 @@ * See License.AGPL.txt in the project root for license information. */ -import { useContext, useEffect, useState } from "react"; -import { useLocation } from "react-router"; +import { useCallback, useContext, useEffect, useState } from "react"; +import { useLocation, useHistory } from "react-router"; import { Project, ProjectSettings, Team } from "@gitpod/gitpod-protocol"; import CheckBox from "../components/CheckBox"; import { getGitpodService } from "../service/service"; @@ -17,6 +17,7 @@ import SelectWorkspaceClass from "../settings/selectClass"; import { BillingMode } from "@gitpod/gitpod-protocol/lib/billing-mode"; import Alert from "../components/Alert"; import { Link } from "react-router-dom"; +import { RemoveProjectModal } from "./RemoveProjectModal"; export function getProjectSettingsMenu(project?: Project, team?: Team) { const teamOrUserSlug = !!team ? "t/" + team.slug : "projects"; @@ -51,8 +52,11 @@ export function ProjectSettingsPage(props: { project?: Project; children?: React export default function () { const { project, setProject } = useContext(ProjectContext); const [billingMode, setBillingMode] = useState(undefined); + const [showRemoveModal, setShowRemoveModal] = useState(false); const { teams } = useContext(TeamsContext); const team = getCurrentTeam(useLocation(), teams); + const history = useHistory(); + useEffect(() => { if (team) { getGitpodService().server.getBillingModeForTeam(team.id).then(setBillingMode); @@ -61,33 +65,52 @@ export default function () { } }, [team]); - if (!project) return null; + const updateProjectSettings = useCallback( + (settings: ProjectSettings) => { + if (!project) return; - const updateProjectSettings = (settings: ProjectSettings) => { - if (!project) return; + const newSettings = { ...project.settings, ...settings }; + getGitpodService().server.updateProjectPartial({ id: project.id, settings: newSettings }); + setProject({ ...project, settings: newSettings }); + }, + [project, setProject], + ); - const newSettings = { ...project.settings, ...settings }; - getGitpodService().server.updateProjectPartial({ id: project.id, settings: newSettings }); - setProject({ ...project, settings: newSettings }); - }; + const setWorkspaceClass = useCallback( + async (value: string) => { + if (!project) { + return value; + } + const before = project.settings?.workspaceClasses?.regular; + updateProjectSettings({ workspaceClasses: { ...project.settings?.workspaceClasses, regular: value } }); + return before; + }, + [project, updateProjectSettings], + ); - const setWorkspaceClass = async (value: string) => { - if (!project) { - return value; - } - const before = project.settings?.workspaceClasses?.regular; - updateProjectSettings({ workspaceClasses: { ...project.settings?.workspaceClasses, regular: value } }); - return before; - }; + const setWorkspaceClassForPrebuild = useCallback( + async (value: string) => { + if (!project) { + return value; + } + const before = project.settings?.workspaceClasses?.prebuild; + updateProjectSettings({ workspaceClasses: { ...project.settings?.workspaceClasses, prebuild: value } }); + return before; + }, + [project, updateProjectSettings], + ); - const setWorkspaceClassForPrebuild = async (value: string) => { - if (!project) { - return value; + const onProjectRemoved = useCallback(() => { + // if there's a current team, navigate to team projects + if (team) { + history.push(`/t/${team.slug}/projects`); + } else { + history.push("/projects"); } - const before = project.settings?.workspaceClasses?.prebuild; - updateProjectSettings({ workspaceClasses: { ...project.settings?.workspaceClasses, prebuild: value } }); - return before; - }; + }, [history, team]); + + // TODO: Render a generic error screen for when an entity isn't found + if (!project) return null; return ( @@ -237,6 +260,22 @@ export default function () { )} +
+

Delete Project

+

+ Removing the project from this team will also remove team members access to it. +

+ +
+ {showRemoveModal && ( + setShowRemoveModal(false)} + /> + )}
); } diff --git a/components/dashboard/src/projects/RemoveProjectModal.tsx b/components/dashboard/src/projects/RemoveProjectModal.tsx new file mode 100644 index 00000000000000..b662a9d990cbf0 --- /dev/null +++ b/components/dashboard/src/projects/RemoveProjectModal.tsx @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2022 Gitpod GmbH. All rights reserved. + * Licensed under the GNU Affero General Public License (AGPL). + * See License.AGPL.txt in the project root for license information. + */ + +import { FunctionComponent, useCallback, useState } from "react"; +import type { Project } from "@gitpod/gitpod-protocol"; +import { projectsService } from "../service/public-api"; +import { getGitpodService } from "../service/service"; +import ConfirmationModal from "../components/ConfirmationModal"; +import { useFeatureFlags } from "../contexts/FeatureFlagContext"; + +type RemoveProjectModalProps = { + project: Project; + onClose: () => void; + onRemoved: () => void; +}; + +export const RemoveProjectModal: FunctionComponent = ({ project, onClose, onRemoved }) => { + const { usePublicApiProjectsService } = useFeatureFlags(); + const [disabled, setDisabled] = useState(false); + + const removeProject = useCallback(async () => { + setDisabled(true); + usePublicApiProjectsService + ? await projectsService.deleteProject({ projectId: project.id }) + : await getGitpodService().server.deleteProject(project.id); + setDisabled(false); + onRemoved(); + }, [onRemoved, project.id, usePublicApiProjectsService]); + + return ( + + ); +};