diff --git a/.github/workflows/jobs.yaml b/.github/workflows/jobs.yaml
index 5544d5edd..64d443c94 100644
--- a/.github/workflows/jobs.yaml
+++ b/.github/workflows/jobs.yaml
@@ -276,7 +276,7 @@ jobs:
semgrep --config semgrep.yaml $(pwd)/portal-ui --error
no-warnings-and-make-assets:
- name: "React Code Has No Warning & Prettified and then Make Assets"
+ name: "React Code Has No Warnings & is Prettified, then Make Assets"
runs-on: ${{ matrix.os }}
strategy:
matrix:
diff --git a/models/login_request.go b/models/login_request.go
index 696785edc..a9cd8327a 100644
--- a/models/login_request.go
+++ b/models/login_request.go
@@ -28,7 +28,6 @@ import (
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
- "github.com/go-openapi/validate"
)
// LoginRequest login request
@@ -37,48 +36,32 @@ import (
type LoginRequest struct {
// access key
- // Required: true
- AccessKey *string `json:"accessKey"`
+ AccessKey string `json:"accessKey,omitempty"`
// features
Features *LoginRequestFeatures `json:"features,omitempty"`
// secret key
- // Required: true
- SecretKey *string `json:"secretKey"`
+ SecretKey string `json:"secretKey,omitempty"`
+
+ // sts
+ Sts string `json:"sts,omitempty"`
}
// Validate validates this login request
func (m *LoginRequest) Validate(formats strfmt.Registry) error {
var res []error
- if err := m.validateAccessKey(formats); err != nil {
- res = append(res, err)
- }
-
if err := m.validateFeatures(formats); err != nil {
res = append(res, err)
}
- if err := m.validateSecretKey(formats); err != nil {
- res = append(res, err)
- }
-
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
-func (m *LoginRequest) validateAccessKey(formats strfmt.Registry) error {
-
- if err := validate.Required("accessKey", "body", m.AccessKey); err != nil {
- return err
- }
-
- return nil
-}
-
func (m *LoginRequest) validateFeatures(formats strfmt.Registry) error {
if swag.IsZero(m.Features) { // not required
return nil
@@ -98,15 +81,6 @@ func (m *LoginRequest) validateFeatures(formats strfmt.Registry) error {
return nil
}
-func (m *LoginRequest) validateSecretKey(formats strfmt.Registry) error {
-
- if err := validate.Required("secretKey", "body", m.SecretKey); err != nil {
- return err
- }
-
- return nil
-}
-
// ContextValidate validate this login request based on the context it is used
func (m *LoginRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
diff --git a/models/principal.go b/models/principal.go
index 761359b32..23899c1fd 100644
--- a/models/principal.go
+++ b/models/principal.go
@@ -48,6 +48,9 @@ type Principal struct {
// hm
Hm bool `json:"hm,omitempty"`
+
+ // ob
+ Ob bool `json:"ob,omitempty"`
}
// Validate validates this principal
diff --git a/operatorapi/embedded_spec.go b/operatorapi/embedded_spec.go
index 2dc8f4008..dd7278418 100644
--- a/operatorapi/embedded_spec.go
+++ b/operatorapi/embedded_spec.go
@@ -3288,10 +3288,6 @@ func init() {
},
"loginRequest": {
"type": "object",
- "required": [
- "accessKey",
- "secretKey"
- ],
"properties": {
"accessKey": {
"type": "string"
@@ -3306,6 +3302,9 @@ func init() {
},
"secretKey": {
"type": "string"
+ },
+ "sts": {
+ "type": "string"
}
}
},
@@ -8801,10 +8800,6 @@ func init() {
},
"loginRequest": {
"type": "object",
- "required": [
- "accessKey",
- "secretKey"
- ],
"properties": {
"accessKey": {
"type": "string"
@@ -8819,6 +8814,9 @@ func init() {
},
"secretKey": {
"type": "string"
+ },
+ "sts": {
+ "type": "string"
}
}
},
diff --git a/pkg/auth/token.go b/pkg/auth/token.go
index c287b5d2a..49f084a70 100644
--- a/pkg/auth/token.go
+++ b/pkg/auth/token.go
@@ -67,11 +67,18 @@ type TokenClaims struct {
STSSessionToken string `json:"stsSessionToken,omitempty"`
AccountAccessKey string `json:"accountAccessKey,omitempty"`
HideMenu bool `json:"hm,omitempty"`
+ ObjectBrowser bool `json:"ob,omitempty"`
+}
+
+// STSClaims claims struct for STS Token
+type STSClaims struct {
+ AccessKey string `json:"accessKey,omitempty"`
}
// SessionFeatures represents features stored in the session
type SessionFeatures struct {
- HideMenu bool
+ HideMenu bool
+ ObjectBrowser bool
}
// SessionTokenAuthenticate takes a session token, decode it, extract claims and validate the signature
@@ -115,6 +122,7 @@ func NewEncryptedTokenForClient(credentials *credentials.Value, accountAccessKey
}
if features != nil {
tokenClaims.HideMenu = features.HideMenu
+ tokenClaims.ObjectBrowser = features.ObjectBrowser
}
encryptedClaims, err := encryptClaims(tokenClaims)
if err != nil {
diff --git a/portal-ui/src/screens/Console/Buckets/BucketDetails/BrowserHandler.tsx b/portal-ui/src/screens/Console/Buckets/BucketDetails/BrowserHandler.tsx
index 1cbb18c53..7389673d7 100644
--- a/portal-ui/src/screens/Console/Buckets/BucketDetails/BrowserHandler.tsx
+++ b/portal-ui/src/screens/Console/Buckets/BucketDetails/BrowserHandler.tsx
@@ -36,13 +36,15 @@ import {
IAM_ROLES,
IAM_SCOPES,
} from "../../../../common/SecureComponent/permissions";
-import SearchBox from "../../Common/SearchBox";
import BackLink from "../../../../common/BackLink";
import {
setSearchObjects,
setSearchVersions,
setVersionsModeEnabled,
} from "../../ObjectBrowser/objectBrowserSlice";
+import SearchBox from "../../Common/SearchBox";
+import { selFeatures } from "../../consoleSlice";
+import { LoginMinIOLogo } from "../../../../icons";
const styles = (theme: Theme) =>
createStyles({
@@ -67,9 +69,13 @@ const BrowserHandler = () => {
(state: AppState) => state.objectBrowser.searchVersions
);
+ const features = useSelector(selFeatures);
+
const bucketName = params.bucketName || "";
const internalPaths = get(params, "subpaths", "");
+ const obOnly = !!features?.includes("object-browser-only");
+
useEffect(() => {
dispatch(setVersionsModeEnabled({ status: false }));
}, [internalPaths, dispatch]);
@@ -78,59 +84,79 @@ const BrowserHandler = () => {
navigate(`/buckets/${bucketName}/admin`);
};
+ const searchBar = (
+
+ {!versionsMode ? (
+
+ {
+ dispatch(setSearchObjects(value));
+ }}
+ value={searchObjects}
+ />
+
+ ) : (
+
+ {
+ dispatch(setSearchVersions(value));
+ }}
+ value={searchVersions}
+ />
+
+ )}
+
+ );
+
return (
- }
- actions={
-
-
-
-
-
-
-
- }
- middleComponent={
-
- {!versionsMode ? (
-
- {
- dispatch(setSearchObjects(value));
- }}
- value={searchObjects}
- />
-
- ) : (
-
- {
- dispatch(setSearchVersions(value));
- }}
- value={searchVersions}
- />
-
- )}
-
- }
- />
+ {!obOnly ? (
+ }
+ actions={
+
+
+
+
+
+
+
+ }
+ middleComponent={searchBar}
+ />
+ ) : (
+
+
+
+
+
+ {searchBar}
+
+
+ )}
diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/BucketListItem.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/BucketListItem.tsx
index 5665e810d..4eec912c9 100644
--- a/portal-ui/src/screens/Console/Buckets/ListBuckets/BucketListItem.tsx
+++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/BucketListItem.tsx
@@ -163,6 +163,7 @@ interface IBucketListItem {
onSelect: (e: React.ChangeEvent) => void;
selected: boolean;
bulkSelect: boolean;
+ noManage?: boolean;
}
const BucketListItem = ({
@@ -171,6 +172,7 @@ const BucketListItem = ({
onSelect,
selected,
bulkSelect,
+ noManage = false,
}: IBucketListItem) => {
const usage = niceBytes(`${bucket.size}` || "0");
const usageScalar = usage.split(" ")[0];
@@ -236,24 +238,26 @@ const BucketListItem = ({
-
-
- {}}
- text={"Manage"}
- icon={}
- color={"primary"}
- variant={"outlined"}
- />
-
-
+
+ {}}
+ text={"Manage"}
+ icon={}
+ color={"primary"}
+ variant={"outlined"}
+ />
+
+
+ )}
createStyles({
@@ -98,9 +101,11 @@ const ListBuckets = ({ classes }: IListBucketsProps) => {
const [replicationModalOpen, setReplicationModalOpen] =
useState(false);
const [lifecycleModalOpen, setLifecycleModalOpen] = useState(false);
-
const [bulkSelect, setBulkSelect] = useState(false);
+ const features = useSelector(selFeatures);
+ const obOnly = !!features?.includes("object-browser-only");
+
useEffect(() => {
if (loading) {
const fetchRecords = () => {
@@ -172,6 +177,7 @@ const ListBuckets = ({ classes }: IListBucketsProps) => {
onSelect={selectListBuckets}
selected={selectedBuckets.includes(bucket.name)}
bulkSelect={bulkSelect}
+ noManage={obOnly}
/>
);
}
@@ -209,9 +215,16 @@ const ListBuckets = ({ classes }: IListBucketsProps) => {
open={lifecycleModalOpen}
/>
)}
-
+ {!obOnly && }
+ {obOnly && (
+
+
+
+ )}
{
alignItems={"center"}
justifyContent={"flex-end"}
>
- {
- setBulkSelect(!bulkSelect);
- setSelectedBuckets([]);
- }}
- text={""}
- icon={}
- color={"primary"}
- variant={bulkSelect ? "contained" : "outlined"}
- />
+ {!obOnly && (
+
+ {
+ setBulkSelect(!bulkSelect);
+ setSelectedBuckets([]);
+ }}
+ text={""}
+ icon={}
+ color={"primary"}
+ variant={bulkSelect ? "contained" : "outlined"}
+ />
- {bulkSelect && (
- }
- color={"primary"}
- variant={"outlined"}
- />
+ {bulkSelect && (
+ }
+ color={"primary"}
+ variant={"outlined"}
+ />
+ )}
+
+ {
+ setLifecycleModalOpen(true);
+ }}
+ text={""}
+ icon={}
+ disabled={selectedBuckets.length === 0}
+ color={"primary"}
+ variant={"outlined"}
+ />
+
+ {
+ setReplicationModalOpen(true);
+ }}
+ text={""}
+ icon={}
+ disabled={selectedBuckets.length === 0}
+ color={"primary"}
+ variant={"outlined"}
+ />
+
)}
- {
- setLifecycleModalOpen(true);
- }}
- text={""}
- icon={}
- disabled={selectedBuckets.length === 0}
- color={"primary"}
- variant={"outlined"}
- />
-
- {
- setReplicationModalOpen(true);
- }}
- text={""}
- icon={}
- disabled={selectedBuckets.length === 0}
- color={"primary"}
- variant={"outlined"}
- />
-
{
@@ -290,17 +307,19 @@ const ListBuckets = ({ classes }: IListBucketsProps) => {
variant={"outlined"}
/>
- {
- navigate(IAM_PAGES.ADD_BUCKETS);
- }}
- text={"Create Bucket"}
- icon={}
- color={"primary"}
- variant={"contained"}
- disabled={!canCreateBucket}
- />
+ {!obOnly && (
+ {
+ navigate(IAM_PAGES.ADD_BUCKETS);
+ }}
+ text={"Create Bucket"}
+ icon={}
+ color={"primary"}
+ variant={"contained"}
+ disabled={!canCreateBucket}
+ />
+ )}
diff --git a/portal-ui/src/screens/Console/Console.tsx b/portal-ui/src/screens/Console/Console.tsx
index 15700e443..4f17096c2 100644
--- a/portal-ui/src/screens/Console/Console.tsx
+++ b/portal-ui/src/screens/Console/Console.tsx
@@ -203,6 +203,8 @@ const Console = ({ classes }: IConsoleProps) => {
const [openSnackbar, setOpenSnackbar] = useState(false);
const ldapIsEnabled = (features && features.includes("ldap-idp")) || false;
+ const obOnly = !!features?.includes("object-browser-only");
+
const restartServer = () => {
dispatch(serverIsLoading(true));
api
@@ -461,16 +463,17 @@ const Console = ({ classes }: IConsoleProps) => {
const allowedRoutes = (
operatorMode ? operatorConsoleRoutes : consoleAdminRoutes
- ).filter(
- (route: any) =>
- (route.forceDisplay ||
- (route.customPermissionFnc
- ? route.customPermissionFnc()
- : hasPermission(
- CONSOLE_UI_RESOURCE,
- IAM_PAGES_PERMISSIONS[route.path]
- ))) &&
- !route.fsHidden
+ ).filter((route: any) =>
+ obOnly
+ ? route.path.includes("buckets")
+ : (route.forceDisplay ||
+ (route.customPermissionFnc
+ ? route.customPermissionFnc()
+ : hasPermission(
+ CONSOLE_UI_RESOURCE,
+ IAM_PAGES_PERMISSIONS[route.path]
+ ))) &&
+ !route.fsHidden
);
const closeSnackBar = () => {
@@ -494,6 +497,8 @@ const Console = ({ classes }: IConsoleProps) => {
hideMenu = true;
} else if (pathname.endsWith("/hop")) {
hideMenu = true;
+ } else if (obOnly) {
+ hideMenu = true;
}
return (
diff --git a/portal-ui/src/screens/LoginPage/LoginField.tsx b/portal-ui/src/screens/LoginPage/LoginField.tsx
new file mode 100644
index 000000000..70647fdc3
--- /dev/null
+++ b/portal-ui/src/screens/LoginPage/LoginField.tsx
@@ -0,0 +1,68 @@
+// 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 License as published by
+// the Free Software Foundation, either version 3 of the License, 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 License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+import makeStyles from "@mui/styles/makeStyles";
+import { Theme } from "@mui/material/styles";
+import createStyles from "@mui/styles/createStyles";
+import { TextFieldProps } from "@mui/material";
+import TextField from "@mui/material/TextField";
+import React from "react";
+
+const inputStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ "& .MuiOutlinedInput-root": {
+ paddingLeft: 0,
+ "& svg": {
+ marginLeft: 4,
+ height: 14,
+ color: theme.palette.primary.main,
+ },
+ "& input": {
+ padding: 10,
+ fontSize: 14,
+ paddingLeft: 0,
+ "&::placeholder": {
+ fontSize: 12,
+ },
+ "@media (max-width: 900px)": {
+ padding: 10,
+ },
+ },
+ "& fieldset": {},
+
+ "& fieldset:hover": {
+ borderBottom: "2px solid #000000",
+ borderRadius: 0,
+ },
+ },
+ },
+ })
+);
+
+export const LoginField = (props: TextFieldProps) => {
+ const classes = inputStyles();
+
+ return (
+
+ );
+};
diff --git a/portal-ui/src/screens/LoginPage/LoginPage.tsx b/portal-ui/src/screens/LoginPage/LoginPage.tsx
index a2f0fd01d..988487018 100644
--- a/portal-ui/src/screens/LoginPage/LoginPage.tsx
+++ b/portal-ui/src/screens/LoginPage/LoginPage.tsx
@@ -14,25 +14,16 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
-import React, { useEffect, useState } from "react";
+import React, { useEffect } from "react";
import { useNavigate } from "react-router-dom";
-import {
- Box,
- InputAdornment,
- LinearProgress,
- TextFieldProps,
-} from "@mui/material";
+import { Box, InputAdornment, LinearProgress } from "@mui/material";
import { Theme, useTheme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import makeStyles from "@mui/styles/makeStyles";
-import withStyles from "@mui/styles/withStyles";
import Button from "@mui/material/Button";
-import TextField from "@mui/material/TextField";
import Grid from "@mui/material/Grid";
-import { ILoginDetails, loginStrategyType } from "./types";
-import { ErrorResponseHandler } from "../../common/types";
-import api from "../../common/api";
+import { loginStrategyType } from "./types";
import RefreshIcon from "../../icons/RefreshIcon";
import MainError from "../Console/Common/MainError/MainError";
import {
@@ -45,20 +36,22 @@ import {
} from "../../icons";
import { spacingUtils } from "../Console/Common/FormComponents/common/styleLibrary";
import CssBaseline from "@mui/material/CssBaseline";
-import LockFilledIcon from "../../icons/LockFilledIcon";
-import UserFilledIcon from "../../icons/UsersFilledIcon";
import { SupportMenuIcon } from "../../icons/SidebarMenus";
import GithubIcon from "../../icons/GithubIcon";
import clsx from "clsx";
import Loader from "../Console/Common/Loader/Loader";
+import { AppState, useAppDispatch } from "../../store";
+import { useSelector } from "react-redux";
import {
- setErrorSnackMessage,
- userLogged,
- showMarketplace,
-} from "../../systemSlice";
-import { useAppDispatch } from "../../store";
+ doLoginAsync,
+ getFetchConfigurationAsync,
+ getVersionAsync,
+} from "./loginThunks";
+import { resetForm, setJwt } from "./loginSlice";
+import StrategyForm from "./StrategyForm";
+import { LoginField } from "./LoginField";
-const styles = (theme: Theme) =>
+const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
position: "absolute",
@@ -78,18 +71,6 @@ const styles = (theme: Theme) =>
boxShadow: "none",
padding: "16px 30px",
},
- learnMore: {
- textAlign: "center",
- fontSize: 10,
- "& a": {
- color: "#2781B0",
- },
- "& .min-icon": {
- marginLeft: 12,
- marginTop: 2,
- width: 10,
- },
- },
separator: {
marginLeft: 8,
marginRight: 8,
@@ -227,298 +208,89 @@ const styles = (theme: Theme) =>
},
},
...spacingUtils,
- });
-
-const inputStyles = makeStyles((theme: Theme) =>
- createStyles({
- root: {
- "& .MuiOutlinedInput-root": {
- paddingLeft: 0,
- "& svg": {
- marginLeft: 4,
- height: 14,
- color: theme.palette.primary.main,
- },
- "& input": {
- padding: 10,
- fontSize: 14,
- paddingLeft: 0,
- "&::placeholder": {
- fontSize: 12,
- },
- "@media (max-width: 900px)": {
- padding: 10,
- },
- },
- "& fieldset": {},
-
- "& fieldset:hover": {
- borderBottom: "2px solid #000000",
- borderRadius: 0,
- },
- },
- },
})
);
-function LoginField(props: TextFieldProps) {
- const classes = inputStyles();
-
- return (
-
- );
-}
-
-// The inferred type will look like:
-// {isOn: boolean, toggleOn: () => void}
-
-interface ILoginProps {
- classes: any;
-}
-
-interface LoginStrategyRoutes {
+export interface LoginStrategyRoutes {
[key: string]: string;
}
-interface LoginStrategyPayload {
+export interface LoginStrategyPayload {
[key: string]: any;
}
-const Login = ({ classes }: ILoginProps) => {
+export const loginStrategyEndpoints: LoginStrategyRoutes = {
+ form: "/api/v1/login",
+ "service-account": "/api/v1/login/operator",
+};
+
+export const getTargetPath = () => {
+ let targetPath = "/";
+ if (
+ localStorage.getItem("redirect-path") &&
+ localStorage.getItem("redirect-path") !== ""
+ ) {
+ targetPath = `${localStorage.getItem("redirect-path")}`;
+ localStorage.setItem("redirect-path", "");
+ }
+ return targetPath;
+};
+
+const Login = () => {
const dispatch = useAppDispatch();
const navigate = useNavigate();
+ const classes = useStyles();
- const [accessKey, setAccessKey] = useState("");
- const [jwt, setJwt] = useState("");
- const [secretKey, setSecretKey] = useState("");
- const [loginStrategy, setLoginStrategy] = useState({
- loginStrategy: loginStrategyType.unknown,
- redirect: "",
- });
- const [loginSending, setLoginSending] = useState(false);
- const [loadingFetchConfiguration, setLoadingFetchConfiguration] =
- useState(true);
+ const jwt = useSelector((state: AppState) => state.login.jwt);
+ const loginStrategy = useSelector(
+ (state: AppState) => state.login.loginStrategy
+ );
+ const loginSending = useSelector(
+ (state: AppState) => state.login.loginSending
+ );
+ const loadingFetchConfiguration = useSelector(
+ (state: AppState) => state.login.loadingFetchConfiguration
+ );
- const [latestMinIOVersion, setLatestMinIOVersion] = useState("");
- const [loadingVersion, setLoadingVersion] = useState(true);
+ const latestMinIOVersion = useSelector(
+ (state: AppState) => state.login.latestMinIOVersion
+ );
+ const loadingVersion = useSelector(
+ (state: AppState) => state.login.loadingVersion
+ );
+ const navigateTo = useSelector((state: AppState) => state.login.navigateTo);
const isOperator =
loginStrategy.loginStrategy === loginStrategyType.serviceAccount ||
loginStrategy.loginStrategy === loginStrategyType.redirectServiceAccount;
- const loginStrategyEndpoints: LoginStrategyRoutes = {
- form: "/api/v1/login",
- "service-account": "/api/v1/login/operator",
- };
- const loginStrategyPayload: LoginStrategyPayload = {
- form: { accessKey, secretKey },
- "service-account": { jwt },
- };
-
- const fetchConfiguration = () => {
- setLoadingFetchConfiguration(true);
- };
-
- const getTargetPath = () => {
- let targetPath = "/";
- if (
- localStorage.getItem("redirect-path") &&
- localStorage.getItem("redirect-path") !== ""
- ) {
- targetPath = `${localStorage.getItem("redirect-path")}`;
- localStorage.setItem("redirect-path", "");
- }
- return targetPath;
- };
-
- const redirectAfterLogin = () => {
- navigate(getTargetPath());
- };
-
- const redirectToMarketplace = () => {
- api
- .invoke("GET", "/api/v1/mp-integration/")
- .then((res: any) => {
- redirectAfterLogin(); // Email already set, continue with normal flow
- })
- .catch((err: ErrorResponseHandler) => {
- if (err.statusCode === 404) {
- dispatch(showMarketplace(true));
- navigate("/marketplace");
- } else {
- // Unexpected error, continue with normal flow
- redirectAfterLogin();
- }
- });
- };
+ if (navigateTo !== "") {
+ navigate(navigateTo);
+ dispatch(resetForm());
+ }
const formSubmit = (e: React.FormEvent) => {
e.preventDefault();
- setLoginSending(true);
- api
- .invoke(
- "POST",
- loginStrategyEndpoints[loginStrategy.loginStrategy] || "/api/v1/login",
- loginStrategyPayload[loginStrategy.loginStrategy]
- )
- .then(() => {
- // We set the state in redux
- dispatch(userLogged(true));
- if (loginStrategy.loginStrategy === loginStrategyType.form) {
- localStorage.setItem("userLoggedIn", accessKey);
- }
- if (isOperator) {
- redirectToMarketplace();
- } else {
- redirectAfterLogin();
- }
- })
- .catch((err) => {
- setLoginSending(false);
- dispatch(setErrorSnackMessage(err));
- });
+ dispatch(doLoginAsync());
};
useEffect(() => {
if (loadingFetchConfiguration) {
- api
- .invoke("GET", "/api/v1/login")
- .then((loginDetails: ILoginDetails) => {
- setLoginStrategy(loginDetails);
- setLoadingFetchConfiguration(false);
- })
- .catch((err: ErrorResponseHandler) => {
- dispatch(setErrorSnackMessage(err));
- setLoadingFetchConfiguration(false);
- });
+ dispatch(getFetchConfigurationAsync());
}
}, [loadingFetchConfiguration, dispatch]);
useEffect(() => {
if (loadingVersion) {
- api
- .invoke("GET", "/api/v1/check-version")
- .then(
- ({
- current_version,
- latest_version,
- }: {
- current_version: string;
- latest_version: string;
- }) => {
- setLatestMinIOVersion(latest_version);
- setLoadingVersion(false);
- }
- )
- .catch((err: ErrorResponseHandler) => {
- // try the operator version
- api
- .invoke("GET", "/api/v1/check-operator-version")
- .then(
- ({
- current_version,
- latest_version,
- }: {
- current_version: string;
- latest_version: string;
- }) => {
- setLatestMinIOVersion(latest_version);
- setLoadingVersion(false);
- }
- )
- .catch((err: ErrorResponseHandler) => {
- setLoadingVersion(false);
- });
- });
+ dispatch(getVersionAsync());
}
- }, [loadingVersion, setLoadingVersion, setLatestMinIOVersion]);
+ }, [dispatch, loadingVersion]);
- let loginComponent = null;
+ let loginComponent;
switch (loginStrategy.loginStrategy) {
case loginStrategyType.form: {
- loginComponent = (
-
-
-
- );
+ loginComponent = ;
break;
}
case loginStrategyType.redirect:
@@ -553,7 +325,7 @@ const Login = ({ classes }: ILoginProps) => {
id="jwt"
value={jwt}
onChange={(e: React.ChangeEvent) =>
- setJwt(e.target.value)
+ dispatch(setJwt(e.target.value))
}
name="jwt"
autoComplete="off"
@@ -607,7 +379,7 @@ const Login = ({ classes }: ILoginProps) => {