Display Retention Policy details inside bucket details (#905)

This commit is contained in:
Alex
2021-07-29 12:37:33 -05:00
committed by GitHub
parent e6dec7aa46
commit e20ef0cfb8
12 changed files with 183 additions and 98 deletions

View File

@@ -1,25 +1,25 @@
{
"files": {
"main.css": "/static/css/main.8cfac526.chunk.css",
"main.js": "/static/js/main.dd8abda8.chunk.js",
"main.js.map": "/static/js/main.dd8abda8.chunk.js.map",
"main.js": "/static/js/main.d02553d5.chunk.js",
"main.js.map": "/static/js/main.d02553d5.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.43a31377.js",
"runtime-main.js.map": "/static/js/runtime-main.43a31377.js.map",
"static/css/2.60e04a19.chunk.css": "/static/css/2.60e04a19.chunk.css",
"static/js/2.fdaf1119.chunk.js": "/static/js/2.fdaf1119.chunk.js",
"static/js/2.fdaf1119.chunk.js.map": "/static/js/2.fdaf1119.chunk.js.map",
"static/js/2.a3d22cff.chunk.js": "/static/js/2.a3d22cff.chunk.js",
"static/js/2.a3d22cff.chunk.js.map": "/static/js/2.a3d22cff.chunk.js.map",
"index.html": "/index.html",
"static/css/2.60e04a19.chunk.css.map": "/static/css/2.60e04a19.chunk.css.map",
"static/css/main.8cfac526.chunk.css.map": "/static/css/main.8cfac526.chunk.css.map",
"static/js/2.fdaf1119.chunk.js.LICENSE.txt": "/static/js/2.fdaf1119.chunk.js.LICENSE.txt",
"static/js/2.a3d22cff.chunk.js.LICENSE.txt": "/static/js/2.a3d22cff.chunk.js.LICENSE.txt",
"static/media/minio_console_logo.0837460e.svg": "/static/media/minio_console_logo.0837460e.svg",
"static/media/minio_operator_logo.1312b7c9.svg": "/static/media/minio_operator_logo.1312b7c9.svg"
},
"entrypoints": [
"static/js/runtime-main.43a31377.js",
"static/css/2.60e04a19.chunk.css",
"static/js/2.fdaf1119.chunk.js",
"static/js/2.a3d22cff.chunk.js",
"static/css/main.8cfac526.chunk.css",
"static/js/main.dd8abda8.chunk.js"
"static/js/main.d02553d5.chunk.js"
]
}

View File

@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="MinIO Console"/><link href="https://fonts.googleapis.com/css2?family=Lato:wght@400;500;700;900&display=swap" rel="stylesheet"/><link href="/styles/root-styles.css" rel="stylesheet"/><link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png"/><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"/><link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png"/><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"/><link rel="manifest" href="/manifest.json"/><link rel="mask-icon" href="/safari-pinned-tab.svg" color="#3a4e54"/><title>MinIO Console</title><link href="/static/css/2.60e04a19.chunk.css" rel="stylesheet"><link href="/static/css/main.8cfac526.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"><div id="loader-block"><svg class="loader-svg-container" viewBox="22 22 44 44"><circle class="loader-style MuiCircularProgress-circle MuiCircularProgress-circleIndeterminate" cx="44" cy="44" r="20.2" fill="none" stroke-width="3.6"></circle></svg></div></div><script>!function(e){function r(r){for(var n,l,i=r[0],a=r[1],p=r[2],c=0,s=[];c<i.length;c++)l=i[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,p||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var a=t[i];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="/";var i=this["webpackJsonpportal-ui"]=this["webpackJsonpportal-ui"]||[],a=i.push.bind(i);i.push=r,i=i.slice();for(var p=0;p<i.length;p++)r(i[p]);var f=a;t()}([])</script><script src="/static/js/2.fdaf1119.chunk.js"></script><script src="/static/js/main.dd8abda8.chunk.js"></script></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="MinIO Console"/><link href="https://fonts.googleapis.com/css2?family=Lato:wght@400;500;700;900&display=swap" rel="stylesheet"/><link href="/styles/root-styles.css" rel="stylesheet"/><link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png"/><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"/><link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png"/><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"/><link rel="manifest" href="/manifest.json"/><link rel="mask-icon" href="/safari-pinned-tab.svg" color="#3a4e54"/><title>MinIO Console</title><link href="/static/css/2.60e04a19.chunk.css" rel="stylesheet"><link href="/static/css/main.8cfac526.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"><div id="loader-block"><svg class="loader-svg-container" viewBox="22 22 44 44"><circle class="loader-style MuiCircularProgress-circle MuiCircularProgress-circleIndeterminate" cx="44" cy="44" r="20.2" fill="none" stroke-width="3.6"></circle></svg></div></div><script>!function(e){function r(r){for(var n,l,i=r[0],a=r[1],p=r[2],c=0,s=[];c<i.length;c++)l=i[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,p||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var a=t[i];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="/";var i=this["webpackJsonpportal-ui"]=this["webpackJsonpportal-ui"]||[],a=i.push.bind(i);i.push=r,i=i.slice();for(var p=0;p<i.length;p++)r(i[p]);var f=a;t()}([])</script><script src="/static/js/2.a3d22cff.chunk.js"></script><script src="/static/js/main.d02553d5.chunk.js"></script></body></html>

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

File diff suppressed because one or more lines are too long

View File

@@ -383,3 +383,9 @@ export interface ErrorResponseHandler {
errorMessage: string;
detailedError: string;
}
export interface IRetentionConfig {
mode: string;
unit: string;
validity: number;
}

View File

@@ -38,7 +38,10 @@ import {
buttonsStyles,
hrClass,
} from "../../Common/FormComponents/common/styleLibrary";
import { ErrorResponseHandler } from "../../../../common/types";
import {
ErrorResponseHandler,
IRetentionConfig,
} from "../../../../common/types";
import api from "../../../../common/api";
import SetAccessPolicy from "./SetAccessPolicy";
import SetRetentionConfig from "./SetRetentionConfig";
@@ -82,6 +85,12 @@ const styles = (theme: Theme) =>
dualCardRight: {
paddingLeft: "5px",
},
capitalizeFirst: {
textTransform: "capitalize",
},
titleCol: {
width: "25%",
},
...hrClass,
...buttonsStyles,
});
@@ -107,10 +116,14 @@ const BucketSummary = ({
const [loadingVersioning, setLoadingVersioning] = useState<boolean>(true);
const [loadingQuota, setLoadingQuota] = useState<boolean>(true);
const [loadingReplication, setLoadingReplication] = useState<boolean>(true);
const [loadingRetention, setLoadingRetention] = useState<boolean>(true);
const [isVersioned, setIsVersioned] = useState<boolean>(false);
const [quotaEnabled, setQuotaEnabled] = useState<boolean>(false);
const [quota, setQuota] = useState<BucketQuota | null>(null);
const [encryptionEnabled, setEncryptionEnabled] = useState<boolean>(false);
const [retentionEnabled, setRetentionEnabled] = useState<boolean>(false);
const [retentionConfig, setRetentionConfig] =
useState<IRetentionConfig | null>(null);
const [retentionConfigOpen, setRetentionConfigOpen] =
useState<boolean>(false);
const [enableEncryptionScreenOpen, setEnableEncryptionScreenOpen] =
@@ -270,11 +283,29 @@ const BucketSummary = ({
}
}, [loadingReplication, setErrorSnackMessage, bucketName, distributedSetup]);
useEffect(() => {
if (loadingRetention && hasObjectLocking) {
api
.invoke("GET", `/api/v1/buckets/${bucketName}/retention`)
.then((res: IRetentionConfig) => {
setLoadingRetention(false);
setRetentionEnabled(true);
setRetentionConfig(res);
})
.catch((err: ErrorResponseHandler) => {
setRetentionEnabled(false);
setLoadingRetention(false);
setRetentionConfig(null);
});
}
}, [loadingRetention, hasObjectLocking, bucketName]);
const loadAllBucketData = () => {
setLoadingBucket(true);
setLoadingSize(true);
setLoadingVersioning(true);
setLoadingEncryption(true);
setLoadingRetention(true);
};
const setBucketVersioning = () => {
@@ -396,7 +427,7 @@ const BucketSummary = ({
</td>
</tr>
{distributedSetup && (
<React.Fragment>
<Fragment>
<tr>
<td className={classes.titleCol}>Replication:</td>
<td className={classes.doubleElement}>
@@ -404,14 +435,10 @@ const BucketSummary = ({
</td>
</tr>
<tr>
{!hasObjectLocking && (
<React.Fragment>
<td className={classes.titleCol}>Object Locking:</td>
<td>Disabled</td>
</React.Fragment>
)}
<td className={classes.titleCol}>Object Locking:</td>
<td>{!hasObjectLocking ? "Disabled" : "Enabled"}</td>
</tr>
</React.Fragment>
</Fragment>
)}
<tr>
<td className={classes.titleCol}>Encryption:</td>
@@ -539,14 +566,14 @@ const BucketSummary = ({
<Paper className={classes.paperContainer}>
<Grid container>
<Grid item xs={12}>
<h2>Object Locking</h2>
<h2>Retention</h2>
<hr className={classes.hrClass} />
<table>
<table width={"100%"}>
<tbody>
<tr className={classes.gridContainer}>
<td className={classes.titleCol}>Retention:</td>
<td className={classes.titleCol}>Status:</td>
<td>
{loadingVersioning ? (
{loadingRetention ? (
<CircularProgress
color="primary"
size={16}
@@ -561,11 +588,37 @@ const BucketSummary = ({
setRetentionConfigOpen(true);
}}
>
Configure
{!retentionEnabled ? "Disabled" : "Enabled"}
</Button>
</Fragment>
)}
</td>
{retentionConfig === null ? (
<td colSpan={2}>&nbsp;</td>
) : (
<Fragment>
<td className={classes.titleCol}>Mode:</td>
<td className={classes.capitalizeFirst}>
{retentionConfig && retentionConfig.mode}
</td>
</Fragment>
)}
</tr>
<tr className={classes.gridContainer}>
{retentionConfig === null ? (
<td colSpan={2}></td>
) : (
<Fragment>
<td className={classes.titleCol}>Valitidy:</td>
<td className={classes.capitalizeFirst}>
{retentionConfig && retentionConfig.validity}{" "}
{retentionConfig &&
(retentionConfig.validity === 1
? retentionConfig.unit.slice(0, -1)
: retentionConfig.unit)}
</td>
</Fragment>
)}
</tr>
</tbody>
</table>

View File

@@ -16,12 +16,15 @@
import React, { useEffect, useState } from "react";
import { connect } from "react-redux";
import { Button, LinearProgress } from "@material-ui/core";
import { Button, LinearProgress, CircularProgress } from "@material-ui/core";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import Grid from "@material-ui/core/Grid";
import { modalBasic } from "../../Common/FormComponents/common/styleLibrary";
import { setModalErrorSnackMessage } from "../../../../actions";
import { ErrorResponseHandler } from "../../../../common/types";
import {
ErrorResponseHandler,
IRetentionConfig,
} from "../../../../common/types";
import api from "../../../../common/api";
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
import RadioGroupSelector from "../../Common/FormComponents/RadioGroupSelector/RadioGroupSelector";
@@ -48,6 +51,7 @@ const SetRetentionConfig = ({
setModalErrorSnackMessage,
}: ISetRetentionConfigProps) => {
const [addLoading, setAddLoading] = useState<boolean>(false);
const [loadingForm, setLoadingForm] = useState<boolean>(true);
const [retentionMode, setRetentionMode] = useState<string>("compliance");
const [retentionUnit, setRetentionUnit] = useState<string>("days");
const [retentionValidity, setRetentionValidity] = useState<number>(1);
@@ -83,6 +87,24 @@ const SetRetentionConfig = ({
setValid(true);
}, [retentionValidity]);
useEffect(() => {
if (loadingForm) {
api
.invoke("GET", `/api/v1/buckets/${bucketName}/retention`)
.then((res: IRetentionConfig) => {
setLoadingForm(false);
// We set default values
setRetentionMode(res.mode);
setRetentionValidity(res.validity);
setRetentionUnit(res.unit);
})
.catch((err: ErrorResponseHandler) => {
setLoadingForm(false);
});
}
}, [loadingForm, bucketName]);
return (
<ModalWrapper
title="Set Retention Configuration"
@@ -91,78 +113,82 @@ const SetRetentionConfig = ({
closeModalAndRefresh();
}}
>
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
setRetention(e);
}}
>
<Grid container>
<Grid item xs={12} className={classes.formScrollable}>
<Grid item xs={12}>
<RadioGroupSelector
currentSelection={retentionMode}
id="retention_mode"
name="retention_mode"
label="Retention Mode"
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
setRetentionMode(e.target.value as string);
}}
selectorOptions={[
{ value: "compliance", label: "Compliance" },
{ value: "governance", label: "Governance" },
]}
/>
{loadingForm ? (
<CircularProgress color="primary" size={16} variant="indeterminate" />
) : (
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
setRetention(e);
}}
>
<Grid container>
<Grid item xs={12} className={classes.formScrollable}>
<Grid item xs={12}>
<RadioGroupSelector
currentSelection={retentionMode}
id="retention_mode"
name="retention_mode"
label="Retention Mode"
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
setRetentionMode(e.target.value as string);
}}
selectorOptions={[
{ value: "compliance", label: "Compliance" },
{ value: "governance", label: "Governance" },
]}
/>
</Grid>
<Grid item xs={12}>
<RadioGroupSelector
currentSelection={retentionUnit}
id="retention_unit"
name="retention_unit"
label="Retention Unit"
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
setRetentionUnit(e.target.value as string);
}}
selectorOptions={[
{ value: "days", label: "Days" },
{ value: "years", label: "Years" },
]}
/>
</Grid>
<Grid item xs={12}>
<InputBoxWrapper
type="number"
id="retention_validity"
name="retention_validity"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setRetentionValidity(e.target.valueAsNumber);
}}
label="Retention Validity"
value={String(retentionValidity)}
required
min="1"
/>
</Grid>
</Grid>
<Grid item xs={12}>
<RadioGroupSelector
currentSelection={retentionUnit}
id="retention_unit"
name="retention_unit"
label="Retention Unit"
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
setRetentionUnit(e.target.value as string);
}}
selectorOptions={[
{ value: "days", label: "Days" },
{ value: "years", label: "Years" },
]}
/>
</Grid>
<Grid item xs={12}>
<InputBoxWrapper
type="number"
id="retention_validity"
name="retention_validity"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setRetentionValidity(e.target.valueAsNumber);
}}
label="Retention Validity"
value={String(retentionValidity)}
required
min="1"
/>
<Button
type="submit"
variant="contained"
color="primary"
fullWidth
disabled={addLoading || !valid}
>
Set
</Button>
</Grid>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</Grid>
<Grid item xs={12}>
<Button
type="submit"
variant="contained"
color="primary"
fullWidth
disabled={addLoading || !valid}
>
Set
</Button>
</Grid>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</Grid>
</form>
</form>
)}
</ModalWrapper>
);
};