Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27fd91ed37 | ||
|
|
7df0560104 | ||
|
|
2368199e03 | ||
|
|
bee98e1ba0 | ||
|
|
8abbbb4625 | ||
|
|
ef182fe75e |
2
.github/workflows/jobs.yaml
vendored
2
.github/workflows/jobs.yaml
vendored
@@ -2517,7 +2517,7 @@ jobs:
|
||||
go tool cover -func=all.out | grep total > tmp2
|
||||
result=`cat tmp2 | awk 'END {print $3}'`
|
||||
result=${result%\%}
|
||||
threshold=53.40
|
||||
threshold=54.40
|
||||
echo "Result:"
|
||||
echo "$result%"
|
||||
if (( $(echo "$result >= $threshold" |bc -l) )); then
|
||||
|
||||
@@ -15,7 +15,7 @@ spec:
|
||||
serviceAccountName: console-sa
|
||||
containers:
|
||||
- name: console
|
||||
image: 'minio/console:v0.22.1'
|
||||
image: 'minio/console:v0.22.2'
|
||||
imagePullPolicy: "IfNotPresent"
|
||||
env:
|
||||
- name: CONSOLE_OPERATOR_MODE
|
||||
|
||||
@@ -32,7 +32,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: console
|
||||
image: 'minio/console:v0.22.1'
|
||||
image: 'minio/console:v0.22.2'
|
||||
imagePullPolicy: "IfNotPresent"
|
||||
env:
|
||||
- name: CONSOLE_MINIO_SERVER
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "./static/css/main.b20a708b.css",
|
||||
"main.js": "./static/js/main.ed30ed16.js",
|
||||
"static/js/1260.4d240571.chunk.js": "./static/js/1260.4d240571.chunk.js",
|
||||
"main.js": "./static/js/main.2b781eaf.js",
|
||||
"static/js/1260.ded6e17b.chunk.js": "./static/js/1260.ded6e17b.chunk.js",
|
||||
"static/js/6914.1699f207.chunk.js": "./static/js/6914.1699f207.chunk.js",
|
||||
"static/js/4209.227aa3b5.chunk.js": "./static/js/4209.227aa3b5.chunk.js",
|
||||
"static/js/1829.be0f91b9.chunk.js": "./static/js/1829.be0f91b9.chunk.js",
|
||||
@@ -40,6 +40,12 @@
|
||||
"static/css/5517.9cb5f34b.chunk.css": "./static/css/5517.9cb5f34b.chunk.css",
|
||||
"static/js/5517.730e0aeb.chunk.js": "./static/js/5517.730e0aeb.chunk.js",
|
||||
"static/js/2555.47860755.chunk.js": "./static/js/2555.47860755.chunk.js",
|
||||
"static/js/7486.83e0d248.chunk.js": "./static/js/7486.83e0d248.chunk.js",
|
||||
"static/js/1377.6fbc40f3.chunk.js": "./static/js/1377.6fbc40f3.chunk.js",
|
||||
"static/js/4672.7e50d90b.chunk.js": "./static/js/4672.7e50d90b.chunk.js",
|
||||
"static/js/2516.5d118ef6.chunk.js": "./static/js/2516.5d118ef6.chunk.js",
|
||||
"static/js/2759.3ab5d8ec.chunk.js": "./static/js/2759.3ab5d8ec.chunk.js",
|
||||
"static/js/7295.c85034bf.chunk.js": "./static/js/7295.c85034bf.chunk.js",
|
||||
"static/js/7585.cd3ad44f.chunk.js": "./static/js/7585.cd3ad44f.chunk.js",
|
||||
"static/js/4902.b5c5ff07.chunk.js": "./static/js/4902.b5c5ff07.chunk.js",
|
||||
"static/js/7847.659fc617.chunk.js": "./static/js/7847.659fc617.chunk.js",
|
||||
@@ -61,9 +67,9 @@
|
||||
"static/js/8833.9dccd2d5.chunk.js": "./static/js/8833.9dccd2d5.chunk.js",
|
||||
"static/js/6526.e3612299.chunk.js": "./static/js/6526.e3612299.chunk.js",
|
||||
"static/js/483.5b997456.chunk.js": "./static/js/483.5b997456.chunk.js",
|
||||
"static/js/9467.5b40a136.chunk.js": "./static/js/9467.5b40a136.chunk.js",
|
||||
"static/js/9467.8e1b707f.chunk.js": "./static/js/9467.8e1b707f.chunk.js",
|
||||
"static/js/6895.488a4025.chunk.js": "./static/js/6895.488a4025.chunk.js",
|
||||
"static/js/5882.277a7242.chunk.js": "./static/js/5882.277a7242.chunk.js",
|
||||
"static/js/5882.41668ace.chunk.js": "./static/js/5882.41668ace.chunk.js",
|
||||
"static/js/8277.e772e8bd.chunk.js": "./static/js/8277.e772e8bd.chunk.js",
|
||||
"static/js/4133.2386eedc.chunk.js": "./static/js/4133.2386eedc.chunk.js",
|
||||
"static/css/1367.9cb5f34b.chunk.css": "./static/css/1367.9cb5f34b.chunk.css",
|
||||
@@ -104,7 +110,7 @@
|
||||
"static/js/9179.73844de6.chunk.js": "./static/js/9179.73844de6.chunk.js",
|
||||
"static/js/51.f63429fd.chunk.js": "./static/js/51.f63429fd.chunk.js",
|
||||
"static/js/711.7013b9d7.chunk.js": "./static/js/711.7013b9d7.chunk.js",
|
||||
"static/js/6901.e2472ebd.chunk.js": "./static/js/6901.e2472ebd.chunk.js",
|
||||
"static/js/6901.cda3f1f9.chunk.js": "./static/js/6901.cda3f1f9.chunk.js",
|
||||
"static/js/2185.4baca582.chunk.js": "./static/js/2185.4baca582.chunk.js",
|
||||
"static/js/312.770148c8.chunk.js": "./static/js/312.770148c8.chunk.js",
|
||||
"static/js/2112.c85537ec.chunk.js": "./static/js/2112.c85537ec.chunk.js",
|
||||
@@ -151,8 +157,10 @@
|
||||
"static/js/9515.a4e964be.chunk.js": "./static/js/9515.a4e964be.chunk.js",
|
||||
"static/js/2983.e248775f.chunk.js": "./static/js/2983.e248775f.chunk.js",
|
||||
"static/js/5861.65847210.chunk.js": "./static/js/5861.65847210.chunk.js",
|
||||
"static/js/537.85347210.chunk.js": "./static/js/537.85347210.chunk.js",
|
||||
"static/js/2763.08c6e1fd.chunk.js": "./static/js/2763.08c6e1fd.chunk.js",
|
||||
"static/media/LoginBG.png": "./static/media/LoginBG.143407455857f28ba809.png",
|
||||
"static/media/videoBG.mp4": "./static/media/videoBG.17363418b3c2246a0e27.mp4",
|
||||
"static/media/loginAnimationPoster.png": "./static/media/loginAnimationPoster.9aa924bfe619e71d5d29.png",
|
||||
"static/media/Inter-BoldItalic.woff": "./static/media/Inter-BoldItalic.b376885042f6c961a541.woff",
|
||||
"static/media/Inter-LightItalic.woff": "./static/media/Inter-LightItalic.ef9f65d91d2b0ba9b2e4.woff",
|
||||
"static/media/Inter-BlackItalic.woff": "./static/media/Inter-BlackItalic.ca1e738e4f349f27514d.woff",
|
||||
@@ -173,8 +181,8 @@
|
||||
"static/media/Inter-Regular.woff2": "./static/media/Inter-Regular.c8ba52b05a9ef10f4758.woff2",
|
||||
"index.html": "./index.html",
|
||||
"main.b20a708b.css.map": "./static/css/main.b20a708b.css.map",
|
||||
"main.ed30ed16.js.map": "./static/js/main.ed30ed16.js.map",
|
||||
"1260.4d240571.chunk.js.map": "./static/js/1260.4d240571.chunk.js.map",
|
||||
"main.2b781eaf.js.map": "./static/js/main.2b781eaf.js.map",
|
||||
"1260.ded6e17b.chunk.js.map": "./static/js/1260.ded6e17b.chunk.js.map",
|
||||
"6914.1699f207.chunk.js.map": "./static/js/6914.1699f207.chunk.js.map",
|
||||
"4209.227aa3b5.chunk.js.map": "./static/js/4209.227aa3b5.chunk.js.map",
|
||||
"1829.be0f91b9.chunk.js.map": "./static/js/1829.be0f91b9.chunk.js.map",
|
||||
@@ -212,6 +220,12 @@
|
||||
"5517.9cb5f34b.chunk.css.map": "./static/css/5517.9cb5f34b.chunk.css.map",
|
||||
"5517.730e0aeb.chunk.js.map": "./static/js/5517.730e0aeb.chunk.js.map",
|
||||
"2555.47860755.chunk.js.map": "./static/js/2555.47860755.chunk.js.map",
|
||||
"7486.83e0d248.chunk.js.map": "./static/js/7486.83e0d248.chunk.js.map",
|
||||
"1377.6fbc40f3.chunk.js.map": "./static/js/1377.6fbc40f3.chunk.js.map",
|
||||
"4672.7e50d90b.chunk.js.map": "./static/js/4672.7e50d90b.chunk.js.map",
|
||||
"2516.5d118ef6.chunk.js.map": "./static/js/2516.5d118ef6.chunk.js.map",
|
||||
"2759.3ab5d8ec.chunk.js.map": "./static/js/2759.3ab5d8ec.chunk.js.map",
|
||||
"7295.c85034bf.chunk.js.map": "./static/js/7295.c85034bf.chunk.js.map",
|
||||
"7585.cd3ad44f.chunk.js.map": "./static/js/7585.cd3ad44f.chunk.js.map",
|
||||
"4902.b5c5ff07.chunk.js.map": "./static/js/4902.b5c5ff07.chunk.js.map",
|
||||
"7847.659fc617.chunk.js.map": "./static/js/7847.659fc617.chunk.js.map",
|
||||
@@ -233,9 +247,9 @@
|
||||
"8833.9dccd2d5.chunk.js.map": "./static/js/8833.9dccd2d5.chunk.js.map",
|
||||
"6526.e3612299.chunk.js.map": "./static/js/6526.e3612299.chunk.js.map",
|
||||
"483.5b997456.chunk.js.map": "./static/js/483.5b997456.chunk.js.map",
|
||||
"9467.5b40a136.chunk.js.map": "./static/js/9467.5b40a136.chunk.js.map",
|
||||
"9467.8e1b707f.chunk.js.map": "./static/js/9467.8e1b707f.chunk.js.map",
|
||||
"6895.488a4025.chunk.js.map": "./static/js/6895.488a4025.chunk.js.map",
|
||||
"5882.277a7242.chunk.js.map": "./static/js/5882.277a7242.chunk.js.map",
|
||||
"5882.41668ace.chunk.js.map": "./static/js/5882.41668ace.chunk.js.map",
|
||||
"8277.e772e8bd.chunk.js.map": "./static/js/8277.e772e8bd.chunk.js.map",
|
||||
"4133.2386eedc.chunk.js.map": "./static/js/4133.2386eedc.chunk.js.map",
|
||||
"1367.9cb5f34b.chunk.css.map": "./static/css/1367.9cb5f34b.chunk.css.map",
|
||||
@@ -276,7 +290,7 @@
|
||||
"9179.73844de6.chunk.js.map": "./static/js/9179.73844de6.chunk.js.map",
|
||||
"51.f63429fd.chunk.js.map": "./static/js/51.f63429fd.chunk.js.map",
|
||||
"711.7013b9d7.chunk.js.map": "./static/js/711.7013b9d7.chunk.js.map",
|
||||
"6901.e2472ebd.chunk.js.map": "./static/js/6901.e2472ebd.chunk.js.map",
|
||||
"6901.cda3f1f9.chunk.js.map": "./static/js/6901.cda3f1f9.chunk.js.map",
|
||||
"2185.4baca582.chunk.js.map": "./static/js/2185.4baca582.chunk.js.map",
|
||||
"312.770148c8.chunk.js.map": "./static/js/312.770148c8.chunk.js.map",
|
||||
"2112.c85537ec.chunk.js.map": "./static/js/2112.c85537ec.chunk.js.map",
|
||||
@@ -323,10 +337,11 @@
|
||||
"9515.a4e964be.chunk.js.map": "./static/js/9515.a4e964be.chunk.js.map",
|
||||
"2983.e248775f.chunk.js.map": "./static/js/2983.e248775f.chunk.js.map",
|
||||
"5861.65847210.chunk.js.map": "./static/js/5861.65847210.chunk.js.map",
|
||||
"537.85347210.chunk.js.map": "./static/js/537.85347210.chunk.js.map",
|
||||
"2763.08c6e1fd.chunk.js.map": "./static/js/2763.08c6e1fd.chunk.js.map"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.b20a708b.css",
|
||||
"static/js/main.ed30ed16.js"
|
||||
"static/js/main.2b781eaf.js"
|
||||
]
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><base href="/"/><meta content="width=device-width,initial-scale=1" name="viewport"/><meta content="#081C42" media="(prefers-color-scheme: light)" name="theme-color"/><meta content="#081C42" media="(prefers-color-scheme: dark)" name="theme-color"/><meta content="MinIO Console" name="description"/><link href="./styles/root-styles.css" rel="stylesheet"/><link href="./apple-icon-180x180.png" rel="apple-touch-icon" sizes="180x180"/><link href="./favicon-32x32.png" rel="icon" sizes="32x32" type="image/png"/><link href="./favicon-96x96.png" rel="icon" sizes="96x96" type="image/png"/><link href="./favicon-16x16.png" rel="icon" sizes="16x16" type="image/png"/><link href="./manifest.json" rel="manifest"/><link color="#3a4e54" href="./safari-pinned-tab.svg" rel="mask-icon"/><title>MinIO Console</title><script defer="defer" src="./static/js/main.ed30ed16.js"></script><link href="./static/css/main.b20a708b.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"><div id="preload"><img src="./images/background.svg"/> <img src="./images/background-wave-orig2.svg"/></div><div id="loader-block"><img src="./Loader.svg"/></div></div></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><base href="/"/><meta content="width=device-width,initial-scale=1" name="viewport"/><meta content="#081C42" media="(prefers-color-scheme: light)" name="theme-color"/><meta content="#081C42" media="(prefers-color-scheme: dark)" name="theme-color"/><meta content="MinIO Console" name="description"/><link href="./styles/root-styles.css" rel="stylesheet"/><link href="./apple-icon-180x180.png" rel="apple-touch-icon" sizes="180x180"/><link href="./favicon-32x32.png" rel="icon" sizes="32x32" type="image/png"/><link href="./favicon-96x96.png" rel="icon" sizes="96x96" type="image/png"/><link href="./favicon-16x16.png" rel="icon" sizes="16x16" type="image/png"/><link href="./manifest.json" rel="manifest"/><link color="#3a4e54" href="./safari-pinned-tab.svg" rel="mask-icon"/><title>MinIO Console</title><script defer="defer" src="./static/js/main.2b781eaf.js"></script><link href="./static/css/main.b20a708b.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"><div id="preload"><img src="./images/background.svg"/> <img src="./images/background-wave-orig2.svg"/></div><div id="loader-block"><img src="./Loader.svg"/></div></div></body></html>
|
||||
@@ -1,2 +0,0 @@
|
||||
"use strict";(self.webpackChunkportal_ui=self.webpackChunkportal_ui||[]).push([[1260],{1260:function(t,e,o){o.r(e);o(72791);var a=o(16871),n=o(25469),r=o(45248),u=o(81207),c=o(87995),l=o(46078),i=o(80184);e.default=function(){var t=(0,n.TL)(),e=(0,a.s0)();return function(){var o=function(){(0,r.Ov)(),t((0,c.wr)(!1)),localStorage.setItem("userLoggedIn",""),localStorage.setItem("redirect-path",""),t((0,l.lX)()),e("login")},a=localStorage.getItem("auth-state");u.Z.invoke("POST","/api/v1/logout",{state:a}).then((function(){o()})).catch((function(t){console.log(t),o()}))}(),(0,i.jsx)(i.Fragment,{})}}}]);
|
||||
//# sourceMappingURL=1260.4d240571.chunk.js.map
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"static/js/1260.4d240571.chunk.js","mappings":"6MAoDA,UA3BmB,WACjB,IAAMA,GAAWC,EAAAA,EAAAA,MACXC,GAAWC,EAAAA,EAAAA,MAsBjB,OArBe,WACb,IAAMC,EAAgB,YACpBC,EAAAA,EAAAA,MACAL,GAASM,EAAAA,EAAAA,KAAW,IACpBC,aAAaC,QAAQ,eAAgB,IACrCD,aAAaC,QAAQ,gBAAiB,IACtCR,GAASS,EAAAA,EAAAA,OACTP,EAAS,QACV,EACKQ,EAAQH,aAAaI,QAAQ,cACnCC,EAAAA,EAAAA,OACU,OADV,iBACoC,CAAEF,MAAAA,IACnCG,MAAK,WACJT,GACD,IACAU,OAAM,SAACC,GACNC,QAAQC,IAAIF,GACZX,GACD,GACJ,CACDc,IACO,uBACR,C","sources":["screens/LogoutPage/LogoutPage.tsx"],"sourcesContent":["// This file is part of MinIO Console Server\n// Copyright (c) 2022 MinIO, Inc.\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <http://www.gnu.org/licenses/>.\n\nimport React from \"react\";\nimport { useNavigate } from \"react-router-dom\";\nimport { useAppDispatch } from \"../../store\";\nimport { ErrorResponseHandler } from \"../../common/types\";\nimport { clearSession } from \"../../common/utils\";\nimport api from \"../../common/api\";\nimport { userLogged } from \"../../systemSlice\";\nimport { resetSession } from \"../Console/consoleSlice\";\n\nconst LogoutPage = () => {\n const dispatch = useAppDispatch();\n const navigate = useNavigate();\n const logout = () => {\n const deleteSession = () => {\n clearSession();\n dispatch(userLogged(false));\n localStorage.setItem(\"userLoggedIn\", \"\");\n localStorage.setItem(\"redirect-path\", \"\");\n dispatch(resetSession());\n navigate(`login`);\n };\n const state = localStorage.getItem(\"auth-state\");\n api\n .invoke(\"POST\", `/api/v1/logout`, { state })\n .then(() => {\n deleteSession();\n })\n .catch((err: ErrorResponseHandler) => {\n console.log(err);\n deleteSession();\n });\n };\n logout();\n return <></>;\n};\n\nexport default LogoutPage;\n"],"names":["dispatch","useAppDispatch","navigate","useNavigate","deleteSession","clearSession","userLogged","localStorage","setItem","resetSession","state","getItem","api","then","catch","err","console","log","logout"],"sourceRoot":""}
|
||||
2
portal-ui/build/static/js/1260.ded6e17b.chunk.js
Normal file
2
portal-ui/build/static/js/1260.ded6e17b.chunk.js
Normal file
@@ -0,0 +1,2 @@
|
||||
"use strict";(self.webpackChunkportal_ui=self.webpackChunkportal_ui||[]).push([[1260],{1260:function(t,e,o){o.r(e);o(72791);var a=o(16871),n=o(25469),u=o(45248),c=o(87995),l=o(46078),r=o(81207),i=o(7241),s=o(80184);e.default=function(){var t=(0,n.TL)(),e=(0,a.s0)();return function(){var o=function(){(0,u.Ov)(),t((0,c.wr)(!1)),localStorage.setItem("userLoggedIn",""),localStorage.setItem("redirect-path",""),t((0,l.lX)()),e("/login")},a=localStorage.getItem("auth-state");r.Z.invoke("POST","/api/v1/logout",{state:a}).then((function(){o()})).catch((function(t){console.log(t),o()}))}(),(0,s.jsx)(i.Z,{})}}}]);
|
||||
//# sourceMappingURL=1260.ded6e17b.chunk.js.map
|
||||
1
portal-ui/build/static/js/1260.ded6e17b.chunk.js.map
Normal file
1
portal-ui/build/static/js/1260.ded6e17b.chunk.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"static/js/1260.ded6e17b.chunk.js","mappings":"uNAqDA,UA3BmB,WACjB,IAAMA,GAAWC,EAAAA,EAAAA,MACXC,GAAWC,EAAAA,EAAAA,MAsBjB,OArBe,WACb,IAAMC,EAAgB,YACpBC,EAAAA,EAAAA,MACAL,GAASM,EAAAA,EAAAA,KAAW,IACpBC,aAAaC,QAAQ,eAAgB,IACrCD,aAAaC,QAAQ,gBAAiB,IACtCR,GAASS,EAAAA,EAAAA,OACTP,EAAS,SACV,EACKQ,EAAQH,aAAaI,QAAQ,cACnCC,EAAAA,EAAAA,OACU,OADV,iBACoC,CAAEF,MAAAA,IACnCG,MAAK,WACJT,GACD,IACAU,OAAM,SAACC,GACNC,QAAQC,IAAIF,GACZX,GACD,GACJ,CACDc,IACO,SAAC,IAAD,GACR,C","sources":["screens/LogoutPage/LogoutPage.tsx"],"sourcesContent":["// This file is part of MinIO Console Server\n// Copyright (c) 2022 MinIO, Inc.\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <http://www.gnu.org/licenses/>.\n\nimport React from \"react\";\nimport { useNavigate } from \"react-router-dom\";\nimport { useAppDispatch } from \"../../store\";\nimport { ErrorResponseHandler } from \"../../common/types\";\nimport { clearSession } from \"../../common/utils\";\nimport { userLogged } from \"../../systemSlice\";\nimport { resetSession } from \"../Console/consoleSlice\";\nimport api from \"../../common/api\";\nimport LoadingComponent from \"../../common/LoadingComponent\";\n\nconst LogoutPage = () => {\n const dispatch = useAppDispatch();\n const navigate = useNavigate();\n const logout = () => {\n const deleteSession = () => {\n clearSession();\n dispatch(userLogged(false));\n localStorage.setItem(\"userLoggedIn\", \"\");\n localStorage.setItem(\"redirect-path\", \"\");\n dispatch(resetSession());\n navigate(`/login`);\n };\n const state = localStorage.getItem(\"auth-state\");\n api\n .invoke(\"POST\", `/api/v1/logout`, { state })\n .then(() => {\n deleteSession();\n })\n .catch((err: ErrorResponseHandler) => {\n console.log(err);\n deleteSession();\n });\n };\n logout();\n return <LoadingComponent />;\n};\n\nexport default LogoutPage;\n"],"names":["dispatch","useAppDispatch","navigate","useNavigate","deleteSession","clearSession","userLogged","localStorage","setItem","resetSession","state","getItem","api","then","catch","err","console","log","logout"],"sourceRoot":""}
|
||||
2
portal-ui/build/static/js/1377.6fbc40f3.chunk.js
Normal file
2
portal-ui/build/static/js/1377.6fbc40f3.chunk.js
Normal file
@@ -0,0 +1,2 @@
|
||||
"use strict";(self.webpackChunkportal_ui=self.webpackChunkportal_ui||[]).push([[1377],{81377:function(u,e,n){n.r(e);n(72791);var t=n(11135),r=n(25787),s=n(44959),i=n(80184);e.default=(0,r.Z)((function(u){return(0,t.Z)({})}))((function(u){u.classes;return(0,i.jsx)(s.Z,{idpType:"openid"})}))}}]);
|
||||
//# sourceMappingURL=1377.6fbc40f3.chunk.js.map
|
||||
1
portal-ui/build/static/js/1377.6fbc40f3.chunk.js.map
Normal file
1
portal-ui/build/static/js/1377.6fbc40f3.chunk.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"static/js/1377.6fbc40f3.chunk.js","mappings":"6KAiCA,WAAeA,EAAAA,EAAAA,IANA,SAACC,GAAD,OAAkBC,EAAAA,EAAAA,GAAa,CAAC,EAAhC,GAMf,EAJgC,SAAC,GAA8C,EAA5CC,QACjC,OAAO,SAAC,IAAD,CAAmBC,QAAS,UACpC,G","sources":["screens/Console/IDP/IDPOpenIDConfigurations.tsx"],"sourcesContent":["// This file is part of MinIO Console Server\n// Copyright (c) 2022 MinIO, Inc.\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <http://www.gnu.org/licenses/>.\n\nimport React from \"react\";\n\nimport { Theme } from \"@mui/material/styles\";\nimport createStyles from \"@mui/styles/createStyles\";\nimport withStyles from \"@mui/styles/withStyles\";\nimport IDPConfigurations from \"./IDPConfigurations\";\n\ntype IDPOpenIDConfigurationsProps = {\n classes?: any;\n};\n\nconst styles = (theme: Theme) => createStyles({});\n\nconst IDPOpenIDConfigurations = ({ classes }: IDPOpenIDConfigurationsProps) => {\n return <IDPConfigurations idpType={\"openid\"} />;\n};\n\nexport default withStyles(styles)(IDPOpenIDConfigurations);\n"],"names":["withStyles","theme","createStyles","classes","idpType"],"sourceRoot":""}
|
||||
2
portal-ui/build/static/js/2516.5d118ef6.chunk.js
Normal file
2
portal-ui/build/static/js/2516.5d118ef6.chunk.js
Normal file
File diff suppressed because one or more lines are too long
1
portal-ui/build/static/js/2516.5d118ef6.chunk.js.map
Normal file
1
portal-ui/build/static/js/2516.5d118ef6.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
2
portal-ui/build/static/js/2759.3ab5d8ec.chunk.js
Normal file
2
portal-ui/build/static/js/2759.3ab5d8ec.chunk.js
Normal file
File diff suppressed because one or more lines are too long
1
portal-ui/build/static/js/2759.3ab5d8ec.chunk.js.map
Normal file
1
portal-ui/build/static/js/2759.3ab5d8ec.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
2
portal-ui/build/static/js/4672.7e50d90b.chunk.js
Normal file
2
portal-ui/build/static/js/4672.7e50d90b.chunk.js
Normal file
File diff suppressed because one or more lines are too long
1
portal-ui/build/static/js/4672.7e50d90b.chunk.js.map
Normal file
1
portal-ui/build/static/js/4672.7e50d90b.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
2
portal-ui/build/static/js/537.85347210.chunk.js
Normal file
2
portal-ui/build/static/js/537.85347210.chunk.js
Normal file
File diff suppressed because one or more lines are too long
1
portal-ui/build/static/js/537.85347210.chunk.js.map
Normal file
1
portal-ui/build/static/js/537.85347210.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
portal-ui/build/static/js/5882.41668ace.chunk.js.map
Normal file
1
portal-ui/build/static/js/5882.41668ace.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
portal-ui/build/static/js/6901.cda3f1f9.chunk.js.map
Normal file
1
portal-ui/build/static/js/6901.cda3f1f9.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
portal-ui/build/static/js/7295.c85034bf.chunk.js
Normal file
2
portal-ui/build/static/js/7295.c85034bf.chunk.js
Normal file
File diff suppressed because one or more lines are too long
1
portal-ui/build/static/js/7295.c85034bf.chunk.js.map
Normal file
1
portal-ui/build/static/js/7295.c85034bf.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
2
portal-ui/build/static/js/7486.83e0d248.chunk.js
Normal file
2
portal-ui/build/static/js/7486.83e0d248.chunk.js
Normal file
@@ -0,0 +1,2 @@
|
||||
"use strict";(self.webpackChunkportal_ui=self.webpackChunkportal_ui||[]).push([[7486],{17486:function(u,e,n){n.r(e);n(72791);var t=n(11135),r=n(25787),s=n(44959),a=n(80184);e.default=(0,r.Z)((function(u){return(0,t.Z)({})}))((function(u){u.classes;return(0,a.jsx)(s.Z,{idpType:"ldap"})}))}}]);
|
||||
//# sourceMappingURL=7486.83e0d248.chunk.js.map
|
||||
1
portal-ui/build/static/js/7486.83e0d248.chunk.js.map
Normal file
1
portal-ui/build/static/js/7486.83e0d248.chunk.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"static/js/7486.83e0d248.chunk.js","mappings":"6KAiCA,WAAeA,EAAAA,EAAAA,IANA,SAACC,GAAD,OAAkBC,EAAAA,EAAAA,GAAa,CAAC,EAAhC,GAMf,EAJ8B,SAAC,GAA4C,EAA1CC,QAC/B,OAAO,SAAC,IAAD,CAAmBC,QAAS,QACpC,G","sources":["screens/Console/IDP/IDPLDAPConfigurations.tsx"],"sourcesContent":["// This file is part of MinIO Console Server\n// Copyright (c) 2022 MinIO, Inc.\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <http://www.gnu.org/licenses/>.\n\nimport React from \"react\";\n\nimport { Theme } from \"@mui/material/styles\";\nimport createStyles from \"@mui/styles/createStyles\";\nimport withStyles from \"@mui/styles/withStyles\";\nimport IDPConfigurations from \"./IDPConfigurations\";\n\ntype IDPLDAPConfigurationsProps = {\n classes?: any;\n};\n\nconst styles = (theme: Theme) => createStyles({});\n\nconst IDPLDAPConfigurations = ({ classes }: IDPLDAPConfigurationsProps) => {\n return <IDPConfigurations idpType={\"ldap\"} />;\n};\n\nexport default withStyles(styles)(IDPLDAPConfigurations);\n"],"names":["withStyles","theme","createStyles","classes","idpType"],"sourceRoot":""}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
3
portal-ui/build/static/js/main.2b781eaf.js
Normal file
3
portal-ui/build/static/js/main.2b781eaf.js
Normal file
File diff suppressed because one or more lines are too long
1
portal-ui/build/static/js/main.2b781eaf.js.map
Normal file
1
portal-ui/build/static/js/main.2b781eaf.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 2.0 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 318 KiB |
BIN
portal-ui/build/static/media/videoBG.17363418b3c2246a0e27.mp4
Normal file
BIN
portal-ui/build/static/media/videoBG.17363418b3c2246a0e27.mp4
Normal file
Binary file not shown.
@@ -30,7 +30,7 @@
|
||||
"kbar": "^0.1.0-beta.34",
|
||||
"local-storage-fallback": "^4.1.1",
|
||||
"lodash": "^4.17.21",
|
||||
"mds": "https://github.com/minio/mds.git#v0.0.5",
|
||||
"mds": "https://github.com/minio/mds.git#v0.0.7",
|
||||
"minio": "^7.0.28",
|
||||
"moment": "^2.29.4",
|
||||
"react": "^18.1.0",
|
||||
|
||||
@@ -39,7 +39,14 @@ const MainRouter = () => {
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
<Route path="/logout" element={<Logout />} />
|
||||
<Route
|
||||
path="/logout"
|
||||
element={
|
||||
<Suspense fallback={<LoadingComponent />}>
|
||||
<Logout />
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/login"
|
||||
element={
|
||||
|
||||
@@ -35,6 +35,7 @@ import { SRInfoStateType } from "./types";
|
||||
import { AppState, useAppDispatch } from "./store";
|
||||
import { saveSessionResponse } from "./screens/Console/consoleSlice";
|
||||
import { getOverrideColorVariants } from "./utils/stylesUtils";
|
||||
import LoadingComponent from "./common/LoadingComponent";
|
||||
|
||||
interface ProtectedRouteProps {
|
||||
Component: any;
|
||||
@@ -119,7 +120,7 @@ const ProtectedRoute = ({ Component }: ProtectedRouteProps) => {
|
||||
|
||||
// if we're still trying to retrieve user session render nothing
|
||||
if (sessionLoading) {
|
||||
return null;
|
||||
return <LoadingComponent />;
|
||||
}
|
||||
// redirect user to the right page based on session status
|
||||
return userLoggedIn ? <Component /> : <StorePathAndRedirect />;
|
||||
|
||||
@@ -30,8 +30,6 @@ const LoadingComponent = () => {
|
||||
>
|
||||
<Grid item xs={3} style={{ textAlign: "center" }}>
|
||||
<Loader style={{ width: 35, height: 35 }} />
|
||||
<br />
|
||||
Loading...
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
|
||||
@@ -130,6 +130,15 @@ export const IAM_PAGES = {
|
||||
ACCOUNT_ADD: "/access-keys/new-account",
|
||||
USER_SA_ACCOUNT_ADD: "/identity/users/new-user-sa/:userName",
|
||||
|
||||
/* IDP */
|
||||
IDP_LDAP_CONFIGURATIONS: "/idp/ldap/configurations",
|
||||
IDP_LDAP_CONFIGURATIONS_VIEW: "/idp/ldap/configurations/:idpName",
|
||||
IDP_LDAP_CONFIGURATIONS_ADD: "/idp/ldap/configurations/add-idp",
|
||||
|
||||
IDP_OPENID_CONFIGURATIONS: "/idp/openid/configurations",
|
||||
IDP_OPENID_CONFIGURATIONS_VIEW: "/idp/openid/configurations/:idpName",
|
||||
IDP_OPENID_CONFIGURATIONS_ADD: "/idp/openid/configurations/add-idp",
|
||||
|
||||
POLICIES: "/identity/policies",
|
||||
POLICY_ADD: "/identity/add-policy",
|
||||
POLICIES_VIEW: "/identity/policies/*",
|
||||
@@ -430,6 +439,30 @@ export const IAM_PAGES_PERMISSIONS = {
|
||||
IAM_SCOPES.ADMIN_SERVER_INFO,
|
||||
IAM_SCOPES.ADMIN_CONFIG_UPDATE,
|
||||
],
|
||||
[IAM_PAGES.IDP_LDAP_CONFIGURATIONS]: [
|
||||
IAM_SCOPES.ADMIN_ALL_ACTIONS,
|
||||
IAM_SCOPES.ADMIN_CONFIG_UPDATE,
|
||||
],
|
||||
[IAM_PAGES.IDP_LDAP_CONFIGURATIONS_ADD]: [
|
||||
IAM_SCOPES.ADMIN_ALL_ACTIONS,
|
||||
IAM_SCOPES.ADMIN_CONFIG_UPDATE,
|
||||
],
|
||||
[IAM_PAGES.IDP_LDAP_CONFIGURATIONS_VIEW]: [
|
||||
IAM_SCOPES.ADMIN_ALL_ACTIONS,
|
||||
IAM_SCOPES.ADMIN_CONFIG_UPDATE,
|
||||
],
|
||||
[IAM_PAGES.IDP_OPENID_CONFIGURATIONS]: [
|
||||
IAM_SCOPES.ADMIN_ALL_ACTIONS,
|
||||
IAM_SCOPES.ADMIN_CONFIG_UPDATE,
|
||||
],
|
||||
[IAM_PAGES.IDP_OPENID_CONFIGURATIONS_ADD]: [
|
||||
IAM_SCOPES.ADMIN_ALL_ACTIONS,
|
||||
IAM_SCOPES.ADMIN_CONFIG_UPDATE,
|
||||
],
|
||||
[IAM_PAGES.IDP_OPENID_CONFIGURATIONS_VIEW]: [
|
||||
IAM_SCOPES.ADMIN_ALL_ACTIONS,
|
||||
IAM_SCOPES.ADMIN_CONFIG_UPDATE,
|
||||
],
|
||||
};
|
||||
|
||||
export const S3_ALL_RESOURCES = "arn:aws:s3:::*";
|
||||
|
||||
@@ -42,7 +42,7 @@ import {
|
||||
setIsVersioned,
|
||||
setLoadingLocking,
|
||||
setLoadingObjectInfo,
|
||||
setLoadingObjectsList,
|
||||
setLoadingObjects,
|
||||
setLoadingRecords,
|
||||
setLoadingVersioning,
|
||||
setLoadingVersions,
|
||||
@@ -82,12 +82,16 @@ const styles = (theme: Theme) =>
|
||||
let objectsWS: WebSocket;
|
||||
let currentRequestID: number = 0;
|
||||
let errorCounter: number = 0;
|
||||
let wsInFlight: boolean = false;
|
||||
|
||||
const initWSConnection = (
|
||||
onMessageCallback: (message: IMessageEvent) => void,
|
||||
openCallback?: () => void,
|
||||
notAvailableCallback?: () => void
|
||||
onMessageCallback?: (message: IMessageEvent) => void
|
||||
) => {
|
||||
if (wsInFlight) {
|
||||
return;
|
||||
}
|
||||
wsInFlight = true;
|
||||
const url = new URL(window.location.toString());
|
||||
const isDev = process.env.NODE_ENV === "development";
|
||||
const port = isDev ? "9090" : url.port;
|
||||
@@ -103,25 +107,28 @@ const initWSConnection = (
|
||||
);
|
||||
|
||||
objectsWS.onopen = () => {
|
||||
wsInFlight = false;
|
||||
if (openCallback) {
|
||||
openCallback();
|
||||
}
|
||||
errorCounter = 0;
|
||||
};
|
||||
|
||||
if (onMessageCallback) {
|
||||
objectsWS.onmessage = onMessageCallback;
|
||||
}
|
||||
|
||||
const reconnectFn = () => {
|
||||
if (errorCounter <= 5) {
|
||||
initWSConnection(onMessageCallback, openCallback);
|
||||
initWSConnection(openCallback, onMessageCallback);
|
||||
errorCounter += 1;
|
||||
} else {
|
||||
console.error("Websocket not available.");
|
||||
if (notAvailableCallback) {
|
||||
notAvailableCallback();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
objectsWS.onclose = () => {
|
||||
wsInFlight = false;
|
||||
console.warn("Websocket Disconnected. Attempting Reconnection...");
|
||||
|
||||
// We reconnect after 3 seconds
|
||||
@@ -129,6 +136,7 @@ const initWSConnection = (
|
||||
};
|
||||
|
||||
objectsWS.onerror = () => {
|
||||
wsInFlight = false;
|
||||
console.error("Error in websocket connection. Attempting reconnection...");
|
||||
|
||||
// We reconnect after 3 seconds
|
||||
@@ -136,8 +144,6 @@ const initWSConnection = (
|
||||
};
|
||||
};
|
||||
|
||||
initWSConnection(() => {});
|
||||
|
||||
const BrowserHandler = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const navigate = useNavigate();
|
||||
@@ -201,10 +207,10 @@ const BrowserHandler = () => {
|
||||
const obOnly = !!features?.includes("object-browser-only");
|
||||
|
||||
/*WS Request Handlers*/
|
||||
objectsWS.onmessage = useCallback(
|
||||
const onMessageCallBack = useCallback(
|
||||
(message: IMessageEvent) => {
|
||||
// reset start status
|
||||
dispatch(setLoadingObjectsList(false));
|
||||
dispatch(setLoadingObjects(false));
|
||||
|
||||
const response: WebsocketResponse = JSON.parse(message.data.toString());
|
||||
if (currentRequestID === response.request_id) {
|
||||
@@ -250,7 +256,7 @@ const BrowserHandler = () => {
|
||||
|
||||
// This indicates final messages is received.
|
||||
if (response.request_end) {
|
||||
dispatch(setLoadingObjectsList(false));
|
||||
dispatch(setLoadingObjects(false));
|
||||
dispatch(setLoadingRecords(false));
|
||||
return;
|
||||
}
|
||||
@@ -283,7 +289,7 @@ const BrowserHandler = () => {
|
||||
// We store the new ID for the requestID
|
||||
currentRequestID = newRequestID;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
console.error(e);
|
||||
}
|
||||
} else {
|
||||
// Socket is disconnected, we request reconnection but will need to recreate call
|
||||
@@ -291,10 +297,10 @@ const BrowserHandler = () => {
|
||||
initWSRequest(path, date);
|
||||
};
|
||||
|
||||
initWSConnection(dupRequest);
|
||||
initWSConnection(dupRequest, onMessageCallBack);
|
||||
}
|
||||
},
|
||||
[bucketName, rewindEnabled, showDeleted, dispatch]
|
||||
[bucketName, rewindEnabled, showDeleted, dispatch, onMessageCallBack]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -394,7 +400,7 @@ const BrowserHandler = () => {
|
||||
|
||||
initWSRequest(pathPrefix, requestDate);
|
||||
} else {
|
||||
dispatch(setLoadingObjectsList(false));
|
||||
dispatch(setLoadingObjects(false));
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [
|
||||
|
||||
@@ -64,7 +64,7 @@ import { selFeatures } from "../../consoleSlice";
|
||||
import AutoColorIcon from "../../Common/Components/AutoColorIcon";
|
||||
import TooltipWrapper from "../../Common/TooltipWrapper/TooltipWrapper";
|
||||
import AButton from "../../Common/AButton/AButton";
|
||||
import { setLoadingObjectsList } from "../../ObjectBrowser/objectBrowserSlice";
|
||||
import { setLoadingObjects } from "../../ObjectBrowser/objectBrowserSlice";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -124,7 +124,7 @@ const ListBuckets = ({ classes }: IListBucketsProps) => {
|
||||
.then((res: BucketList) => {
|
||||
setLoading(false);
|
||||
setRecords(res.buckets || []);
|
||||
dispatch(setLoadingObjectsList(true));
|
||||
dispatch(setLoadingObjects(true));
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
setLoading(false);
|
||||
|
||||
@@ -96,7 +96,7 @@ import {
|
||||
resetMessages,
|
||||
resetRewind,
|
||||
setDownloadRenameModal,
|
||||
setLoadingObjectsList,
|
||||
setLoadingObjects,
|
||||
setLoadingRecords,
|
||||
setLoadingVersions,
|
||||
setNewObject,
|
||||
@@ -317,7 +317,7 @@ const ListObjects = () => {
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(setSearchObjects(""));
|
||||
dispatch(setLoadingObjectsList(true));
|
||||
dispatch(setLoadingObjects(true));
|
||||
dispatch(setSelectedObjects([]));
|
||||
}, [simplePath, dispatch]);
|
||||
|
||||
@@ -424,7 +424,7 @@ const ListObjects = () => {
|
||||
if (refresh) {
|
||||
dispatch(setSnackBarMessage(`Objects deleted successfully.`));
|
||||
dispatch(setSelectedObjects([]));
|
||||
dispatch(setLoadingObjectsList(true));
|
||||
dispatch(setLoadingObjects(true));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -595,7 +595,7 @@ const ListObjects = () => {
|
||||
};
|
||||
xhr.onloadend = () => {
|
||||
if (files.length === 0) {
|
||||
dispatch(setLoadingObjectsList(true));
|
||||
dispatch(setLoadingObjects(true));
|
||||
}
|
||||
};
|
||||
xhr.onabort = () => {
|
||||
@@ -650,7 +650,7 @@ const ListObjects = () => {
|
||||
dispatch(setErrorSnackMessage(err));
|
||||
}
|
||||
// We force objects list reload after all promises were handled
|
||||
dispatch(setLoadingObjectsList(true));
|
||||
dispatch(setLoadingObjects(true));
|
||||
dispatch(setSelectedObjects([]));
|
||||
});
|
||||
};
|
||||
@@ -736,7 +736,7 @@ const ListObjects = () => {
|
||||
dispatch(setSelectedObjects([]));
|
||||
|
||||
if (forceRefresh) {
|
||||
dispatch(setLoadingObjectsList(true));
|
||||
dispatch(setLoadingObjects(true));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -949,7 +949,7 @@ const ListObjects = () => {
|
||||
} else {
|
||||
dispatch(resetMessages());
|
||||
dispatch(setLoadingRecords(true));
|
||||
dispatch(setLoadingObjectsList(true));
|
||||
dispatch(setLoadingObjects(true));
|
||||
}
|
||||
}}
|
||||
disabled={
|
||||
|
||||
@@ -27,7 +27,7 @@ import { AppState, useAppDispatch } from "../../../../../../store";
|
||||
import { selFeatures } from "../../../../consoleSlice";
|
||||
import { encodeURLString } from "../../../../../../common/utils";
|
||||
import {
|
||||
setLoadingObjectsList,
|
||||
setLoadingObjects,
|
||||
setLoadingVersions,
|
||||
setObjectDetailsView,
|
||||
setSelectedObjects,
|
||||
@@ -168,7 +168,7 @@ const ListObjectsTable = () => {
|
||||
const newSortDirection = get(sortData, "sortDirection", "DESC");
|
||||
setCurrentSortField(sortData.sortBy);
|
||||
setSortDirection(newSortDirection);
|
||||
dispatch(setLoadingObjectsList(true));
|
||||
dispatch(setLoadingObjects(true));
|
||||
};
|
||||
|
||||
const selectAllItems = () => {
|
||||
|
||||
@@ -25,7 +25,7 @@ import FormSwitchWrapper from "../../../../Common/FormComponents/FormSwitchWrapp
|
||||
import { AppState, useAppDispatch } from "../../../../../../store";
|
||||
import {
|
||||
resetRewind,
|
||||
setLoadingObjectsList,
|
||||
setLoadingObjects,
|
||||
setRewindEnable,
|
||||
} from "../../../../ObjectBrowser/objectBrowserSlice";
|
||||
|
||||
@@ -73,7 +73,7 @@ const RewindEnable = ({
|
||||
})
|
||||
);
|
||||
}
|
||||
dispatch(setLoadingObjectsList(true));
|
||||
dispatch(setLoadingObjects(true));
|
||||
|
||||
closeModalAndRefresh();
|
||||
};
|
||||
|
||||
@@ -122,6 +122,24 @@ const AccountCreate = React.lazy(
|
||||
|
||||
const Users = React.lazy(() => import("./Users/Users"));
|
||||
const Groups = React.lazy(() => import("./Groups/Groups"));
|
||||
const IDPLDAPConfigurations = React.lazy(
|
||||
() => import("./IDP/IDPLDAPConfigurations")
|
||||
);
|
||||
const IDPOpenIDConfigurations = React.lazy(
|
||||
() => import("./IDP/IDPOpenIDConfigurations")
|
||||
);
|
||||
const AddIDPLDAPConfiguration = React.lazy(
|
||||
() => import("./IDP/AddIDPLDAPConfiguration")
|
||||
);
|
||||
const AddIDPOpenIDConfiguration = React.lazy(
|
||||
() => import("./IDP/AddIDPOpenIDConfiguration")
|
||||
);
|
||||
const IDPLDAPConfigurationDetails = React.lazy(
|
||||
() => import("./IDP/IDPLDAPConfigurationDetails")
|
||||
);
|
||||
const IDPOpenIDConfigurationDetails = React.lazy(
|
||||
() => import("./IDP/IDPOpenIDConfigurationDetails")
|
||||
);
|
||||
|
||||
const TenantDetails = React.lazy(
|
||||
() => import("./Tenants/TenantDetails/TenantDetails")
|
||||
@@ -343,6 +361,30 @@ const Console = ({ classes }: IConsoleProps) => {
|
||||
component: Policies,
|
||||
path: IAM_PAGES.POLICIES,
|
||||
},
|
||||
{
|
||||
component: IDPLDAPConfigurations,
|
||||
path: IAM_PAGES.IDP_LDAP_CONFIGURATIONS,
|
||||
},
|
||||
{
|
||||
component: IDPOpenIDConfigurations,
|
||||
path: IAM_PAGES.IDP_OPENID_CONFIGURATIONS,
|
||||
},
|
||||
{
|
||||
component: AddIDPLDAPConfiguration,
|
||||
path: IAM_PAGES.IDP_LDAP_CONFIGURATIONS_ADD,
|
||||
},
|
||||
{
|
||||
component: AddIDPOpenIDConfiguration,
|
||||
path: IAM_PAGES.IDP_OPENID_CONFIGURATIONS_ADD,
|
||||
},
|
||||
{
|
||||
component: IDPLDAPConfigurationDetails,
|
||||
path: IAM_PAGES.IDP_LDAP_CONFIGURATIONS_VIEW,
|
||||
},
|
||||
{
|
||||
component: IDPOpenIDConfigurationDetails,
|
||||
path: IAM_PAGES.IDP_OPENID_CONFIGURATIONS_VIEW,
|
||||
},
|
||||
{
|
||||
component: Heal,
|
||||
path: IAM_PAGES.TOOLS_HEAL,
|
||||
|
||||
219
portal-ui/src/screens/Console/IDP/AddIDPConfiguration.tsx
Normal file
219
portal-ui/src/screens/Console/IDP/AddIDPConfiguration.tsx
Normal file
@@ -0,0 +1,219 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { Box, Grid } from "@mui/material";
|
||||
import {
|
||||
formFieldStyles,
|
||||
modalBasic,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import { Button } from "mds";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
import {
|
||||
setErrorSnackMessage,
|
||||
setServerNeedsRestart,
|
||||
} from "../../../systemSlice";
|
||||
import useApi from "../Common/Hooks/useApi";
|
||||
import PageHeader from "../Common/PageHeader/PageHeader";
|
||||
import BackLink from "../../../common/BackLink";
|
||||
import PageLayout from "../Common/Layout/PageLayout";
|
||||
import SectionTitle from "../Common/SectionTitle";
|
||||
|
||||
type AddIDPConfigurationProps = {
|
||||
classes?: any;
|
||||
icon: React.ReactNode;
|
||||
helpBox: React.ReactNode;
|
||||
header: string;
|
||||
title: string;
|
||||
backLink: string;
|
||||
formFields: object;
|
||||
endpoint: string;
|
||||
};
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...formFieldStyles,
|
||||
...modalBasic,
|
||||
});
|
||||
|
||||
const AddIDPConfiguration = ({
|
||||
classes,
|
||||
icon,
|
||||
helpBox,
|
||||
header,
|
||||
backLink,
|
||||
title,
|
||||
formFields,
|
||||
endpoint,
|
||||
}: AddIDPConfigurationProps) => {
|
||||
const extraFormFields = {
|
||||
name: {
|
||||
required: true,
|
||||
hasError: (s: string, editMode: boolean) => {
|
||||
return !s && editMode ? "Config Name is required" : "";
|
||||
},
|
||||
label: "Name",
|
||||
tooltip: "Name for identity provider configuration",
|
||||
placeholder: "Name",
|
||||
type: "text",
|
||||
},
|
||||
...formFields,
|
||||
};
|
||||
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [fields, setFields] = useState<any>({});
|
||||
|
||||
const onSuccess = (res: any) => {
|
||||
navigate(backLink);
|
||||
dispatch(setServerNeedsRestart(res.restart === true));
|
||||
};
|
||||
|
||||
const onError = (err: ErrorResponseHandler) =>
|
||||
dispatch(setErrorSnackMessage(err));
|
||||
|
||||
const [loading, invokeApi] = useApi(onSuccess, onError);
|
||||
|
||||
const validSave = () => {
|
||||
for (const [key, value] of Object.entries(extraFormFields)) {
|
||||
if (
|
||||
value.required &&
|
||||
!(
|
||||
fields[key] !== undefined &&
|
||||
fields[key] !== null &&
|
||||
fields[key] !== ""
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
setFields({});
|
||||
};
|
||||
|
||||
const addRecord = (event: React.FormEvent) => {
|
||||
event.preventDefault();
|
||||
const name = fields["name"];
|
||||
let input = "";
|
||||
for (const key of Object.keys(formFields)) {
|
||||
if (fields[key]) {
|
||||
input += `${key}=${fields[key]} `;
|
||||
}
|
||||
}
|
||||
invokeApi("POST", endpoint, { name, input });
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid item xs={12}>
|
||||
<PageHeader label={<BackLink to={backLink} label={header} />} />
|
||||
<PageLayout>
|
||||
<Box
|
||||
sx={{
|
||||
display: "grid",
|
||||
padding: "25px",
|
||||
gap: "25px",
|
||||
gridTemplateColumns: {
|
||||
md: "2fr 1.2fr",
|
||||
xs: "1fr",
|
||||
},
|
||||
border: "1px solid #eaeaea",
|
||||
}}
|
||||
>
|
||||
<Box>
|
||||
<SectionTitle icon={icon}>{title}</SectionTitle>
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
addRecord(e);
|
||||
}}
|
||||
>
|
||||
<Grid container item spacing="20" sx={{ marginTop: 1 }}>
|
||||
<Grid xs={12} item>
|
||||
{Object.entries(extraFormFields).map(([key, value]) => (
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
className={classes.formFieldRow}
|
||||
key={key}
|
||||
>
|
||||
<InputBoxWrapper
|
||||
id={key}
|
||||
required={value.required}
|
||||
name={key}
|
||||
label={value.label}
|
||||
tooltip={value.tooltip}
|
||||
error={value.hasError(fields[key], true)}
|
||||
value={fields[key] ? fields[key] : ""}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
setFields({ ...fields, [key]: e.target.value })
|
||||
}
|
||||
placeholder={value.placeholder}
|
||||
type={value.type}
|
||||
/>
|
||||
</Grid>
|
||||
))}
|
||||
<Grid item xs={12} textAlign={"right"}>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
marginTop: "20px",
|
||||
gap: "15px",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
id={"clear"}
|
||||
type="button"
|
||||
variant="regular"
|
||||
onClick={resetForm}
|
||||
label={"Clear"}
|
||||
/>
|
||||
|
||||
<Button
|
||||
id={"save-key"}
|
||||
type="submit"
|
||||
variant="callAction"
|
||||
color="primary"
|
||||
disabled={loading || !validSave()}
|
||||
label={"Save"}
|
||||
/>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
</Box>
|
||||
{helpBox}
|
||||
</Box>
|
||||
</PageLayout>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(AddIDPConfiguration);
|
||||
106
portal-ui/src/screens/Console/IDP/AddIDPConfigurationHelpbox.tsx
Normal file
106
portal-ui/src/screens/Console/IDP/AddIDPConfigurationHelpbox.tsx
Normal file
@@ -0,0 +1,106 @@
|
||||
import React, { Fragment } from "react";
|
||||
|
||||
import { Box } from "@mui/material";
|
||||
import { HelpIconFilled } from "../../../icons";
|
||||
|
||||
interface IContent {
|
||||
icon: React.ReactNode;
|
||||
text: string;
|
||||
iconDescription: string;
|
||||
}
|
||||
|
||||
interface IAddIDPConfigurationHelpBoxProps {
|
||||
helpText: string;
|
||||
docLink: string;
|
||||
docText: string;
|
||||
contents: IContent[];
|
||||
}
|
||||
|
||||
const FeatureItem = ({
|
||||
icon,
|
||||
description,
|
||||
}: {
|
||||
icon: any;
|
||||
description: string;
|
||||
}) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
"& .min-icon": {
|
||||
marginRight: "10px",
|
||||
height: "23px",
|
||||
width: "23px",
|
||||
marginBottom: "10px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{icon}{" "}
|
||||
<div style={{ fontSize: "14px", fontStyle: "italic", color: "#5E5E5E" }}>
|
||||
{description}
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const AddIDPConfigurationHelpBox = ({
|
||||
helpText,
|
||||
docLink,
|
||||
docText,
|
||||
contents,
|
||||
}: IAddIDPConfigurationHelpBoxProps) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
flex: 1,
|
||||
border: "1px solid #eaeaea",
|
||||
borderRadius: "2px",
|
||||
display: "flex",
|
||||
flexFlow: "column",
|
||||
padding: "20px",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
fontWeight: 600,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
marginBottom: "16px",
|
||||
paddingBottom: "20px",
|
||||
|
||||
"& .min-icon": {
|
||||
height: "21px",
|
||||
width: "21px",
|
||||
marginRight: "15px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<HelpIconFilled />
|
||||
<div>{helpText}</div>
|
||||
</Box>
|
||||
<Box sx={{ fontSize: "14px", marginBottom: "15px" }}>
|
||||
{contents.map((content) => (
|
||||
<Fragment>
|
||||
{content.icon && (
|
||||
<Box sx={{ paddingBottom: "20px" }}>
|
||||
<FeatureItem
|
||||
icon={content.icon}
|
||||
description={content.iconDescription}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
<Box sx={{ paddingBottom: "20px" }}>{content.text}</Box>
|
||||
</Fragment>
|
||||
))}
|
||||
<Box sx={{ paddingBottom: "20px" }}>
|
||||
<a href={docLink} target="_blank" rel="noreferrer">
|
||||
{docText}
|
||||
</a>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddIDPConfigurationHelpBox;
|
||||
@@ -0,0 +1,86 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import LoginIcon from "@mui/icons-material/Login";
|
||||
import {
|
||||
formFieldStyles,
|
||||
modalBasic,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
|
||||
import AddIDPConfiguration from "./AddIDPConfiguration";
|
||||
import { ldapFormFields } from "./utils";
|
||||
import AddIDPConfigurationHelpBox from "./AddIDPConfigurationHelpbox";
|
||||
|
||||
type AddIDPLDAPConfigurationProps = {
|
||||
classes?: any;
|
||||
};
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...formFieldStyles,
|
||||
formFieldRow: {
|
||||
...formFieldStyles.formFieldRow,
|
||||
},
|
||||
...modalBasic,
|
||||
});
|
||||
|
||||
const AddIDPLDAPConfiguration = ({ classes }: AddIDPLDAPConfigurationProps) => {
|
||||
const helpBoxContents = [
|
||||
{
|
||||
text: "MinIO supports using an Active Directory or LDAP (AD/LDAP) service for external management of user identities. Configuring an external IDentity Provider (IDP) enables Single-Sign On (SSO) workflows, where applications authenticate against the external IDP before accessing MinIO.",
|
||||
icon: <LoginIcon />,
|
||||
iconDescription: "Create Configurations",
|
||||
},
|
||||
{
|
||||
text: "MinIO queries the configured Active Directory / LDAP server to verify the credentials specified by the application and optionally return a list of groups in which the user has membership. MinIO supports two modes (Lookup-Bind Mode and Username-Bind Mode) for performing these queries",
|
||||
icon: null,
|
||||
iconDescription: "",
|
||||
},
|
||||
{
|
||||
text: "MinIO recommends using Lookup-Bind mode as the preferred method for verifying AD/LDAP credentials. Username-Bind mode is a legacy method retained for backwards compatibility only.",
|
||||
icon: null,
|
||||
iconDescription: "",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<AddIDPConfiguration
|
||||
icon={<LoginIcon />}
|
||||
helpBox={
|
||||
<AddIDPConfigurationHelpBox
|
||||
helpText={"Learn more about LDAP Configurations"}
|
||||
contents={helpBoxContents}
|
||||
docLink={
|
||||
"https://min.io/docs/minio/linux/operations/external-iam.html?ref=con#minio-external-iam-ad-ldap"
|
||||
}
|
||||
docText={"Learn more about LDAP Configurations"}
|
||||
/>
|
||||
}
|
||||
header={"LDAP Configurations"}
|
||||
backLink={IAM_PAGES.IDP_LDAP_CONFIGURATIONS}
|
||||
title={"Create LDAP Configuration"}
|
||||
endpoint={"/api/v1/idp/ldap/"}
|
||||
formFields={ldapFormFields}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(AddIDPLDAPConfiguration);
|
||||
@@ -0,0 +1,71 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
|
||||
import { LockIcon } from "../../../icons";
|
||||
import AddIDPConfiguration from "./AddIDPConfiguration";
|
||||
import { openIDFormFields } from "./utils";
|
||||
import AddIDPConfigurationHelpBox from "./AddIDPConfigurationHelpbox";
|
||||
|
||||
type AddIDPOpenIDConfigurationProps = {
|
||||
classes?: any;
|
||||
};
|
||||
|
||||
const styles = (theme: Theme) => createStyles({});
|
||||
|
||||
const AddIDPOpenIDConfiguration = ({
|
||||
classes,
|
||||
}: AddIDPOpenIDConfigurationProps) => {
|
||||
const helpBoxContents = [
|
||||
{
|
||||
text: "MinIO supports using an OpenID Connect (OIDC) compatible IDentity Provider (IDP) such as Okta, KeyCloak, Dex, Google, or Facebook for external management of user identities.",
|
||||
icon: <LockIcon />,
|
||||
iconDescription: "Create Configurations",
|
||||
},
|
||||
{
|
||||
text: "Configuring an external IDP enables Single-Sign On workflows, where applications authenticate against the external IDP before accessing MinIO.",
|
||||
icon: null,
|
||||
iconDescription: "",
|
||||
},
|
||||
];
|
||||
return (
|
||||
<AddIDPConfiguration
|
||||
icon={<LockIcon />}
|
||||
helpBox={
|
||||
<AddIDPConfigurationHelpBox
|
||||
helpText={"Learn more about OpenID Connect Configurations"}
|
||||
contents={helpBoxContents}
|
||||
docLink={
|
||||
"https://min.io/docs/minio/linux/operations/external-iam.html?ref=con#minio-external-iam-oidc"
|
||||
}
|
||||
docText={"Learn more about OpenID Connect Configurations"}
|
||||
/>
|
||||
}
|
||||
header={"OpenID Configurations"}
|
||||
backLink={IAM_PAGES.IDP_OPENID_CONFIGURATIONS}
|
||||
title={"Create OpenID Configuration"}
|
||||
endpoint={"/api/v1/idp/openid/"}
|
||||
formFields={openIDFormFields}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(AddIDPOpenIDConfiguration);
|
||||
@@ -0,0 +1,86 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { DialogContentText } from "@mui/material";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import useApi from "../Common/Hooks/useApi";
|
||||
import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog";
|
||||
import { ConfirmDeleteIcon } from "../../../icons";
|
||||
import {
|
||||
setErrorSnackMessage,
|
||||
setServerNeedsRestart,
|
||||
} from "../../../systemSlice";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
|
||||
interface IDeleteIDPConfigurationModalProps {
|
||||
closeDeleteModalAndRefresh: (refresh: boolean) => void;
|
||||
deleteOpen: boolean;
|
||||
idp: string;
|
||||
idpType: string;
|
||||
}
|
||||
|
||||
const DeleteIDPConfigurationModal = ({
|
||||
closeDeleteModalAndRefresh,
|
||||
deleteOpen,
|
||||
idp,
|
||||
idpType,
|
||||
}: IDeleteIDPConfigurationModalProps) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const onDelSuccess = (res: any) => {
|
||||
closeDeleteModalAndRefresh(true);
|
||||
dispatch(setServerNeedsRestart(res.restart === true));
|
||||
};
|
||||
const onDelError = (err: ErrorResponseHandler) =>
|
||||
dispatch(setErrorSnackMessage(err));
|
||||
const onClose = () => closeDeleteModalAndRefresh(false);
|
||||
|
||||
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
|
||||
|
||||
if (!idp) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const onConfirmDelete = () => {
|
||||
invokeDeleteApi("DELETE", `/api/v1/idp/${idpType}/${idp}`);
|
||||
};
|
||||
|
||||
const displayName = idp === "_" ? "Default" : idp;
|
||||
|
||||
return (
|
||||
<ConfirmDialog
|
||||
title={`Delete ${displayName}`}
|
||||
confirmText={"Delete"}
|
||||
isOpen={deleteOpen}
|
||||
titleIcon={<ConfirmDeleteIcon />}
|
||||
isLoading={deleteLoading}
|
||||
onConfirm={onConfirmDelete}
|
||||
onClose={onClose}
|
||||
confirmButtonProps={{
|
||||
disabled: deleteLoading,
|
||||
}}
|
||||
confirmationContent={
|
||||
<DialogContentText>
|
||||
Are you sure you want to delete IDP <b>{displayName}</b>{" "}
|
||||
configuration? <br />
|
||||
</DialogContentText>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeleteIDPConfigurationModal;
|
||||
364
portal-ui/src/screens/Console/IDP/IDPConfigurationDetails.tsx
Normal file
364
portal-ui/src/screens/Console/IDP/IDPConfigurationDetails.tsx
Normal file
@@ -0,0 +1,364 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { Box, Grid } from "@mui/material";
|
||||
import {
|
||||
buttonsStyles,
|
||||
containerForHeader,
|
||||
formFieldStyles,
|
||||
hrClass,
|
||||
modalBasic,
|
||||
pageContentStyles,
|
||||
searchField,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import { RefreshIcon, TrashIcon } from "../../../icons";
|
||||
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import { Button } from "mds";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
import {
|
||||
setErrorSnackMessage,
|
||||
setServerNeedsRestart,
|
||||
} from "../../../systemSlice";
|
||||
import useApi from "../Common/Hooks/useApi";
|
||||
import api from "../../../common/api";
|
||||
import PageLayout from "../Common/Layout/PageLayout";
|
||||
import PageHeader from "../Common/PageHeader/PageHeader";
|
||||
import BackLink from "../../../common/BackLink";
|
||||
import ScreenTitle from "../Common/ScreenTitle/ScreenTitle";
|
||||
import DeleteIDPConfigurationModal from "./DeleteIDPConfigurationModal";
|
||||
import FormSwitchWrapper from "../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
|
||||
type IDPConfigurationDetailsProps = {
|
||||
classes?: any;
|
||||
formFields: object;
|
||||
endpoint: string;
|
||||
backLink: string;
|
||||
header: string;
|
||||
idpType: string;
|
||||
icon: React.ReactNode;
|
||||
};
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...formFieldStyles,
|
||||
formFieldRow: {
|
||||
...formFieldStyles.formFieldRow,
|
||||
},
|
||||
...modalBasic,
|
||||
pageContainer: {
|
||||
height: "100%",
|
||||
},
|
||||
screenTitle: {
|
||||
border: 0,
|
||||
paddingTop: 0,
|
||||
},
|
||||
...pageContentStyles,
|
||||
...searchField,
|
||||
capitalize: {
|
||||
textTransform: "capitalize",
|
||||
},
|
||||
...hrClass,
|
||||
...buttonsStyles,
|
||||
...containerForHeader(theme.spacing(4)),
|
||||
});
|
||||
|
||||
const IDPConfigurationDetails = ({
|
||||
classes,
|
||||
formFields,
|
||||
endpoint,
|
||||
backLink,
|
||||
header,
|
||||
idpType,
|
||||
icon,
|
||||
}: IDPConfigurationDetailsProps) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const navigate = useNavigate();
|
||||
const params = useParams();
|
||||
|
||||
const configurationName = params.idpName;
|
||||
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [isEnabled, setIsEnabled] = useState<boolean>(false);
|
||||
const [fields, setFields] = useState<any>({});
|
||||
const [originalFields, setOriginalFields] = useState<any>({});
|
||||
const [record, setRecord] = useState<any>({});
|
||||
const [editMode, setEditMode] = useState<boolean>(false);
|
||||
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
|
||||
|
||||
const onSuccess = (res: any) => {
|
||||
dispatch(setServerNeedsRestart(res.restart === true));
|
||||
};
|
||||
|
||||
const onError = (err: ErrorResponseHandler) =>
|
||||
dispatch(setErrorSnackMessage(err));
|
||||
|
||||
const [loadingSave, invokeApi] = useApi(onSuccess, onError);
|
||||
|
||||
const onEnabledSuccess = (res: any) => {
|
||||
setIsEnabled(!isEnabled);
|
||||
dispatch(setServerNeedsRestart(res.restart === true));
|
||||
};
|
||||
|
||||
const onEnabledError = (err: ErrorResponseHandler) => {
|
||||
dispatch(setErrorSnackMessage(err));
|
||||
};
|
||||
|
||||
const [loadingEnabledSave, invokeEnabledApi] = useApi(
|
||||
onEnabledSuccess,
|
||||
onEnabledError
|
||||
);
|
||||
|
||||
const toggleEditMode = () => {
|
||||
if (editMode) {
|
||||
parseFields(record);
|
||||
}
|
||||
setEditMode(!editMode);
|
||||
};
|
||||
|
||||
const parseFields = (record: any) => {
|
||||
let fields: any = {};
|
||||
if (record.info) {
|
||||
record.info.forEach((item: any) => {
|
||||
if (item.key === "enable") {
|
||||
setIsEnabled(item.value === "on");
|
||||
}
|
||||
fields[item.key] = item.value;
|
||||
});
|
||||
}
|
||||
setFields(fields);
|
||||
};
|
||||
|
||||
const parseOriginalFields = (record: any) => {
|
||||
let fields: any = {};
|
||||
if (record.info) {
|
||||
record.info.forEach((item: any) => {
|
||||
fields[item.key] = item.value;
|
||||
});
|
||||
}
|
||||
setOriginalFields(fields);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const loadRecord = () => {
|
||||
api
|
||||
.invoke("GET", `${endpoint}${configurationName}`)
|
||||
.then((result: any) => {
|
||||
if (result) {
|
||||
setRecord(result);
|
||||
parseFields(result);
|
||||
parseOriginalFields(result);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
dispatch(setErrorSnackMessage(err));
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
if (loading) {
|
||||
loadRecord();
|
||||
}
|
||||
}, [dispatch, loading, configurationName, endpoint]);
|
||||
|
||||
const validSave = () => {
|
||||
for (const [key, value] of Object.entries(formFields)) {
|
||||
if (
|
||||
value.required &&
|
||||
!(
|
||||
fields[key] !== undefined &&
|
||||
fields[key] !== null &&
|
||||
fields[key] !== ""
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
setFields({});
|
||||
};
|
||||
|
||||
const saveRecord = (event: React.FormEvent) => {
|
||||
event.preventDefault();
|
||||
let input = "";
|
||||
for (const key of Object.keys(formFields)) {
|
||||
if (fields[key] || fields[key] !== originalFields[key]) {
|
||||
input += `${key}=${fields[key]} `;
|
||||
}
|
||||
}
|
||||
invokeApi("PUT", `${endpoint}${configurationName}`, { input });
|
||||
setEditMode(false);
|
||||
};
|
||||
|
||||
const closeDeleteModalAndRefresh = async (refresh: boolean) => {
|
||||
setDeleteOpen(false);
|
||||
|
||||
if (refresh) {
|
||||
navigate(backLink);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleConfiguration = (value: boolean) => {
|
||||
const input = `enable=${value ? "on" : "off"}`;
|
||||
invokeEnabledApi("PUT", `${endpoint}${configurationName}`, { input });
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid item xs={12}>
|
||||
{deleteOpen && configurationName && (
|
||||
<DeleteIDPConfigurationModal
|
||||
deleteOpen={deleteOpen}
|
||||
idp={configurationName}
|
||||
idpType={idpType}
|
||||
closeDeleteModalAndRefresh={closeDeleteModalAndRefresh}
|
||||
/>
|
||||
)}
|
||||
<PageHeader
|
||||
label={<BackLink to={backLink} label={header} />}
|
||||
actions={
|
||||
<FormSwitchWrapper
|
||||
label={""}
|
||||
indicatorLabels={["Enabled", "Disabled"]}
|
||||
checked={isEnabled}
|
||||
value={"is-configuration-enabled"}
|
||||
id={"is-configuration-enabled"}
|
||||
name={"is-configuration-enabled"}
|
||||
onChange={(e) => toggleConfiguration(e.target.checked)}
|
||||
description=""
|
||||
disabled={loadingEnabledSave}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageLayout className={classes.pageContainer}>
|
||||
<Grid item xs={12}>
|
||||
<ScreenTitle
|
||||
classes={{
|
||||
screenTitle: classes.screenTitle,
|
||||
}}
|
||||
icon={icon}
|
||||
title={configurationName === "_" ? "Default" : configurationName}
|
||||
actions={
|
||||
<Fragment>
|
||||
{configurationName !== "_" && (
|
||||
<Button
|
||||
id={"delete-idp-config"}
|
||||
onClick={() => {
|
||||
setDeleteOpen(true);
|
||||
}}
|
||||
label={"Delete Configuration"}
|
||||
icon={<TrashIcon />}
|
||||
variant={"secondary"}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
id={"refresh-idp-config"}
|
||||
onClick={() => setLoading(true)}
|
||||
label={"Refresh"}
|
||||
icon={<RefreshIcon />}
|
||||
/>
|
||||
</Fragment>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
saveRecord(e);
|
||||
}}
|
||||
>
|
||||
<Grid container item spacing="20" sx={{ marginTop: 1 }}>
|
||||
<Grid xs={12} item className={classes.fieldBox}>
|
||||
{Object.entries(formFields).map(([key, value]) => (
|
||||
<Grid item xs={12} className={classes.formFieldRow} key={key}>
|
||||
<InputBoxWrapper
|
||||
id={key}
|
||||
required={value.required}
|
||||
name={key}
|
||||
label={value.label}
|
||||
tooltip={value.tooltip}
|
||||
error={value.hasError(fields[key], editMode)}
|
||||
value={fields[key] ? fields[key] : ""}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
setFields({ ...fields, [key]: e.target.value })
|
||||
}
|
||||
placeholder={value.placeholder}
|
||||
disabled={!editMode}
|
||||
type={value.type}
|
||||
/>
|
||||
</Grid>
|
||||
))}
|
||||
<Grid item xs={12} textAlign={"right"}>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
marginTop: "20px",
|
||||
gap: "15px",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
id={"edit"}
|
||||
type="button"
|
||||
variant={editMode ? "regular" : "callAction"}
|
||||
onClick={toggleEditMode}
|
||||
label={editMode ? "Cancel" : "Edit"}
|
||||
/>
|
||||
{editMode && (
|
||||
<Button
|
||||
id={"clear"}
|
||||
type="button"
|
||||
variant="regular"
|
||||
onClick={resetForm}
|
||||
label={"Clear"}
|
||||
/>
|
||||
)}
|
||||
|
||||
{editMode && (
|
||||
<Button
|
||||
id={"save-key"}
|
||||
type="submit"
|
||||
variant="callAction"
|
||||
color="primary"
|
||||
disabled={loading || loadingSave || !validSave()}
|
||||
label={"Save"}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
</PageLayout>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(IDPConfigurationDetails);
|
||||
225
portal-ui/src/screens/Console/IDP/IDPConfigurations.tsx
Normal file
225
portal-ui/src/screens/Console/IDP/IDPConfigurations.tsx
Normal file
@@ -0,0 +1,225 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import {
|
||||
CONSOLE_UI_RESOURCE,
|
||||
IAM_SCOPES,
|
||||
} from "../../../common/SecureComponent/permissions";
|
||||
import {
|
||||
hasPermission,
|
||||
SecureComponent,
|
||||
} from "../../../common/SecureComponent";
|
||||
import api from "../../../common/api";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import { setErrorSnackMessage } from "../../../systemSlice";
|
||||
import PageHeader from "../Common/PageHeader/PageHeader";
|
||||
import PageLayout from "../Common/Layout/PageLayout";
|
||||
import { containerForHeader } from "../Common/FormComponents/common/styleLibrary";
|
||||
import { Grid } from "@mui/material";
|
||||
import TooltipWrapper from "../Common/TooltipWrapper/TooltipWrapper";
|
||||
import { Button } from "mds";
|
||||
import { AddIcon, RefreshIcon } from "../../../icons";
|
||||
import TableWrapper from "../Common/TableWrapper/TableWrapper";
|
||||
import DeleteIDPConfigurationModal from "./DeleteIDPConfigurationModal";
|
||||
|
||||
type IDPConfigurationsProps = {
|
||||
classes?: any;
|
||||
idpType: string;
|
||||
};
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...containerForHeader(theme.spacing(4)),
|
||||
});
|
||||
|
||||
const IDPConfigurations = ({ classes, idpType }: IDPConfigurationsProps) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
|
||||
const [selectedIDP, setSelectedIDP] = useState<string>("");
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [records, setRecords] = useState<[]>([]);
|
||||
|
||||
const deleteIDP = hasPermission(CONSOLE_UI_RESOURCE, [
|
||||
IAM_SCOPES.ADMIN_CONFIG_UPDATE,
|
||||
]);
|
||||
|
||||
const viewIDP = hasPermission(CONSOLE_UI_RESOURCE, [
|
||||
IAM_SCOPES.ADMIN_CONFIG_UPDATE,
|
||||
]);
|
||||
|
||||
const displayIDPs = hasPermission(CONSOLE_UI_RESOURCE, [
|
||||
IAM_SCOPES.ADMIN_CONFIG_UPDATE,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchRecords();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (loading) {
|
||||
if (displayIDPs) {
|
||||
api
|
||||
.invoke("GET", `/api/v1/idp/${idpType}`)
|
||||
.then((res) => {
|
||||
setLoading(false);
|
||||
setRecords(
|
||||
res.results.map((r: any) => {
|
||||
r.name = r.name === "_" ? "Default" : r.name;
|
||||
r.enabled = r.enabled === true ? "Enabled" : "Disabled";
|
||||
return r;
|
||||
})
|
||||
);
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
setLoading(false);
|
||||
dispatch(setErrorSnackMessage(err));
|
||||
});
|
||||
} else {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
}, [loading, setLoading, setRecords, dispatch, displayIDPs, idpType]);
|
||||
|
||||
const fetchRecords = () => {
|
||||
setLoading(true);
|
||||
};
|
||||
|
||||
const confirmDeleteIDP = (idp: string) => {
|
||||
setDeleteOpen(true);
|
||||
idp = idp === "Default" ? "_" : idp;
|
||||
setSelectedIDP(idp);
|
||||
};
|
||||
|
||||
const viewAction = (idp: any) => {
|
||||
let name = idp.name === "Default" ? "_" : idp.name;
|
||||
navigate(`/idp/${idpType}/configurations/${name}`);
|
||||
};
|
||||
|
||||
const closeDeleteModalAndRefresh = async (refresh: boolean) => {
|
||||
setDeleteOpen(false);
|
||||
|
||||
if (refresh) {
|
||||
fetchRecords();
|
||||
}
|
||||
};
|
||||
|
||||
const tableActions = [
|
||||
{
|
||||
type: "view",
|
||||
onClick: viewAction,
|
||||
disableButtonFunction: () => !viewIDP,
|
||||
},
|
||||
{
|
||||
type: "delete",
|
||||
onClick: confirmDeleteIDP,
|
||||
sendOnlyId: true,
|
||||
disableButtonFunction: (idp: string) => !deleteIDP || idp === "Default",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{deleteOpen && (
|
||||
<DeleteIDPConfigurationModal
|
||||
deleteOpen={deleteOpen}
|
||||
idp={selectedIDP}
|
||||
idpType={idpType}
|
||||
closeDeleteModalAndRefresh={closeDeleteModalAndRefresh}
|
||||
/>
|
||||
)}
|
||||
<PageHeader label={`${idpType.toUpperCase()} Configurations`} />
|
||||
<PageLayout className={classes.pageContainer}>
|
||||
<Grid container spacing={1}>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
display={"flex"}
|
||||
alignItems={"center"}
|
||||
justifyContent={"flex-end"}
|
||||
sx={{
|
||||
"& button": {
|
||||
marginLeft: "8px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<SecureComponent
|
||||
scopes={[IAM_SCOPES.ADMIN_CONFIG_UPDATE]}
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
<TooltipWrapper tooltip={"Refresh"}>
|
||||
<Button
|
||||
id={"refresh-keys"}
|
||||
variant="regular"
|
||||
icon={<RefreshIcon />}
|
||||
onClick={() => setLoading(true)}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</SecureComponent>
|
||||
<SecureComponent
|
||||
scopes={[IAM_SCOPES.ADMIN_CONFIG_UPDATE]}
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
<TooltipWrapper tooltip={`Create ${idpType} configuration`}>
|
||||
<Button
|
||||
id={"create-idp"}
|
||||
label={"Create Configuration"}
|
||||
variant={"callAction"}
|
||||
icon={<AddIcon />}
|
||||
onClick={() =>
|
||||
navigate(`/idp/${idpType}/configurations/add-idp`)
|
||||
}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</SecureComponent>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.tableBlock}>
|
||||
<SecureComponent
|
||||
scopes={[IAM_SCOPES.ADMIN_CONFIG_UPDATE]}
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
<TableWrapper
|
||||
itemActions={tableActions}
|
||||
columns={[
|
||||
{ label: "Name", elementKey: "name" },
|
||||
{ label: "Type", elementKey: "type" },
|
||||
{ label: "Enabled", elementKey: "enabled" },
|
||||
]}
|
||||
isLoading={loading}
|
||||
records={records}
|
||||
entityName="Keys"
|
||||
idField="name"
|
||||
/>
|
||||
</SecureComponent>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</PageLayout>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(IDPConfigurations);
|
||||
@@ -0,0 +1,48 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { ldapFormFields } from "./utils";
|
||||
import LoginIcon from "@mui/icons-material/Login";
|
||||
import IDPConfigurationDetails from "./IDPConfigurationDetails";
|
||||
import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
|
||||
|
||||
type IDPLDAPConfigurationDetailsProps = {
|
||||
classes?: any;
|
||||
};
|
||||
|
||||
const styles = (theme: Theme) => createStyles({});
|
||||
|
||||
const IDPLDAPConfigurationDetails = ({
|
||||
classes,
|
||||
}: IDPLDAPConfigurationDetailsProps) => {
|
||||
return (
|
||||
<IDPConfigurationDetails
|
||||
backLink={IAM_PAGES.IDP_LDAP_CONFIGURATIONS}
|
||||
header={"LDAP Configurations"}
|
||||
endpoint={"/api/v1/idp/ldap/"}
|
||||
idpType={"ldap"}
|
||||
formFields={ldapFormFields}
|
||||
icon={<LoginIcon width={40} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(IDPLDAPConfigurationDetails);
|
||||
34
portal-ui/src/screens/Console/IDP/IDPLDAPConfigurations.tsx
Normal file
34
portal-ui/src/screens/Console/IDP/IDPLDAPConfigurations.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import IDPConfigurations from "./IDPConfigurations";
|
||||
|
||||
type IDPLDAPConfigurationsProps = {
|
||||
classes?: any;
|
||||
};
|
||||
|
||||
const styles = (theme: Theme) => createStyles({});
|
||||
|
||||
const IDPLDAPConfigurations = ({ classes }: IDPLDAPConfigurationsProps) => {
|
||||
return <IDPConfigurations idpType={"ldap"} />;
|
||||
};
|
||||
|
||||
export default withStyles(styles)(IDPLDAPConfigurations);
|
||||
@@ -0,0 +1,48 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
|
||||
import { LockIcon } from "../../../icons";
|
||||
import { openIDFormFields } from "./utils";
|
||||
import IDPConfigurationDetails from "./IDPConfigurationDetails";
|
||||
|
||||
type IDPOpenIDConfigurationDetailsProps = {
|
||||
classes?: any;
|
||||
};
|
||||
|
||||
const styles = (theme: Theme) => createStyles({});
|
||||
|
||||
const IDPOpenIDConfigurationDetails = ({
|
||||
classes,
|
||||
}: IDPOpenIDConfigurationDetailsProps) => {
|
||||
return (
|
||||
<IDPConfigurationDetails
|
||||
backLink={IAM_PAGES.IDP_OPENID_CONFIGURATIONS}
|
||||
header={"OpenID Configurations"}
|
||||
endpoint={"/api/v1/idp/openid/"}
|
||||
idpType={"openid"}
|
||||
formFields={openIDFormFields}
|
||||
icon={<LockIcon width={40} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(IDPOpenIDConfigurationDetails);
|
||||
@@ -0,0 +1,34 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import IDPConfigurations from "./IDPConfigurations";
|
||||
|
||||
type IDPOpenIDConfigurationsProps = {
|
||||
classes?: any;
|
||||
};
|
||||
|
||||
const styles = (theme: Theme) => createStyles({});
|
||||
|
||||
const IDPOpenIDConfigurations = ({ classes }: IDPOpenIDConfigurationsProps) => {
|
||||
return <IDPConfigurations idpType={"openid"} />;
|
||||
};
|
||||
|
||||
export default withStyles(styles)(IDPOpenIDConfigurations);
|
||||
176
portal-ui/src/screens/Console/IDP/utils.tsx
Normal file
176
portal-ui/src/screens/Console/IDP/utils.tsx
Normal file
@@ -0,0 +1,176 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
export const openIDFormFields = {
|
||||
config_url: {
|
||||
required: true,
|
||||
hasError: (s: string, editMode: boolean) => {
|
||||
return !s && editMode ? "Config URL is required" : "";
|
||||
},
|
||||
label: "Config URL",
|
||||
tooltip: "Config URL for identity provider configuration",
|
||||
placeholder:
|
||||
"https://identity-provider-url/.well-known/openid-configuration",
|
||||
type: "text",
|
||||
},
|
||||
client_id: {
|
||||
required: true,
|
||||
hasError: (s: string, editMode: boolean) => {
|
||||
return !s && editMode ? "Client ID is required" : "";
|
||||
},
|
||||
label: "Client ID",
|
||||
tooltip: "Identity provider Client ID",
|
||||
placeholder: "Enter Client ID",
|
||||
type: "text",
|
||||
},
|
||||
client_secret: {
|
||||
required: true,
|
||||
hasError: (s: string, editMode: boolean) => {
|
||||
return !s && editMode ? "Client Secret is required" : "";
|
||||
},
|
||||
label: "Client Secret",
|
||||
tooltip: "Identity provider Client Secret",
|
||||
placeholder: "Enter Client Secret",
|
||||
type: "password",
|
||||
},
|
||||
display_name: {
|
||||
required: false,
|
||||
label: "Display Name",
|
||||
tooltip: "Display Name",
|
||||
placeholder: "Enter Display Name",
|
||||
type: "text",
|
||||
hasError: (s: string, editMode: boolean) => "",
|
||||
},
|
||||
claim_name: {
|
||||
required: false,
|
||||
label: "Claim Name",
|
||||
tooltip: "Claim from which MinIO will read the policy or role to use",
|
||||
placeholder: "Enter Claim Name",
|
||||
type: "text",
|
||||
hasError: (s: string, editMode: boolean) => "",
|
||||
},
|
||||
claim_prefix: {
|
||||
required: false,
|
||||
label: "Claim Prefix",
|
||||
tooltip: "Claim Prefix",
|
||||
placeholder: "Enter Claim Prefix",
|
||||
type: "text",
|
||||
hasError: (s: string, editMode: boolean) => "",
|
||||
},
|
||||
scopes: {
|
||||
required: false,
|
||||
label: "Scopes",
|
||||
tooltip: "Scopes",
|
||||
placeholder: "openid,profile,email",
|
||||
type: "text",
|
||||
hasError: (s: string, editMode: boolean) => "",
|
||||
},
|
||||
redirect_uri: {
|
||||
required: false,
|
||||
label: "Redirect URI",
|
||||
tooltip: "Redirect URI",
|
||||
placeholder: "https://console-endpoint-url/oauth_callback",
|
||||
type: "text",
|
||||
hasError: (s: string, editMode: boolean) => "",
|
||||
},
|
||||
role_policy: {
|
||||
required: false,
|
||||
label: "Role Policy",
|
||||
tooltip: "Role Policy",
|
||||
placeholder: "readonly",
|
||||
type: "text",
|
||||
hasError: (s: string, editMode: boolean) => "",
|
||||
},
|
||||
};
|
||||
|
||||
export const ldapFormFields = {
|
||||
server_addr: {
|
||||
required: true,
|
||||
hasError: (s: string, editMode: boolean) => {
|
||||
return !s && editMode ? "Server Address is required" : "";
|
||||
},
|
||||
label: "Server Address",
|
||||
tooltip: 'AD/LDAP server address e.g. "myldapserver.com:636"',
|
||||
placeholder: "myldapserver.com:636",
|
||||
type: "text",
|
||||
},
|
||||
lookup_bind_dn: {
|
||||
required: true,
|
||||
hasError: (s: string, editMode: boolean) => {
|
||||
return !s && editMode ? "Lookup Bind DN is required" : "";
|
||||
},
|
||||
label: "Lookup Bind DN",
|
||||
tooltip:
|
||||
"DN for LDAP read-only service account used to perform DN and group lookups",
|
||||
placeholder: "cn=admin,dc=min,dc=io",
|
||||
type: "text",
|
||||
},
|
||||
lookup_bind_password: {
|
||||
required: true,
|
||||
hasError: (s: string, editMode: boolean) => {
|
||||
return !s && editMode ? "Lookup Bind Password is required" : "";
|
||||
},
|
||||
label: "Lookup Bind Password",
|
||||
tooltip:
|
||||
"Password for LDAP read-only service account used to perform DN and group lookups",
|
||||
placeholder: "admin",
|
||||
type: "password",
|
||||
},
|
||||
user_dn_search_base_dn: {
|
||||
required: true,
|
||||
hasError: (s: string, editMode: boolean) => {
|
||||
return !s && editMode ? "User DN Search Base DN is required" : "";
|
||||
},
|
||||
label: "User DN Search Base",
|
||||
tooltip: "Base LDAP DN to search for user DN",
|
||||
placeholder: "DC=example,DC=net",
|
||||
type: "text",
|
||||
},
|
||||
user_dn_search_filter: {
|
||||
required: true,
|
||||
hasError: (s: string, editMode: boolean) => {
|
||||
return !s && editMode ? "User DN Search Filter is required" : "";
|
||||
},
|
||||
label: "User DN Search Filter",
|
||||
tooltip: "Search filter to lookup user DN",
|
||||
placeholder: "(sAMAcountName=%s)",
|
||||
type: "text",
|
||||
},
|
||||
display_name: {
|
||||
required: false,
|
||||
label: "Display Name",
|
||||
tooltip: "Display Name",
|
||||
placeholder: "Enter Display Name",
|
||||
type: "text",
|
||||
hasError: (s: string, editMode: boolean) => "",
|
||||
},
|
||||
group_search_base_dn: {
|
||||
required: false,
|
||||
hasError: (s: string, editMode: boolean) => "",
|
||||
label: "Group Search Base DN",
|
||||
tooltip: "Group Search Base DN",
|
||||
placeholder: "ou=swengg,dc=min,dc=io",
|
||||
type: "text",
|
||||
},
|
||||
group_search_filter: {
|
||||
required: false,
|
||||
hasError: (s: string, editMode: boolean) => "",
|
||||
label: "Group Search Filter",
|
||||
tooltip: "Group Search Filter",
|
||||
placeholder: "(&(objectclass=groupofnames)(member=%d))",
|
||||
type: "text",
|
||||
},
|
||||
};
|
||||
@@ -233,7 +233,7 @@ export const objectBrowserSlice = createSlice({
|
||||
setSearchObjects: (state, action: PayloadAction<string>) => {
|
||||
state.searchObjects = action.payload;
|
||||
},
|
||||
setLoadingObjectsList: (state, action: PayloadAction<boolean>) => {
|
||||
setLoadingObjects: (state, action: PayloadAction<boolean>) => {
|
||||
state.loadingObjects = action.payload;
|
||||
},
|
||||
setSearchVersions: (state, action: PayloadAction<string>) => {
|
||||
@@ -352,7 +352,7 @@ export const {
|
||||
openList,
|
||||
closeList,
|
||||
setSearchObjects,
|
||||
setLoadingObjectsList,
|
||||
setLoadingObjects,
|
||||
cancelObjectInList,
|
||||
setSearchVersions,
|
||||
setSelectedVersion,
|
||||
|
||||
@@ -59,6 +59,7 @@ import {
|
||||
import SettingsIcon from "../../icons/SettingsIcon";
|
||||
import React from "react";
|
||||
import LicenseBadge from "./Menu/LicenseBadge";
|
||||
import { LockOpen, Login } from "@mui/icons-material";
|
||||
|
||||
export const validRoutes = (
|
||||
features: string[] | null | undefined,
|
||||
@@ -141,6 +142,20 @@ export const validRoutes = (
|
||||
to: IAM_PAGES.POLICIES,
|
||||
icon: AccessMenuIcon,
|
||||
},
|
||||
{
|
||||
name: "OpenID",
|
||||
component: NavLink,
|
||||
id: "openID",
|
||||
to: IAM_PAGES.IDP_OPENID_CONFIGURATIONS,
|
||||
icon: LockOpen,
|
||||
},
|
||||
{
|
||||
name: "LDAP",
|
||||
component: NavLink,
|
||||
id: "ldap",
|
||||
to: IAM_PAGES.IDP_LDAP_CONFIGURATIONS,
|
||||
icon: Login,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
|
||||
@@ -19,9 +19,10 @@ import { useNavigate } from "react-router-dom";
|
||||
import { useAppDispatch } from "../../store";
|
||||
import { ErrorResponseHandler } from "../../common/types";
|
||||
import { clearSession } from "../../common/utils";
|
||||
import api from "../../common/api";
|
||||
import { userLogged } from "../../systemSlice";
|
||||
import { resetSession } from "../Console/consoleSlice";
|
||||
import api from "../../common/api";
|
||||
import LoadingComponent from "../../common/LoadingComponent";
|
||||
|
||||
const LogoutPage = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
@@ -33,7 +34,7 @@ const LogoutPage = () => {
|
||||
localStorage.setItem("userLoggedIn", "");
|
||||
localStorage.setItem("redirect-path", "");
|
||||
dispatch(resetSession());
|
||||
navigate(`login`);
|
||||
navigate(`/login`);
|
||||
};
|
||||
const state = localStorage.getItem("auth-state");
|
||||
api
|
||||
@@ -47,7 +48,7 @@ const LogoutPage = () => {
|
||||
});
|
||||
};
|
||||
logout();
|
||||
return <></>;
|
||||
return <LoadingComponent />;
|
||||
};
|
||||
|
||||
export default LogoutPage;
|
||||
|
||||
@@ -7969,9 +7969,9 @@ mdn-data@2.0.4:
|
||||
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b"
|
||||
integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==
|
||||
|
||||
"mds@https://github.com/minio/mds.git#v0.0.5":
|
||||
version "0.0.5"
|
||||
resolved "https://github.com/minio/mds.git#b9183841f178b7cc3ef320554f762c1d5bf6d7bd"
|
||||
"mds@https://github.com/minio/mds.git#v0.0.7":
|
||||
version "0.0.7"
|
||||
resolved "https://github.com/minio/mds.git#dd51b9d694550e7737e6cf2462195b8ad70fbfe6"
|
||||
dependencies:
|
||||
"@types/styled-components" "^5.1.25"
|
||||
styled-components "^5.3.6"
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@@ -604,9 +603,6 @@ func (wsc *wsMinioClient) objectManager(session *models.Principal) {
|
||||
|
||||
// start listing and writing to web socket
|
||||
go func() {
|
||||
defer func() {
|
||||
log.Println("Closing listing goroutine:", messageRequest.RequestID)
|
||||
}()
|
||||
objectRqConfigs, err := getObjectsOptionsFromReq(messageRequest)
|
||||
if err != nil {
|
||||
LogInfo(fmt.Sprintf("Error during Objects OptionsParse %s", err.Error()))
|
||||
|
||||
Reference in New Issue
Block a user