diff --git a/portal-ui/src/screens/Console/Console.tsx b/portal-ui/src/screens/Console/Console.tsx
index e859f8bb4..2166e0bba 100644
--- a/portal-ui/src/screens/Console/Console.tsx
+++ b/portal-ui/src/screens/Console/Console.tsx
@@ -66,6 +66,7 @@ const Heal = React.lazy(() => import("./Heal/Heal"));
const Watch = React.lazy(() => import("./Watch/Watch"));
const HealthInfo = React.lazy(() => import("./HealthInfo/HealthInfo"));
const Hop = React.lazy(() => import("./Tenants/TenantDetails/hop/Hop"));
+const RegisterOperator = React.lazy(() => import("./Support/RegisterOperator"));
const AddTenant = React.lazy(() => import("./Tenants/AddTenant/AddTenant"));
@@ -462,6 +463,11 @@ const Console = ({ classes }: IConsoleProps) => {
path: IAM_PAGES.LICENSE,
forceDisplay: true,
},
+ {
+ component: RegisterOperator,
+ path: IAM_PAGES.REGISTER_SUPPORT,
+ forceDisplay: true,
+ },
{
component: Marketplace,
path: IAM_PAGES.OPERATOR_MARKETPLACE,
diff --git a/portal-ui/src/screens/Console/Support/ApiKeyRegister.tsx b/portal-ui/src/screens/Console/Support/ApiKeyRegister.tsx
index 2d81c93f7..597776d18 100644
--- a/portal-ui/src/screens/Console/Support/ApiKeyRegister.tsx
+++ b/portal-ui/src/screens/Console/Support/ApiKeyRegister.tsx
@@ -34,6 +34,7 @@ import withStyles from "@mui/styles/withStyles";
interface IApiKeyRegister {
classes: any;
+ registerEndpoint: string;
afterRegister: () => void;
}
@@ -45,7 +46,11 @@ const styles = (theme: Theme) =>
...spacingUtils,
});
-const ApiKeyRegister = ({ classes, afterRegister }: IApiKeyRegister) => {
+const ApiKeyRegister = ({
+ classes,
+ registerEndpoint,
+ afterRegister,
+}: IApiKeyRegister) => {
const [showApiKeyModal, setShowApiKeyModal] = useState(false);
const [apiKey, setApiKey] = useState("");
const [loading, setLoading] = useState(false);
@@ -59,7 +64,7 @@ const ApiKeyRegister = ({ classes, afterRegister }: IApiKeyRegister) => {
setLoading(true);
let request: SubnetLoginRequest = { apiKey };
api
- .invoke("POST", "/api/v1/subnet/login", request)
+ .invoke("POST", registerEndpoint, request)
.then((resp: SubnetLoginResponse) => {
setLoading(false);
if (resp && resp.registered) {
@@ -72,7 +77,7 @@ const ApiKeyRegister = ({ classes, afterRegister }: IApiKeyRegister) => {
setLoading(false);
reset();
});
- }, [afterRegister, apiKey, dispatch, loading]);
+ }, [afterRegister, apiKey, dispatch, loading, registerEndpoint]);
useEffect(() => {
if (fromModal) {
diff --git a/portal-ui/src/screens/Console/Support/Register.tsx b/portal-ui/src/screens/Console/Support/Register.tsx
index 4493dc6a7..3febe8796 100644
--- a/portal-ui/src/screens/Console/Support/Register.tsx
+++ b/portal-ui/src/screens/Console/Support/Register.tsx
@@ -607,7 +607,10 @@ const Register = ({ classes }: IRegister) => {
linkClass={classes.link}
/>
) : (
-
+
)}
diff --git a/portal-ui/src/screens/Console/Support/RegisterOperator.tsx b/portal-ui/src/screens/Console/Support/RegisterOperator.tsx
new file mode 100644
index 000000000..eb17d202d
--- /dev/null
+++ b/portal-ui/src/screens/Console/Support/RegisterOperator.tsx
@@ -0,0 +1,185 @@
+// This file is part of MinIO Console Server
+// Copyright (c) 2022 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public APIKey as published by
+// the Free Software Foundation, either version 3 of the APIKey, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public APIKey for more details.
+//
+// You should have received a copy of the GNU Affero General Public APIKey
+// along with this program. If not, see .
+
+import React, { Fragment, useCallback, useEffect, useState } from "react";
+import { Theme } from "@mui/material/styles";
+import createStyles from "@mui/styles/createStyles";
+import {
+ actionsTray,
+ containerForHeader,
+ searchField,
+ spacingUtils,
+} from "../Common/FormComponents/common/styleLibrary";
+import withStyles from "@mui/styles/withStyles";
+import { Box } from "@mui/material";
+import PageHeader from "../Common/PageHeader/PageHeader";
+import PageLayout from "../Common/Layout/PageLayout";
+import api from "../../../common/api";
+
+import { ErrorResponseHandler } from "../../../common/types";
+
+import Tabs from "@mui/material/Tabs";
+import Tab from "@mui/material/Tab";
+import { TabPanel } from "../../shared/tabs";
+import { ClusterRegistered } from "./utils";
+import ApiKeyRegister from "./ApiKeyRegister";
+
+interface IRegister {
+ classes: any;
+}
+
+const styles = (theme: Theme) =>
+ createStyles({
+ registerActivationIcon: {
+ color: theme.palette.primary.main,
+ fontSize: 16,
+ fontWeight: "bold",
+ marginBottom: 20,
+ "& .min-icon": {
+ width: 32.12,
+ height: 25,
+ marginRight: 10,
+ verticalAlign: "middle",
+ },
+ },
+ registerActivationMode: {
+ textAlign: "right",
+ "& a": {
+ cursor: "pointer",
+ },
+ },
+ subnetDescription: {
+ textAlign: "left",
+ Font: "normal normal normal 14px/17px Lato",
+ letterSpacing: 0,
+ color: "#000000",
+ "& span": {
+ fontWeight: "bold",
+ },
+ },
+ registeredStatus: {
+ border: "1px solid #E2E2E2",
+ padding: "24px 24px 24px 24px",
+ borderRadius: 2,
+ marginBottom: 25,
+ backgroundColor: "#FBFAFA",
+ "& .min-icon": {
+ width: 20,
+ height: 20,
+ marginLeft: 48,
+ marginRight: 13,
+ verticalAlign: "middle",
+ marginTop: -3,
+ },
+ "& span": {
+ fontWeight: "bold",
+ },
+ },
+ copyInputBox: {
+ "& button": {
+ border: "1px solid #5E5E5E",
+ borderRadius: 2,
+ },
+ },
+ link: {
+ color: "#2781B0",
+ cursor: "pointer",
+ },
+ sizedLabel: {
+ minWidth: "75px",
+ },
+ ...actionsTray,
+ ...searchField,
+ ...spacingUtils,
+ ...containerForHeader(theme.spacing(4)),
+ });
+
+const RegisterOperator = ({ classes }: IRegister) => {
+ const [apiKeyRegistered, setAPIKeyRegistered] = useState(false);
+ const [curTab, setCurTab] = useState(0);
+
+ const fetchAPIKeyInfo = useCallback(() => {
+ api
+ .invoke("GET", `/api/v1/subnet/apikey/info`)
+ .then((res: any) => {
+ setAPIKeyRegistered(true);
+ })
+ .catch((err: ErrorResponseHandler) => {
+ setAPIKeyRegistered(false);
+ });
+ }, []);
+
+ useEffect(() => {
+ fetchAPIKeyInfo();
+ }, [fetchAPIKeyInfo]);
+
+ const apiKeyRegistration = (
+
+
+ {apiKeyRegistered ? (
+
+ ) : (
+
+ )}
+
+
+ );
+
+ return (
+
+ }
+ />
+
+
+ , newValue: number) => {
+ setCurTab(newValue);
+ }}
+ indicatorColor="primary"
+ textColor="primary"
+ aria-label="cluster-tabs"
+ variant="scrollable"
+ scrollButtons="auto"
+ >
+
+
+
+ {apiKeyRegistration}
+
+
+
+ );
+};
+
+export default withStyles(styles)(RegisterOperator);
diff --git a/portal-ui/src/screens/Console/valid-routes.ts b/portal-ui/src/screens/Console/valid-routes.ts
index 2a6918249..68f87fc0a 100644
--- a/portal-ui/src/screens/Console/valid-routes.ts
+++ b/portal-ui/src/screens/Console/valid-routes.ts
@@ -293,6 +293,16 @@ export const validRoutes = (
icon: LicenseIcon,
forceDisplay: true,
},
+ {
+ group: "Operator",
+ type: "item",
+ id: "Register",
+ component: NavLink,
+ to: IAM_PAGES.REGISTER_SUPPORT,
+ name: "Register",
+ icon: RegisterMenuIcon,
+ forceDisplay: true,
+ },
{
group: "Operator",
type: "item",