|
|
@@ -1,12 +1,14 @@
|
|
|
-import React, { Component } from "react";
|
|
|
+import React, { useState, useContext, useEffect } from "react";
|
|
|
import styled from "styled-components";
|
|
|
+import { RouteComponentProps, withRouter } from "react-router";
|
|
|
|
|
|
import gradient from "assets/gradient.png";
|
|
|
+
|
|
|
import { Context } from "shared/Context";
|
|
|
import { InfraType } from "shared/types";
|
|
|
import api from "shared/api";
|
|
|
-
|
|
|
-import { RouteComponentProps, withRouter } from "react-router";
|
|
|
+import { pushFiltered, pushQueryParams } from "shared/routing";
|
|
|
+import { withAuth, WithAuthProps } from "shared/auth/AuthorizationHoc";
|
|
|
|
|
|
import ProvisionerSettings from "../provisioner/ProvisionerSettings";
|
|
|
import ClusterPlaceholderContainer from "./ClusterPlaceholderContainer";
|
|
|
@@ -16,112 +18,113 @@ import TitleSection from "components/TitleSection";
|
|
|
import ClusterSection from "./ClusterSection";
|
|
|
import { StatusPage } from "../onboarding/steps/ProvisionResources/forms/StatusPage";
|
|
|
import Banner from "components/Banner";
|
|
|
-
|
|
|
-import { pushFiltered, pushQueryParams } from "shared/routing";
|
|
|
-import { withAuth, WithAuthProps } from "shared/auth/AuthorizationHoc";
|
|
|
import Spacer from "components/porter/Spacer";
|
|
|
|
|
|
-type PropsType = RouteComponentProps &
|
|
|
- WithAuthProps & {
|
|
|
- projectId: number | null;
|
|
|
- setRefreshClusters: (x: boolean) => void;
|
|
|
- };
|
|
|
-
|
|
|
-type StateType = {
|
|
|
- infras: InfraType[];
|
|
|
- pressingCtrl: boolean;
|
|
|
- pressingK: boolean;
|
|
|
- showFormDebugger: boolean;
|
|
|
+type Props = RouteComponentProps & WithAuthProps & {
|
|
|
+ projectId: number | null;
|
|
|
+ setRefreshClusters: (x: boolean) => void;
|
|
|
};
|
|
|
|
|
|
-class Dashboard extends Component<PropsType, StateType> {
|
|
|
- state = {
|
|
|
- infras: [] as InfraType[],
|
|
|
- pressingCtrl: false,
|
|
|
- pressingK: false,
|
|
|
- showFormDebugger: false,
|
|
|
+const Dashboard: React.FC<Props> = ({
|
|
|
+ projectId,
|
|
|
+ setRefreshClusters,
|
|
|
+ ...props
|
|
|
+}) => {
|
|
|
+ const { currentProject, user, capabilities } = useContext(Context);
|
|
|
+ const [infras, setInfras] = useState<InfraType[]>([]);
|
|
|
+ const [pressingCtrl, setPressingCtrl] = useState(false);
|
|
|
+ const [pressingK, setPressingK] = useState(false);
|
|
|
+ const [showFormDebugger, setShowFormDebugger] = useState(false);
|
|
|
+ const [tabOptions, setTabOptions] = useState([{
|
|
|
+ label: "Connected clusters",
|
|
|
+ value: "overview"
|
|
|
+ }]);
|
|
|
+
|
|
|
+ const handleKeyDown = (e: KeyboardEvent): void => {
|
|
|
+ if (e.key === "k") {
|
|
|
+ setPressingK(true);
|
|
|
+ }
|
|
|
+ if (e.key === "Meta" || e.key === "Control") {
|
|
|
+ setPressingCtrl(true);
|
|
|
+ }
|
|
|
+ if (e.key === "z" && pressingK && pressingCtrl) {
|
|
|
+ setPressingK(false);
|
|
|
+ setPressingCtrl(false);
|
|
|
+ setShowFormDebugger(!showFormDebugger);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleKeyUp = (e: KeyboardEvent): void => {
|
|
|
+ if (e.key === "Meta" || e.key === "Control" || e.key === "k") {
|
|
|
+ setPressingK(false);
|
|
|
+ setPressingCtrl(false);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
- refreshInfras = () => {
|
|
|
- if (this.props.projectId) {
|
|
|
+ useEffect(() => {
|
|
|
+ document.addEventListener("keydown", handleKeyDown);
|
|
|
+ document.addEventListener("keyup", handleKeyUp);
|
|
|
+ return () => {
|
|
|
+ document.removeEventListener("keydown", handleKeyDown);
|
|
|
+ document.removeEventListener("keyup", handleKeyUp);
|
|
|
+ };
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (currentProject) {
|
|
|
+ if (currentProject.simplified_view_enabled) {
|
|
|
+ pushFiltered(props, "/apps", ["project_id"]);
|
|
|
+ }
|
|
|
api
|
|
|
.getInfra(
|
|
|
"<token>",
|
|
|
{},
|
|
|
{
|
|
|
- project_id: this.props.projectId,
|
|
|
+ project_id: currentProject.id,
|
|
|
}
|
|
|
)
|
|
|
- .then((res) => this.setState({ infras: res.data }))
|
|
|
+ .then((res) => setInfras(res.data))
|
|
|
.catch(console.log);
|
|
|
}
|
|
|
- };
|
|
|
-
|
|
|
- componentDidMount() {
|
|
|
- this.refreshInfras();
|
|
|
- document.addEventListener("keydown", this.handleKeyDown);
|
|
|
- document.addEventListener("keyup", this.handleKeyUp);
|
|
|
- }
|
|
|
+ }, [currentProject]);
|
|
|
|
|
|
- componentWillUnmount() {
|
|
|
- document.removeEventListener("keydown", this.handleKeyDown);
|
|
|
- document.removeEventListener("keyup", this.handleKeyUp);
|
|
|
- }
|
|
|
+ const currentTab = () => new URLSearchParams(props.location.search).get("tab");
|
|
|
|
|
|
- handleKeyDown = (e: KeyboardEvent): void => {
|
|
|
- let { pressingK, pressingCtrl } = this.state;
|
|
|
- if (e.key === "Meta" || e.key === "Control") {
|
|
|
- this.setState({ pressingCtrl: true });
|
|
|
- }
|
|
|
- if (e.key === "k") {
|
|
|
- this.setState({ pressingK: true });
|
|
|
- }
|
|
|
- if (e.key === "z" && pressingK && pressingCtrl) {
|
|
|
- this.setState({ pressingK: false, pressingCtrl: false });
|
|
|
- this.setState({ showFormDebugger: !this.state.showFormDebugger });
|
|
|
+ useEffect(() => {
|
|
|
+ if (props.isAuthorized("cluster", "", ["get", "create"])) {
|
|
|
+ tabOptions.push({ label: "Create a cluster", value: "create-cluster" });
|
|
|
}
|
|
|
- };
|
|
|
|
|
|
- handleKeyUp = (e: KeyboardEvent): void => {
|
|
|
- if (e.key === "Meta" || e.key === "Control" || e.key === "k") {
|
|
|
- this.setState({ pressingCtrl: false, pressingK: false });
|
|
|
- }
|
|
|
- };
|
|
|
+ tabOptions.push({ label: "Provisioner status", value: "provisioner" });
|
|
|
|
|
|
- componentDidUpdate(prevProps: PropsType) {
|
|
|
- if (this.props.projectId && prevProps.projectId !== this.props.projectId) {
|
|
|
- this.refreshInfras();
|
|
|
+ if (!capabilities?.provisioner) {
|
|
|
+ let newTabs = [{ label: "Project overview", value: "overview" }];
|
|
|
+ setTabOptions(newTabs);
|
|
|
+ } else {
|
|
|
+ setTabOptions(tabOptions);
|
|
|
}
|
|
|
- }
|
|
|
+ }, [currentProject]);
|
|
|
|
|
|
- currentTab = () => new URLSearchParams(this.props.location.search).get("tab");
|
|
|
-
|
|
|
- renderTabContents = () => {
|
|
|
- if (this.currentTab() === "provisioner") {
|
|
|
+ const renderTabContents = () => {
|
|
|
+ if (currentTab() === "provisioner") {
|
|
|
return (
|
|
|
<StatusPage
|
|
|
filter={[]}
|
|
|
- project_id={this.props.projectId}
|
|
|
+ project_id={currentProject.id}
|
|
|
setInfraStatus={() => null}
|
|
|
/>
|
|
|
);
|
|
|
- } else if (this.currentTab() === "create-cluster") {
|
|
|
- let helperText = "Create a cluster to link to this project";
|
|
|
- let helperType = "info";
|
|
|
- if (
|
|
|
- true
|
|
|
- ) {
|
|
|
- helperText =
|
|
|
- "You need to update your billing to provision or connect a new cluster";
|
|
|
- helperType = "warning";
|
|
|
- }
|
|
|
+ } else if (currentTab() === "create-cluster") {
|
|
|
+ const helperText =
|
|
|
+ "You need to update your billing to provision or connect a new cluster";
|
|
|
+ const helperType = "warning";
|
|
|
return (
|
|
|
<>
|
|
|
<Banner type={helperType} noMargin>
|
|
|
{helperText}
|
|
|
</Banner>
|
|
|
<Br />
|
|
|
- <ProvisionerSettings infras={this.state.infras} provisioner={true} />
|
|
|
+ <ProvisionerSettings infras={infras} provisioner={true} />
|
|
|
</>
|
|
|
);
|
|
|
} else {
|
|
|
@@ -129,139 +132,74 @@ class Dashboard extends Component<PropsType, StateType> {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- onShowProjectSettings = () => {
|
|
|
- pushFiltered(this.props, "/project-settings", ["project_id"]);
|
|
|
- };
|
|
|
-
|
|
|
- setCurrentTab = (x: string) => pushQueryParams(this.props, { tab: x });
|
|
|
-
|
|
|
- render() {
|
|
|
- let { currentProject, capabilities } = this.context;
|
|
|
- let { onShowProjectSettings } = this;
|
|
|
-
|
|
|
- let tabOptions = [{ label: "Connected clusters", value: "overview" }];
|
|
|
-
|
|
|
- if (this.props.isAuthorized("cluster", "", ["get", "create"])) {
|
|
|
- tabOptions.push({ label: "Create a cluster", value: "create-cluster" });
|
|
|
- }
|
|
|
-
|
|
|
- tabOptions.push({ label: "Provisioner status", value: "provisioner" });
|
|
|
-
|
|
|
- if (!capabilities?.provisioner) {
|
|
|
- tabOptions = [{ label: "Project overview", value: "overview" }];
|
|
|
- }
|
|
|
-
|
|
|
- return (
|
|
|
- <>
|
|
|
- {currentProject && (
|
|
|
- <DashboardWrapper>
|
|
|
- {this.state.showFormDebugger ? (
|
|
|
- <FormDebugger
|
|
|
- goBack={() => this.setState({ showFormDebugger: false })}
|
|
|
- />
|
|
|
- ) : (
|
|
|
- <>
|
|
|
- <TitleSection>
|
|
|
- <DashboardIcon>
|
|
|
- <DashboardImage src={gradient} />
|
|
|
- <Overlay>
|
|
|
- {currentProject && currentProject.name[0].toUpperCase()}
|
|
|
- </Overlay>
|
|
|
- </DashboardIcon>
|
|
|
- {currentProject && currentProject.name}
|
|
|
- {this.context.currentProject?.roles?.filter((obj: any) => {
|
|
|
- return obj.user_id === this.context.user.userId;
|
|
|
- })[0].kind === "admin" || (
|
|
|
- <i
|
|
|
- className="material-icons"
|
|
|
- onClick={onShowProjectSettings}
|
|
|
- >
|
|
|
- more_vert
|
|
|
- </i>
|
|
|
- )}
|
|
|
- </TitleSection>
|
|
|
- <Spacer height="15px" />
|
|
|
-
|
|
|
- <InfoSection>
|
|
|
- <TopRow>
|
|
|
- <InfoLabel>
|
|
|
- <i className="material-icons">info</i> Info
|
|
|
- </InfoLabel>
|
|
|
- </TopRow>
|
|
|
- <Description>
|
|
|
- Project overview for {currentProject && currentProject.name}
|
|
|
- .
|
|
|
- </Description>
|
|
|
- </InfoSection>
|
|
|
- {
|
|
|
- currentProject?.capi_provisioner_enabled ? (
|
|
|
- <ClusterSection />
|
|
|
- ) : (
|
|
|
- <TabRegion
|
|
|
- currentTab={this.currentTab()}
|
|
|
- setCurrentTab={this.setCurrentTab}
|
|
|
- options={tabOptions}
|
|
|
- >
|
|
|
- {this.renderTabContents()}
|
|
|
- </TabRegion>
|
|
|
- )
|
|
|
- }
|
|
|
- </>
|
|
|
- )}
|
|
|
- </DashboardWrapper>
|
|
|
- )}
|
|
|
- </>
|
|
|
- );
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-Dashboard.contextType = Context;
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ {currentProject && (
|
|
|
+ <DashboardWrapper>
|
|
|
+ {showFormDebugger ? (
|
|
|
+ <FormDebugger
|
|
|
+ goBack={() => setShowFormDebugger(false)}
|
|
|
+ />
|
|
|
+ ) : (
|
|
|
+ <>
|
|
|
+ <TitleSection>
|
|
|
+ <DashboardIcon>
|
|
|
+ <DashboardImage src={gradient} />
|
|
|
+ <Overlay>
|
|
|
+ {currentProject && currentProject.name[0].toUpperCase()}
|
|
|
+ </Overlay>
|
|
|
+ </DashboardIcon>
|
|
|
+ {currentProject && currentProject.name}
|
|
|
+ {currentProject?.roles?.filter((obj: any) => {
|
|
|
+ return obj.user_id === user.userId;
|
|
|
+ })[0].kind === "admin" || (
|
|
|
+ <i
|
|
|
+ className="material-icons"
|
|
|
+ onClick={() => {
|
|
|
+ pushFiltered(props, "/project-settings", ["project_id"]);
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ more_vert
|
|
|
+ </i>
|
|
|
+ )}
|
|
|
+ </TitleSection>
|
|
|
+ <Spacer height="15px" />
|
|
|
+ <InfoSection>
|
|
|
+ <TopRow>
|
|
|
+ <InfoLabel>
|
|
|
+ <i className="material-icons">info</i> Info
|
|
|
+ </InfoLabel>
|
|
|
+ </TopRow>
|
|
|
+ <Description>
|
|
|
+ Project overview for {currentProject && currentProject.name}
|
|
|
+ .
|
|
|
+ </Description>
|
|
|
+ </InfoSection>
|
|
|
+ {
|
|
|
+ currentProject?.capi_provisioner_enabled ? (
|
|
|
+ <ClusterSection />
|
|
|
+ ) : (
|
|
|
+ <TabRegion
|
|
|
+ currentTab={currentTab()}
|
|
|
+ setCurrentTab={(x: string) => {
|
|
|
+ pushQueryParams(props, { tab: x });
|
|
|
+ }}
|
|
|
+ options={tabOptions}
|
|
|
+ >
|
|
|
+ {renderTabContents()}
|
|
|
+ </TabRegion>
|
|
|
+ )
|
|
|
+ }
|
|
|
+ </>
|
|
|
+ )}
|
|
|
+ </DashboardWrapper>
|
|
|
+ )}
|
|
|
+ </>
|
|
|
+ );
|
|
|
+};
|
|
|
|
|
|
export default withRouter(withAuth(Dashboard));
|
|
|
|
|
|
-const Button = styled.div`
|
|
|
- display: flex;
|
|
|
- flex-direction: row;
|
|
|
- align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
- font-size: 13px;
|
|
|
- cursor: pointer;
|
|
|
- font-family: "Work Sans", sans-serif;
|
|
|
- border-radius: 5px;
|
|
|
- font-weight: 500;
|
|
|
- width: 147px;
|
|
|
- margin-bottom: 30px;
|
|
|
- color: white;
|
|
|
- height: 30px;
|
|
|
- padding: 0 8px;
|
|
|
- padding-right: 13px;
|
|
|
- overflow: hidden;
|
|
|
- white-space: nowrap;
|
|
|
- text-overflow: ellipsis;
|
|
|
- cursor: ${(props: { disabled?: boolean }) =>
|
|
|
- props.disabled ? "not-allowed" : "pointer"};
|
|
|
-
|
|
|
- background: ${(props: { disabled?: boolean }) =>
|
|
|
- props.disabled ? "#aaaabbee" : "#616FEEcc"};
|
|
|
- :hover {
|
|
|
- background: ${(props: { disabled?: boolean }) =>
|
|
|
- props.disabled ? "" : "#505edddd"};
|
|
|
- }
|
|
|
-
|
|
|
- > i {
|
|
|
- color: white;
|
|
|
- width: 18px;
|
|
|
- height: 18px;
|
|
|
- font-weight: 600;
|
|
|
- font-size: 12px;
|
|
|
- border-radius: 20px;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- margin-right: 5px;
|
|
|
- justify-content: center;
|
|
|
- }
|
|
|
-`;
|
|
|
-
|
|
|
const Br = styled.div`
|
|
|
width: 100%;
|
|
|
height: 1px;
|
|
|
@@ -271,23 +209,6 @@ const DashboardWrapper = styled.div`
|
|
|
padding-bottom: 100px;
|
|
|
`;
|
|
|
|
|
|
-// const Banner = styled.div<{ color: string }>`
|
|
|
-// height: 40px;
|
|
|
-// width: 100%;
|
|
|
-// margin: 5px 0 30px;
|
|
|
-// font-size: 13px;
|
|
|
-// display: flex;
|
|
|
-// border-radius: 5px;
|
|
|
-// padding-left: 15px;
|
|
|
-// align-items: center;
|
|
|
-// background: #ffffff11;
|
|
|
-// color: ${(props) => props.color};
|
|
|
-// > i {
|
|
|
-// margin-right: 10px;
|
|
|
-// font-size: 18px;
|
|
|
-// }
|
|
|
-// `;
|
|
|
-
|
|
|
const TopRow = styled.div`
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
@@ -321,13 +242,6 @@ const InfoSection = styled.div`
|
|
|
margin-bottom: 30px;
|
|
|
`;
|
|
|
|
|
|
-const LineBreak = styled.div`
|
|
|
- width: calc(100% - 0px);
|
|
|
- height: 1px;
|
|
|
- background: #494b4f;
|
|
|
- margin: 10px 0px 20px;
|
|
|
-`;
|
|
|
-
|
|
|
const Overlay = styled.div`
|
|
|
height: 100%;
|
|
|
width: 100%;
|