|
@@ -1,55 +1,63 @@
|
|
|
import React, { useContext, useEffect, useRef, useState } from "react";
|
|
import React, { useContext, useEffect, useRef, useState } from "react";
|
|
|
import { createPortal } from "react-dom";
|
|
import { createPortal } from "react-dom";
|
|
|
-import { Route, RouteComponentProps, Switch, withRouter } from "react-router";
|
|
|
|
|
|
|
+import {
|
|
|
|
|
+ Route,
|
|
|
|
|
+ Switch,
|
|
|
|
|
+ withRouter,
|
|
|
|
|
+ type RouteComponentProps,
|
|
|
|
|
+} from "react-router";
|
|
|
import styled, { ThemeProvider } from "styled-components";
|
|
import styled, { ThemeProvider } from "styled-components";
|
|
|
|
|
|
|
|
-import api from "shared/api";
|
|
|
|
|
-import { Context } from "shared/Context";
|
|
|
|
|
-import { PorterUrl, pushFiltered, pushQueryParams } from "shared/routing";
|
|
|
|
|
-import midnight from "shared/themes/midnight";
|
|
|
|
|
-import standard from "shared/themes/standard";
|
|
|
|
|
-import { ClusterType, ProjectListType, ProjectType } from "shared/types";
|
|
|
|
|
-
|
|
|
|
|
import ConfirmOverlay from "components/ConfirmOverlay";
|
|
import ConfirmOverlay from "components/ConfirmOverlay";
|
|
|
import Loading from "components/Loading";
|
|
import Loading from "components/Loading";
|
|
|
-import DashboardRouter from "./cluster-dashboard/DashboardRouter";
|
|
|
|
|
-import Dashboard from "./dashboard/Dashboard";
|
|
|
|
|
-import Integrations from "./integrations/Integrations";
|
|
|
|
|
-import LaunchWrapper from "./launch/LaunchWrapper";
|
|
|
|
|
-
|
|
|
|
|
-import AddOnDashboard from "./add-on-dashboard/AddOnDashboard";
|
|
|
|
|
-import AppDashboard from "./app-dashboard/AppDashboard";
|
|
|
|
|
-import CreateDatabase from "./database-dashboard/CreateDatabase";
|
|
|
|
|
-import DatabaseDashboard from "./database-dashboard/DatabaseDashboard";
|
|
|
|
|
-import Navbar from "./navbar/Navbar";
|
|
|
|
|
-import ProjectSettings from "./project-settings/ProjectSettings";
|
|
|
|
|
-import Sidebar from "./sidebar/Sidebar";
|
|
|
|
|
-
|
|
|
|
|
import NoClusterPlaceHolder from "components/NoClusterPlaceHolder";
|
|
import NoClusterPlaceHolder from "components/NoClusterPlaceHolder";
|
|
|
import Button from "components/porter/Button";
|
|
import Button from "components/porter/Button";
|
|
|
import Modal from "components/porter/Modal";
|
|
import Modal from "components/porter/Modal";
|
|
|
import Spacer from "components/porter/Spacer";
|
|
import Spacer from "components/porter/Spacer";
|
|
|
import Text from "components/porter/Text";
|
|
import Text from "components/porter/Text";
|
|
|
-import { withAuth, WithAuthProps } from "shared/auth/AuthorizationHoc";
|
|
|
|
|
|
|
+
|
|
|
|
|
+import api from "shared/api";
|
|
|
|
|
+import { withAuth, type WithAuthProps } from "shared/auth/AuthorizationHoc";
|
|
|
import { fakeGuardedRoute } from "shared/auth/RouteGuard";
|
|
import { fakeGuardedRoute } from "shared/auth/RouteGuard";
|
|
|
import ClusterResourcesProvider from "shared/ClusterResourcesContext";
|
|
import ClusterResourcesProvider from "shared/ClusterResourcesContext";
|
|
|
|
|
+import { Context } from "shared/Context";
|
|
|
import DeploymentTargetProvider from "shared/DeploymentTargetContext";
|
|
import DeploymentTargetProvider from "shared/DeploymentTargetContext";
|
|
|
|
|
+import { pushFiltered, pushQueryParams, type PorterUrl } from "shared/routing";
|
|
|
|
|
+import midnight from "shared/themes/midnight";
|
|
|
|
|
+import standard from "shared/themes/standard";
|
|
|
|
|
+import {
|
|
|
|
|
+ type ClusterType,
|
|
|
|
|
+ type ProjectListType,
|
|
|
|
|
+ type ProjectType,
|
|
|
|
|
+} from "shared/types";
|
|
|
import { overrideInfraTabEnabled } from "utils/infrastructure";
|
|
import { overrideInfraTabEnabled } from "utils/infrastructure";
|
|
|
|
|
+
|
|
|
import discordLogo from "../../assets/discord.svg";
|
|
import discordLogo from "../../assets/discord.svg";
|
|
|
|
|
+import AddOnDashboard from "./add-on-dashboard/AddOnDashboard";
|
|
|
import NewAddOnFlow from "./add-on-dashboard/NewAddOnFlow";
|
|
import NewAddOnFlow from "./add-on-dashboard/NewAddOnFlow";
|
|
|
import AppView from "./app-dashboard/app-view/AppView";
|
|
import AppView from "./app-dashboard/app-view/AppView";
|
|
|
|
|
+import AppDashboard from "./app-dashboard/AppDashboard";
|
|
|
import Apps from "./app-dashboard/apps/Apps";
|
|
import Apps from "./app-dashboard/apps/Apps";
|
|
|
import CreateApp from "./app-dashboard/create-app/CreateApp";
|
|
import CreateApp from "./app-dashboard/create-app/CreateApp";
|
|
|
import ExpandedApp from "./app-dashboard/expanded-app/ExpandedApp";
|
|
import ExpandedApp from "./app-dashboard/expanded-app/ExpandedApp";
|
|
|
import NewAppFlow from "./app-dashboard/new-app-flow/NewAppFlow";
|
|
import NewAppFlow from "./app-dashboard/new-app-flow/NewAppFlow";
|
|
|
|
|
+import DashboardRouter from "./cluster-dashboard/DashboardRouter";
|
|
|
import PreviewEnvs from "./cluster-dashboard/preview-environments/v2/PreviewEnvs";
|
|
import PreviewEnvs from "./cluster-dashboard/preview-environments/v2/PreviewEnvs";
|
|
|
import SetupApp from "./cluster-dashboard/preview-environments/v2/setup-app/SetupApp";
|
|
import SetupApp from "./cluster-dashboard/preview-environments/v2/setup-app/SetupApp";
|
|
|
|
|
+import ComplianceDashboard from "./compliance-dashboard/ComplianceDashboard";
|
|
|
|
|
+import Dashboard from "./dashboard/Dashboard";
|
|
|
|
|
+import CreateDatabase from "./database-dashboard/CreateDatabase";
|
|
|
|
|
+import DatabaseDashboard from "./database-dashboard/DatabaseDashboard";
|
|
|
import DatabaseView from "./database-dashboard/DatabaseView";
|
|
import DatabaseView from "./database-dashboard/DatabaseView";
|
|
|
import InfrastructureRouter from "./infrastructure/InfrastructureRouter";
|
|
import InfrastructureRouter from "./infrastructure/InfrastructureRouter";
|
|
|
|
|
+import Integrations from "./integrations/Integrations";
|
|
|
|
|
+import LaunchWrapper from "./launch/LaunchWrapper";
|
|
|
import ModalHandler from "./ModalHandler";
|
|
import ModalHandler from "./ModalHandler";
|
|
|
|
|
+import Navbar from "./navbar/Navbar";
|
|
|
import { NewProjectFC } from "./new-project/NewProject";
|
|
import { NewProjectFC } from "./new-project/NewProject";
|
|
|
import Onboarding from "./onboarding/Onboarding";
|
|
import Onboarding from "./onboarding/Onboarding";
|
|
|
-
|
|
|
|
|
|
|
+import ProjectSettings from "./project-settings/ProjectSettings";
|
|
|
|
|
+import Sidebar from "./sidebar/Sidebar";
|
|
|
|
|
|
|
|
// Guarded components
|
|
// Guarded components
|
|
|
const GuardedProjectSettings = fakeGuardedRoute("settings", "", [
|
|
const GuardedProjectSettings = fakeGuardedRoute("settings", "", [
|
|
@@ -125,10 +133,10 @@ const Home: React.FC<Props> = (props) => {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const getProjects = async (id?: number) => {
|
|
const getProjects = async (id?: number) => {
|
|
|
- let { currentProject } = props;
|
|
|
|
|
- let queryString = window.location.search;
|
|
|
|
|
- let urlParams = new URLSearchParams(queryString);
|
|
|
|
|
- let projectId = urlParams.get("project_id");
|
|
|
|
|
|
|
+ const { currentProject } = props;
|
|
|
|
|
+ const queryString = window.location.search;
|
|
|
|
|
+ const urlParams = new URLSearchParams(queryString);
|
|
|
|
|
+ const projectId = urlParams.get("project_id");
|
|
|
if (!projectId && currentProject?.id) {
|
|
if (!projectId && currentProject?.id) {
|
|
|
pushQueryParams(props, { project_id: currentProject.id.toString() });
|
|
pushQueryParams(props, { project_id: currentProject.id.toString() });
|
|
|
}
|
|
}
|
|
@@ -156,7 +164,7 @@ const Home: React.FC<Props> = (props) => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const project = await api
|
|
const project = await api
|
|
|
- .getProject("<token>", {}, { id: id })
|
|
|
|
|
|
|
+ .getProject("<token>", {}, { id })
|
|
|
.then((res) => res.data as ProjectType);
|
|
.then((res) => res.data as ProjectType);
|
|
|
|
|
|
|
|
setCurrentProject(project);
|
|
setCurrentProject(project);
|
|
@@ -200,24 +208,24 @@ const Home: React.FC<Props> = (props) => {
|
|
|
} else {
|
|
} else {
|
|
|
setHasFinishedOnboarding(true);
|
|
setHasFinishedOnboarding(true);
|
|
|
}
|
|
}
|
|
|
- } catch (error) { }
|
|
|
|
|
|
|
+ } catch (error) {}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
checkOnboarding();
|
|
checkOnboarding();
|
|
|
checkIfCanCreateProject();
|
|
checkIfCanCreateProject();
|
|
|
- let { match } = props;
|
|
|
|
|
|
|
+ const { match } = props;
|
|
|
|
|
|
|
|
// Handle redirect from DO
|
|
// Handle redirect from DO
|
|
|
- let queryString = window.location.search;
|
|
|
|
|
- let urlParams = new URLSearchParams(queryString);
|
|
|
|
|
|
|
+ const queryString = window.location.search;
|
|
|
|
|
+ const urlParams = new URLSearchParams(queryString);
|
|
|
|
|
|
|
|
- let err = urlParams.get("error");
|
|
|
|
|
|
|
+ const err = urlParams.get("error");
|
|
|
if (err) {
|
|
if (err) {
|
|
|
setCurrentError(err);
|
|
setCurrentError(err);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- let defaultProjectId = parseInt(urlParams.get("project_id"));
|
|
|
|
|
|
|
+ const defaultProjectId = parseInt(urlParams.get("project_id"));
|
|
|
|
|
|
|
|
setGhRedirect(urlParams.get("gh_oauth") !== null);
|
|
setGhRedirect(urlParams.get("gh_oauth") !== null);
|
|
|
urlParams.delete("gh_oauth");
|
|
urlParams.delete("gh_oauth");
|
|
@@ -290,9 +298,9 @@ const Home: React.FC<Props> = (props) => {
|
|
|
}, [props.currentProject?.id]);
|
|
}, [props.currentProject?.id]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
- let queryString = window.location.search;
|
|
|
|
|
- let urlParams = new URLSearchParams(queryString);
|
|
|
|
|
- let err = urlParams.get("error");
|
|
|
|
|
|
|
+ const queryString = window.location.search;
|
|
|
|
|
+ const urlParams = new URLSearchParams(queryString);
|
|
|
|
|
+ const err = urlParams.get("error");
|
|
|
if (
|
|
if (
|
|
|
!hasFinishedOnboarding &&
|
|
!hasFinishedOnboarding &&
|
|
|
props.history.location.pathname &&
|
|
props.history.location.pathname &&
|
|
@@ -328,7 +336,9 @@ const Home: React.FC<Props> = (props) => {
|
|
|
|
|
|
|
|
setProjects(projectList);
|
|
setProjects(projectList);
|
|
|
if (!projectList.length) {
|
|
if (!projectList.length) {
|
|
|
- setCurrentProject(null, () => redirectToNewProject());
|
|
|
|
|
|
|
+ setCurrentProject(null, () => {
|
|
|
|
|
+ redirectToNewProject();
|
|
|
|
|
+ });
|
|
|
} else {
|
|
} else {
|
|
|
const project = await api
|
|
const project = await api
|
|
|
.getProject("<token>", {}, { id: projectList[0].id })
|
|
.getProject("<token>", {}, { id: projectList[0].id })
|
|
@@ -362,18 +372,18 @@ const Home: React.FC<Props> = (props) => {
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
const res = await api.getClusters<
|
|
const res = await api.getClusters<
|
|
|
- {
|
|
|
|
|
|
|
+ Array<{
|
|
|
infra_id?: number;
|
|
infra_id?: number;
|
|
|
name: string;
|
|
name: string;
|
|
|
- }[]
|
|
|
|
|
|
|
+ }>
|
|
|
>("<token>", {}, { id: currentProject?.id });
|
|
>("<token>", {}, { id: currentProject?.id });
|
|
|
|
|
|
|
|
- const destroyInfraPromises = res.data.map((cluster) => {
|
|
|
|
|
|
|
+ const destroyInfraPromises = res.data.map(async (cluster) => {
|
|
|
if (!cluster.infra_id) {
|
|
if (!cluster.infra_id) {
|
|
|
return undefined;
|
|
return undefined;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return api.destroyInfra(
|
|
|
|
|
|
|
+ return await api.destroyInfra(
|
|
|
"<token>",
|
|
"<token>",
|
|
|
{},
|
|
{},
|
|
|
{ project_id: currentProject.id, infra_id: cluster.infra_id }
|
|
{ project_id: currentProject.id, infra_id: cluster.infra_id }
|
|
@@ -418,7 +428,10 @@ const Home: React.FC<Props> = (props) => {
|
|
|
setRefreshClusters={setForceRefreshClusters}
|
|
setRefreshClusters={setForceRefreshClusters}
|
|
|
/>
|
|
/>
|
|
|
) : (
|
|
) : (
|
|
|
- <DiscordButton href="https://discord.gg/34n7NN7FJ7" target="_blank">
|
|
|
|
|
|
|
+ <DiscordButton
|
|
|
|
|
+ href="https://discord.gg/34n7NN7FJ7"
|
|
|
|
|
+ target="_blank"
|
|
|
|
|
+ >
|
|
|
<Icon src={discordLogo} />
|
|
<Icon src={discordLogo} />
|
|
|
Join Our Discord
|
|
Join Our Discord
|
|
|
</DiscordButton>
|
|
</DiscordButton>
|
|
@@ -474,6 +487,11 @@ const Home: React.FC<Props> = (props) => {
|
|
|
<Route path="/databases">
|
|
<Route path="/databases">
|
|
|
<DatabaseDashboard />
|
|
<DatabaseDashboard />
|
|
|
</Route>
|
|
</Route>
|
|
|
|
|
+
|
|
|
|
|
+ <Route path="/compliance">
|
|
|
|
|
+ <ComplianceDashboard />
|
|
|
|
|
+ </Route>
|
|
|
|
|
+
|
|
|
<Route path="/addons/new">
|
|
<Route path="/addons/new">
|
|
|
<NewAddOnFlow />
|
|
<NewAddOnFlow />
|
|
|
</Route>
|
|
</Route>
|
|
@@ -496,17 +514,17 @@ const Home: React.FC<Props> = (props) => {
|
|
|
overrideInfraTabEnabled({
|
|
overrideInfraTabEnabled({
|
|
|
projectID: currentProject?.id,
|
|
projectID: currentProject?.id,
|
|
|
})) && (
|
|
})) && (
|
|
|
- <Route
|
|
|
|
|
- path="/infrastructure"
|
|
|
|
|
- render={() => {
|
|
|
|
|
- return (
|
|
|
|
|
- <DashboardWrapper>
|
|
|
|
|
- <InfrastructureRouter />
|
|
|
|
|
- </DashboardWrapper>
|
|
|
|
|
- );
|
|
|
|
|
- }}
|
|
|
|
|
- />
|
|
|
|
|
- )}
|
|
|
|
|
|
|
+ <Route
|
|
|
|
|
+ path="/infrastructure"
|
|
|
|
|
+ render={() => {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <DashboardWrapper>
|
|
|
|
|
+ <InfrastructureRouter />
|
|
|
|
|
+ </DashboardWrapper>
|
|
|
|
|
+ );
|
|
|
|
|
+ }}
|
|
|
|
|
+ />
|
|
|
|
|
+ )}
|
|
|
<Route
|
|
<Route
|
|
|
path="/dashboard"
|
|
path="/dashboard"
|
|
|
render={() => {
|
|
render={() => {
|
|
@@ -535,7 +553,7 @@ const Home: React.FC<Props> = (props) => {
|
|
|
render={() => {
|
|
render={() => {
|
|
|
if (currentCluster?.id === -1) {
|
|
if (currentCluster?.id === -1) {
|
|
|
return <Loading />;
|
|
return <Loading />;
|
|
|
- } else if (!currentCluster || !currentCluster.name) {
|
|
|
|
|
|
|
+ } else if (!currentCluster?.name) {
|
|
|
return (
|
|
return (
|
|
|
<DashboardWrapper>
|
|
<DashboardWrapper>
|
|
|
<NoClusterPlaceHolder></NoClusterPlaceHolder>
|
|
<NoClusterPlaceHolder></NoClusterPlaceHolder>
|
|
@@ -563,7 +581,7 @@ const Home: React.FC<Props> = (props) => {
|
|
|
render={() => <GuardedProjectSettings />}
|
|
render={() => <GuardedProjectSettings />}
|
|
|
/>
|
|
/>
|
|
|
{currentProject?.validate_apply_v2 &&
|
|
{currentProject?.validate_apply_v2 &&
|
|
|
- currentProject.preview_envs_enabled ? (
|
|
|
|
|
|
|
+ currentProject.preview_envs_enabled ? (
|
|
|
<>
|
|
<>
|
|
|
<Route exact path="/preview-environments/configure">
|
|
<Route exact path="/preview-environments/configure">
|
|
|
<SetupApp />
|
|
<SetupApp />
|
|
@@ -597,7 +615,9 @@ const Home: React.FC<Props> = (props) => {
|
|
|
: ""
|
|
: ""
|
|
|
}
|
|
}
|
|
|
onYes={handleDelete}
|
|
onYes={handleDelete}
|
|
|
- onNo={() => setCurrentModal(null, null)}
|
|
|
|
|
|
|
+ onNo={() => {
|
|
|
|
|
+ setCurrentModal(null, null);
|
|
|
|
|
+ }}
|
|
|
/>,
|
|
/>,
|
|
|
document.body
|
|
document.body
|
|
|
)}
|
|
)}
|
|
@@ -608,14 +628,14 @@ const Home: React.FC<Props> = (props) => {
|
|
|
</Text>
|
|
</Text>
|
|
|
<Spacer y={1} />
|
|
<Spacer y={1} />
|
|
|
<Text color="helper">
|
|
<Text color="helper">
|
|
|
- Your account email does not match the email associated with this
|
|
|
|
|
- project invite. Please log out and sign up again with the
|
|
|
|
|
|
|
+ Your account email does not match the email associated with
|
|
|
|
|
+ this project invite. Please log out and sign up again with the
|
|
|
correct email using the invite link.
|
|
correct email using the invite link.
|
|
|
</Text>
|
|
</Text>
|
|
|
<Spacer y={1} />
|
|
<Spacer y={1} />
|
|
|
<Text color="helper">
|
|
<Text color="helper">
|
|
|
- You should reach out to the person who sent you the invite link
|
|
|
|
|
- to get the correct email.
|
|
|
|
|
|
|
+ You should reach out to the person who sent you the invite
|
|
|
|
|
+ link to get the correct email.
|
|
|
</Text>
|
|
</Text>
|
|
|
<Spacer y={1} />
|
|
<Spacer y={1} />
|
|
|
<Button onClick={props.logOut}>Log out</Button>
|
|
<Button onClick={props.logOut}>Log out</Button>
|
|
@@ -684,7 +704,9 @@ const DiscordButton = styled.a`
|
|
|
border-radius: 3px;
|
|
border-radius: 3px;
|
|
|
color: #ffffff44;
|
|
color: #ffffff44;
|
|
|
height: 40px;
|
|
height: 40px;
|
|
|
- font-family: Work Sans, sans-serif;
|
|
|
|
|
|
|
+ font-family:
|
|
|
|
|
+ Work Sans,
|
|
|
|
|
+ sans-serif;
|
|
|
font-size: 14px;
|
|
font-size: 14px;
|
|
|
font-weight: bold;
|
|
font-weight: bold;
|
|
|
cursor: pointer;
|
|
cursor: pointer;
|