From b3651ed0a32b8741557aae14702b92b2fd2fe00a Mon Sep 17 00:00:00 2001 From: Javier Adriel Date: Wed, 3 Aug 2022 11:43:22 -0500 Subject: [PATCH] Auto register API key once it is retrieved from subnet (#2217) --- .../Console/Support/ApiKeyRegister.tsx | 183 ++++++--- .../Console/Support/GetApiKeyModal.tsx | 3 +- .../src/screens/Console/Support/Register.tsx | 346 ++++++------------ .../src/screens/Console/Support/utils.tsx | 100 ++++- 4 files changed, 345 insertions(+), 287 deletions(-) diff --git a/portal-ui/src/screens/Console/Support/ApiKeyRegister.tsx b/portal-ui/src/screens/Console/Support/ApiKeyRegister.tsx index 6c6ea2b57..2d81c93f7 100644 --- a/portal-ui/src/screens/Console/Support/ApiKeyRegister.tsx +++ b/portal-ui/src/screens/Console/Support/ApiKeyRegister.tsx @@ -14,29 +14,76 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import React, { Fragment, useState } from "react"; +import React, { Fragment, useEffect, useState } from "react"; import { Box, Button } from "@mui/material"; import { OnlineRegistrationIcon } from "../../../icons"; import { FormTitle } from "./utils"; import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper"; import GetApiKeyModal from "./GetApiKeyModal"; +import RegisterHelpBox from "./RegisterHelpBox"; +import { SubnetLoginRequest, SubnetLoginResponse } from "../License/types"; +import api from "../../../common/api"; +import { useAppDispatch } from "../../../store"; +import { setErrorSnackMessage } from "../../../systemSlice"; +import { ErrorResponseHandler } from "../../../common/types"; +import { useCallback } from "react"; +import { spacingUtils } from "../Common/FormComponents/common/styleLibrary"; +import { Theme } from "@mui/material/styles"; +import createStyles from "@mui/styles/createStyles"; +import withStyles from "@mui/styles/withStyles"; interface IApiKeyRegister { classes: any; - apiKey: string; - setApiKey: (v: string) => void; - onRegister: () => void; - loading: boolean; + afterRegister: () => void; } -const ApiKeyRegister = ({ - classes, - apiKey, - setApiKey, - loading, - onRegister, -}: IApiKeyRegister) => { +const styles = (theme: Theme) => + createStyles({ + sizedLabel: { + minWidth: "75px", + }, + ...spacingUtils, + }); + +const ApiKeyRegister = ({ classes, afterRegister }: IApiKeyRegister) => { const [showApiKeyModal, setShowApiKeyModal] = useState(false); + const [apiKey, setApiKey] = useState(""); + const [loading, setLoading] = useState(false); + const [fromModal, setFromModal] = useState(false); + const dispatch = useAppDispatch(); + + const onRegister = useCallback(() => { + if (loading) { + return; + } + setLoading(true); + let request: SubnetLoginRequest = { apiKey }; + api + .invoke("POST", "/api/v1/subnet/login", request) + .then((resp: SubnetLoginResponse) => { + setLoading(false); + if (resp && resp.registered) { + reset(); + afterRegister(); + } + }) + .catch((err: ErrorResponseHandler) => { + dispatch(setErrorSnackMessage(err)); + setLoading(false); + reset(); + }); + }, [afterRegister, apiKey, dispatch, loading]); + + useEffect(() => { + if (fromModal) { + onRegister(); + } + }, [fromModal, onRegister]); + + const reset = () => { + setApiKey(""); + setFromModal(false); + }; return ( @@ -53,60 +100,92 @@ const ApiKeyRegister = ({ title={`API key activation of MinIO Subscription Network License`} /> - - ) => - setApiKey(event.target.value) - } - label="API Key" - value={apiKey} - /> - - - - setShowApiKeyModal(false)} - onSet={setApiKey} - /> + ) => + setApiKey(event.target.value) + } + label="API Key" + value={apiKey} + /> + + + + + setShowApiKeyModal(false)} + onSet={(value) => { + setApiKey(value); + setFromModal(true); + }} + /> + + + ); }; -export default ApiKeyRegister; +export default withStyles(styles)(ApiKeyRegister); diff --git a/portal-ui/src/screens/Console/Support/GetApiKeyModal.tsx b/portal-ui/src/screens/Console/Support/GetApiKeyModal.tsx index bbc3cb096..14f02fc0b 100644 --- a/portal-ui/src/screens/Console/Support/GetApiKeyModal.tsx +++ b/portal-ui/src/screens/Console/Support/GetApiKeyModal.tsx @@ -214,7 +214,8 @@ const GetApiKeyModal = ({ onConfirm={onConfirm} onClose={closeModal} confirmButtonProps={{ - color: "info", + color: "primary", + variant: "contained", disabled: !email || !password || isLoading, hidden: true, }} diff --git a/portal-ui/src/screens/Console/Support/Register.tsx b/portal-ui/src/screens/Console/Support/Register.tsx index 8fd2a0397..4493dc6a7 100644 --- a/portal-ui/src/screens/Console/Support/Register.tsx +++ b/portal-ui/src/screens/Console/Support/Register.tsx @@ -24,7 +24,7 @@ import { spacingUtils, } from "../Common/FormComponents/common/styleLibrary"; import withStyles from "@mui/styles/withStyles"; -import { Box, Button, Grid, Link } from "@mui/material"; +import { Box, Button, Link } from "@mui/material"; import PageHeader from "../Common/PageHeader/PageHeader"; import PageLayout from "../Common/Layout/PageLayout"; import { CopyIcon, UsersIcon } from "../../../icons"; @@ -55,17 +55,13 @@ import { } from "../../../common/SecureComponent/permissions"; import { useSelector } from "react-redux"; -import SettingsIcon from "../../../icons/SettingsIcon"; -import FormSwitchWrapper from "../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper"; - import RegisterHelpBox from "./RegisterHelpBox"; -import RegistrationStatusBanner from "./RegistrationStatusBanner"; import { selOpMode, setErrorSnackMessage } from "../../../systemSlice"; import { useAppDispatch } from "../../../store"; import Tabs from "@mui/material/Tabs"; import Tab from "@mui/material/Tab"; import { TabPanel } from "../../shared/tabs"; -import { ClusterRegistered, FormTitle } from "./utils"; +import { ClusterRegistered, FormTitle, ProxyConfiguration } from "./utils"; import ApiKeyRegister from "./ApiKeyRegister"; interface IRegister { classes: any; @@ -161,7 +157,6 @@ const Register = ({ classes }: IRegister) => { const [initialLicenseLoading, setInitialLicenseLoading] = useState(true); - const [displaySubnetProxy, setDisplaySubnetProxy] = useState(false); const clearForm = () => { setSubnetAccessToken(""); setSelectedSubnetOrganization(""); @@ -470,111 +465,128 @@ const Register = ({ classes }: IRegister) => { ); } else { clusterRegistrationForm = ( - + + + } + title={`Online activation of MinIO Subscription Network License`} + /> + - Use your MinIO Subscription Network login credentials to register - this cluster. - - - ) => - setSubnetEmail(event.target.value) - } - label="Email" - value={subnetEmail} - overlayIcon={} - /> - ) => - setSubnetPassword(event.target.value) - } - label="Password" - type={showPassword ? "text" : "password"} - value={subnetPassword} - overlayIcon={ - showPassword ? : - } - overlayAction={() => setShowPassword(!showPassword)} - /> - - - + + + + - - + ); } @@ -595,15 +607,10 @@ const Register = ({ classes }: IRegister) => { linkClass={classes.link} /> ) : ( - + )} + ); @@ -791,9 +798,6 @@ const Register = ({ classes }: IRegister) => { ); - const proxyConfigurationCommand = - "mc admin config set {alias} subnet proxy={proxy}"; - const regUi = ( { padding: "43px", }} > - {clusterRegistered && ( - + {clusterRegistered && licenseInfo ? ( + + ) : ( + clusterRegistrationForm )} - {clusterRegistered ? ( - - - Login to{" "} - - SUBNET - {" "} - to avail support for this MinIO cluster - - - ) : null} - - {clusterRegistered ? null : ( - - } - title={`Online activation of MinIO Subscription Network License`} - /> - - )} - - {clusterRegistered ? null : clusterRegistrationForm} - {!clusterRegistered && ( - - - - - -
- Proxy Configuration -
-
- - For airgap/firewalled environments it is possible to{" "} - - configure a proxy - {" "} - to connect to SUBNET . - - - {displaySubnetProxy && ( - {}} - label="" - value={proxyConfigurationCommand} - overlayIcon={} - extraInputProps={{ - readOnly: true, - }} - overlayAction={() => - navigator.clipboard.writeText(proxyConfigurationCommand) - } - /> - )} - -
- - ) => { - setDisplaySubnetProxy(event.target.checked); - }} - /> - -
-
- )} + {!clusterRegistered && }
); diff --git a/portal-ui/src/screens/Console/Support/utils.tsx b/portal-ui/src/screens/Console/Support/utils.tsx index a4bfb8b25..c7b439934 100644 --- a/portal-ui/src/screens/Console/Support/utils.tsx +++ b/portal-ui/src/screens/Console/Support/utils.tsx @@ -1,5 +1,8 @@ import { Box, Grid, Link } from "@mui/material"; -import { Fragment } from "react"; +import { Fragment, useState } from "react"; +import { CopyIcon, SettingsIcon } from "../../../icons"; +import FormSwitchWrapper from "../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper"; +import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper"; import RegistrationStatusBanner from "./RegistrationStatusBanner"; export const FormTitle = ({ @@ -57,3 +60,98 @@ export const ClusterRegistered = ({ ); }; + +export const ProxyConfiguration = ({ linkClass }: { linkClass: string }) => { + const proxyConfigurationCommand = + "mc admin config set {alias} subnet proxy={proxy}"; + const [displaySubnetProxy, setDisplaySubnetProxy] = useState(false); + return ( + + + + + +
+ Proxy Configuration +
+
+ + For airgap/firewalled environments it is possible to{" "} + + configure a proxy + {" "} + to connect to SUBNET . + + + {displaySubnetProxy && ( + {}} + label="" + value={proxyConfigurationCommand} + overlayIcon={} + extraInputProps={{ + readOnly: true, + }} + overlayAction={() => + navigator.clipboard.writeText(proxyConfigurationCommand) + } + /> + )} + +
+ + ) => { + setDisplaySubnetProxy(event.target.checked); + }} + /> + +
+
+ ); +};