Fix Add Bucket Lifecycle Rule (#1797)

Fix Add Bucket Lifecycle Rule
Fix Edit ILM Rule
Update Bucket ILM Rules Listing

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
This commit is contained in:
Daniel Valdivia
2022-04-04 19:13:59 -07:00
committed by GitHub
parent c18c843d03
commit 822724a4f1
8 changed files with 591 additions and 469 deletions

View File

@@ -20,7 +20,15 @@ import { connect } from "react-redux";
import { Theme } from "@mui/material/styles"; import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles"; import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles"; import withStyles from "@mui/styles/withStyles";
import { Button, LinearProgress, SelectChangeEvent } from "@mui/material"; import {
Accordion,
AccordionDetails,
AccordionSummary,
Button,
LinearProgress,
SelectChangeEvent,
Typography,
} from "@mui/material";
import Grid from "@mui/material/Grid"; import Grid from "@mui/material/Grid";
import { setModalErrorSnackMessage } from "../../../../actions"; import { setModalErrorSnackMessage } from "../../../../actions";
import { import {
@@ -42,6 +50,9 @@ import {
} from "../../Common/FormComponents/common/styleLibrary"; } from "../../Common/FormComponents/common/styleLibrary";
import { LifecycleConfigIcon } from "../../../../icons"; import { LifecycleConfigIcon } from "../../../../icons";
import InputUnitMenu from "../../Common/FormComponents/InputUnitMenu/InputUnitMenu"; import InputUnitMenu from "../../Common/FormComponents/InputUnitMenu/InputUnitMenu";
import { BucketVersioning } from "../types";
import { AppState } from "../../../../store";
import FormSwitchWrapper from "../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
interface IReplicationModal { interface IReplicationModal {
open: boolean; open: boolean;
@@ -49,6 +60,7 @@ interface IReplicationModal {
classes: any; classes: any;
bucketName: string; bucketName: string;
setModalErrorSnackMessage: typeof setModalErrorSnackMessage; setModalErrorSnackMessage: typeof setModalErrorSnackMessage;
distributedSetup: boolean;
} }
export interface ITiersDropDown { export interface ITiersDropDown {
@@ -73,6 +85,9 @@ const styles = (theme: Theme) =>
}, },
}, },
}, },
formFieldRowFilter: {
"& .MuiPaper-root": { padding: 0 },
},
...spacingUtils, ...spacingUtils,
...modalStyleUtils, ...modalStyleUtils,
...formFieldStyles, ...formFieldStyles,
@@ -85,19 +100,25 @@ const AddLifecycleModal = ({
classes, classes,
bucketName, bucketName,
setModalErrorSnackMessage, setModalErrorSnackMessage,
distributedSetup,
}: IReplicationModal) => { }: IReplicationModal) => {
const [loadingTiers, setLoadingTiers] = useState<boolean>(true); const [loadingTiers, setLoadingTiers] = useState<boolean>(true);
const [tiersList, setTiersList] = useState<ITiersDropDown[]>([]); const [tiersList, setTiersList] = useState<ITiersDropDown[]>([]);
const [addLoading, setAddLoading] = useState(false); const [addLoading, setAddLoading] = useState(false);
const [isVersioned, setIsVersioned] = useState<boolean>(false);
const [prefix, setPrefix] = useState(""); const [prefix, setPrefix] = useState("");
const [tags, setTags] = useState<string>(""); const [tags, setTags] = useState<string>("");
const [storageClass, setStorageClass] = useState(""); const [storageClass, setStorageClass] = useState("");
const [NCExpirationDays, setNCExpirationDays] = useState<string>("");
const [NCTransitionDays, setNCTransitionDays] = useState<string>("");
const [ilmType, setIlmType] = useState<string>("expiry"); const [ilmType, setIlmType] = useState<string>("expiry");
const [expiryDays, setExpiryDays] = useState<string>(""); const [targetVersion, setTargetVersion] = useState<"current" | "noncurrent">(
const [transitionDays, setTransitionDays] = useState<string>(""); "current"
);
const [lifecycleDays, setLifecycleDays] = useState<string>("");
const [isFormValid, setIsFormValid] = useState<boolean>(false); const [isFormValid, setIsFormValid] = useState<boolean>(false);
const [expiredObjectDM, setExpiredObjectDM] = useState<boolean>(false);
const [loadingVersioning, setLoadingVersioning] = useState<boolean>(true);
useEffect(() => { useEffect(() => {
if (loadingTiers) { if (loadingTiers) {
@@ -136,39 +157,56 @@ const AddLifecycleModal = ({
} }
} }
setIsFormValid(valid); setIsFormValid(valid);
}, [ilmType, expiryDays, transitionDays, storageClass]); }, [ilmType, lifecycleDays, storageClass]);
useEffect(() => {
if (loadingVersioning && distributedSetup) {
api
.invoke("GET", `/api/v1/buckets/${bucketName}/versioning`)
.then((res: BucketVersioning) => {
setIsVersioned(res.is_versioned);
setLoadingVersioning(false);
})
.catch((err: ErrorResponseHandler) => {
setModalErrorSnackMessage(err);
setLoadingVersioning(false);
});
}
}, [
loadingVersioning,
setModalErrorSnackMessage,
bucketName,
distributedSetup,
]);
const addRecord = () => { const addRecord = () => {
let rules = {}; let rules = {};
let markerOn = false;
if (ilmType === "expiry") { if (ilmType === "expiry") {
let expiry = { let expiry: { [key: string]: number } = {};
expiry_days: parseInt(expiryDays),
};
if (parseInt(expiryDays) > 0 && parseInt(NCExpirationDays) > 0) { if (targetVersion === "current") {
markerOn = true; expiry["expiry_days"] = parseInt(lifecycleDays);
} else {
expiry["noncurrentversion_expiration_days"] = parseInt(lifecycleDays);
} }
rules = { rules = {
...expiry, ...expiry,
noncurrentversion_expiration_days: parseInt(NCExpirationDays),
}; };
} else { } else {
let transition = { let transition: { [key: string]: number | string } = {};
transition_days: parseInt(transitionDays), if (targetVersion === "current") {
}; transition["transition_days"] = parseInt(lifecycleDays);
transition["storage_class"] = storageClass;
if (parseInt(transitionDays) > 0 && parseInt(NCTransitionDays) > 0) { } else {
markerOn = true; transition["noncurrentversion_transition_days"] =
parseInt(lifecycleDays);
transition["noncurrentversion_transition_storage_class"] = storageClass;
} }
rules = { rules = {
...transition, ...transition,
noncurrentversion_transition_days: parseInt(NCTransitionDays),
storage_class: storageClass,
}; };
} }
@@ -176,7 +214,7 @@ const AddLifecycleModal = ({
type: ilmType, type: ilmType,
prefix, prefix,
tags, tags,
expired_object_delete_marker: markerOn, expired_object_delete_marker: expiredObjectDM,
...rules, ...rules,
}; };
@@ -226,13 +264,13 @@ const AddLifecycleModal = ({
<Grid container> <Grid container>
<Grid item xs={12} className={classes.formScrollable}> <Grid item xs={12} className={classes.formScrollable}>
<Grid item xs={12}> <Grid item xs={12}>
<Grid container> <Grid container spacing={1}>
<Grid item xs={3} textAlign={"left"}> <Grid item xs={12}>
<RadioGroupSelector <RadioGroupSelector
currentSelection={ilmType} currentSelection={ilmType}
id="quota_type" id="ilm_type"
name="quota_type" name="ilm_type"
label="" label="Type of lifecycle"
onChange={(e: React.ChangeEvent<{ value: unknown }>) => { onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
setIlmType(e.target.value as string); setIlmType(e.target.value as string);
}} }}
@@ -242,65 +280,56 @@ const AddLifecycleModal = ({
]} ]}
/> />
</Grid> </Grid>
<Grid item xs={9} /> {isVersioned && (
{ilmType === "expiry" ? ( <Grid item xs={12}>
<Fragment> <SelectWrapper
<Grid item xs={12} className={classes.formFieldRow}> value={targetVersion}
<InputBoxWrapper id="object_version"
id="expiry_days" name="object_version"
name="expiry_days" label="Object Version"
onChange={( onChange={(e) => {
e: React.ChangeEvent<HTMLInputElement> setTargetVersion(
) => { e.target.value as "current" | "noncurrent"
if (e.target.validity.valid) { );
setExpiryDays(e.target.value); }}
} options={[
}} { value: "current", label: "Current Version" },
pattern={"[0-9]*"} { value: "noncurrent", label: "Non-Current Version" },
label="Delete Latest Version After" ]}
value={expiryDays} />
overlayObject={ </Grid>
<InputUnitMenu )}
id={"expire-current-unit"}
unitSelected={"days"}
unitsList={[{ label: "Days", value: "days" }]}
disabled={true}
/>
}
/>
</Grid>
<Grid item xs={12} className={classes.formFieldRow}> <Grid item xs={12}>
<InputBoxWrapper <InputBoxWrapper
id="noncurrentversion_expiration_days" id="expiry_days"
name="noncurrentversion_expiration_days" name="expiry_days"
onChange={( onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
e: React.ChangeEvent<HTMLInputElement> if (e.target.validity.valid) {
) => { setLifecycleDays(e.target.value);
if (e.target.validity.valid) { }
setNCExpirationDays(e.target.value); }}
} pattern={"[0-9]*"}
}} label="After"
pattern={"[0-9]*"} value={lifecycleDays}
label="Delete Older Versions After" overlayObject={
value={NCExpirationDays} <InputUnitMenu
min="0" id={"expire-current-unit"}
overlayObject={ unitSelected={"days"}
<InputUnitMenu unitsList={[{ label: "Days", value: "days" }]}
id={"expire-noncurrent-unit"} disabled={true}
unitSelected={"days"}
unitsList={[{ label: "Days", value: "days" }]}
disabled={true}
/>
}
/> />
</Grid> }
</Fragment> />
</Grid>
{ilmType === "expiry" ? (
<Fragment></Fragment>
) : ( ) : (
<Fragment> <Fragment>
<Grid item xs={12} className={classes.formFieldRow}> <Grid item xs={12}>
<SelectWrapper <SelectWrapper
label="Tier" label="To Tier"
id="storage_class" id="storage_class"
name="storage_class" name="storage_class"
value={storageClass} value={storageClass}
@@ -310,90 +339,73 @@ const AddLifecycleModal = ({
options={tiersList} options={tiersList}
/> />
</Grid> </Grid>
<Grid item xs={12} className={classes.formFieldRow}>
<InputBoxWrapper
id="transition_days"
name="transition_days"
onChange={(
e: React.ChangeEvent<HTMLInputElement>
) => {
if (e.target.validity.valid) {
setTransitionDays(e.target.value);
}
}}
pattern={"[0-9]*"}
label="Transition Latest Version"
value={transitionDays}
min="0"
overlayObject={
<InputUnitMenu
id={"transition-current-unit"}
unitSelected={"days"}
unitsList={[{ label: "Days", value: "days" }]}
disabled={true}
/>
}
/>
</Grid>
<Grid item xs={12} className={classes.formFieldRow}>
<InputBoxWrapper
type="number"
id="noncurrentversion_transition_days"
name="noncurrentversion_transition_days"
onChange={(
e: React.ChangeEvent<HTMLInputElement>
) => {
if (e.target.validity.valid) {
setNCTransitionDays(e.target.value);
}
}}
label="Transition Older Versions"
value={NCTransitionDays}
pattern={"[0-9]*"}
overlayObject={
<InputUnitMenu
id={"transition-noncurrent-unit"}
unitSelected={"days"}
unitsList={[{ label: "Days", value: "days" }]}
disabled={true}
/>
}
/>
</Grid>
</Fragment> </Fragment>
)} )}
<Grid item xs={12} className={classes.formFieldRowFilter}>
<Accordion>
<AccordionSummary>
<Typography>Filters</Typography>
</AccordionSummary>
<AccordionDetails>
<Grid item xs={12}>
<InputBoxWrapper
id="prefix"
name="prefix"
onChange={(
e: React.ChangeEvent<HTMLInputElement>
) => {
setPrefix(e.target.value);
}}
label="Prefix"
value={prefix}
/>
</Grid>
<Grid item xs={12}>
<QueryMultiSelector
name="tags"
label="Tags"
elements={""}
onChange={(vl: string) => {
setTags(vl);
}}
keyPlaceholder="Tag Key"
valuePlaceholder="Tag Value"
withBorder
/>
</Grid>
</AccordionDetails>
</Accordion>
</Grid>
{ilmType === "expiry" && targetVersion === "noncurrent" && (
<Grid item xs={12} className={classes.formFieldRowFilter}>
<Accordion>
<AccordionSummary>
<Typography>Advanced</Typography>
</AccordionSummary>
<AccordionDetails>
<Grid item xs={12}>
<FormSwitchWrapper
value="expired_delete_marker"
id="expired_delete_marker"
name="expired_delete_marker"
checked={expiredObjectDM}
onChange={(
event: React.ChangeEvent<HTMLInputElement>
) => {
setExpiredObjectDM(event.target.checked);
}}
label={"Expire Delete Marker"}
description={
"Remove the reference to the object if no versions are left"
}
/>
</Grid>
</AccordionDetails>
</Accordion>
</Grid>
)}
</Grid> </Grid>
</Grid> </Grid>
<Grid item xs={12} className={classes.formFieldRow}>
<fieldset className={classes.fieldGroup}>
<legend className={classes.descriptionText}>Filters</legend>
<Grid item xs={12}>
<InputBoxWrapper
id="prefix"
name="prefix"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setPrefix(e.target.value);
}}
label="Prefix"
value={prefix}
/>
</Grid>
<Grid item xs={12}>
<QueryMultiSelector
name="tags"
label="Tags"
elements={""}
onChange={(vl: string) => {
setTags(vl);
}}
keyPlaceholder="Tag Key"
valuePlaceholder="Tag Value"
withBorder
/>
</Grid>
</fieldset>
</Grid>
</Grid> </Grid>
<Grid item xs={12} className={classes.modalButtonBar}> <Grid item xs={12} className={classes.modalButtonBar}>
<Button <Button
@@ -428,7 +440,11 @@ const AddLifecycleModal = ({
); );
}; };
const connector = connect(null, { const mapState = (state: AppState) => ({
distributedSetup: state.system.distributedSetup,
});
const connector = connect(mapState, {
setModalErrorSnackMessage, setModalErrorSnackMessage,
}); });

View File

@@ -20,7 +20,6 @@ import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles"; import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles"; import withStyles from "@mui/styles/withStyles";
import get from "lodash/get"; import get from "lodash/get";
import * as reactMoment from "react-moment";
import Grid from "@mui/material/Grid"; import Grid from "@mui/material/Grid";
import { BucketInfo, LifeCycleItem } from "../types"; import { BucketInfo, LifeCycleItem } from "../types";
import { AddIcon, TiersIcon } from "../../../../icons"; import { AddIcon, TiersIcon } from "../../../../icons";
@@ -38,8 +37,8 @@ import TableWrapper from "../../Common/TableWrapper/TableWrapper";
import HelpBox from "../../../../common/HelpBox"; import HelpBox from "../../../../common/HelpBox";
import PanelTitle from "../../Common/PanelTitle/PanelTitle"; import PanelTitle from "../../Common/PanelTitle/PanelTitle";
import { import {
SecureComponent,
hasPermission, hasPermission,
SecureComponent,
} from "../../../../common/SecureComponent"; } from "../../../../common/SecureComponent";
import { IAM_SCOPES } from "../../../../common/SecureComponent/permissions"; import { IAM_SCOPES } from "../../../../common/SecureComponent/permissions";
import RBIconButton from "./SummaryItems/RBIconButton"; import RBIconButton from "./SummaryItems/RBIconButton";
@@ -142,62 +141,96 @@ const BucketLifecyclePanel = ({
} }
}; };
const expirationRender = (expiration: any) => {
if (expiration.days) {
return `${expiration.days} day${expiration.days > 1 ? "s" : ""}`;
}
if (expiration.date === "0001-01-01T00:00:00Z") {
return "";
}
return <reactMoment.default>{expiration.date}</reactMoment.default>;
};
const transitionRender = (transition: any) => {
if (transition.days) {
return `${transition.days} day${transition.days > 1 ? "s" : ""}`;
}
if (transition.date === "0001-01-01T00:00:00Z") {
return "";
}
return <reactMoment.default>{transition.date}</reactMoment.default>;
};
const renderStorageClass = (objectST: any) => { const renderStorageClass = (objectST: any) => {
const stClass = get(objectST, "transition.storage_class", ""); let stClass = get(objectST, "transition.storage_class", "");
stClass = get(objectST, "transition.noncurrent_storage_class", stClass);
return stClass; return stClass;
}; };
const lifecycleColumns = [ const lifecycleColumns = [
{ label: "ID", elementKey: "id" }, {
label: "Type",
renderFullObject: true,
renderFunction: (el: LifeCycleItem) => {
if (!el) {
return <Fragment />;
}
if (
el.expiration &&
(el.expiration.days > 0 || el.expiration.noncurrent_expiration_days)
) {
return <span>Expiry</span>;
}
if (
el.transition &&
(el.transition.days > 0 || el.transition.noncurrent_transition_days)
) {
return <span>Transition</span>;
}
return <Fragment />;
},
},
{
label: "Version",
renderFullObject: true,
renderFunction: (el: LifeCycleItem) => {
if (!el) {
return <Fragment />;
}
if (el.expiration) {
if (el.expiration.days > 0) {
return <span>Current</span>;
} else if (el.expiration.noncurrent_expiration_days) {
return <span>Non-Current</span>;
}
}
if (el.transition) {
if (el.transition.days > 0) {
return <span>Current</span>;
} else if (el.transition.noncurrent_transition_days) {
return <span>Non-Current</span>;
}
}
},
},
{
label: "Tier",
elementKey: "storage_class",
renderFunction: renderStorageClass,
renderFullObject: true,
},
{ {
label: "Prefix", label: "Prefix",
elementKey: "prefix", elementKey: "prefix",
}, },
{
label: "After",
renderFullObject: true,
renderFunction: (el: LifeCycleItem) => {
if (!el) {
return <Fragment />;
}
if (el.expiration) {
if (el.expiration.days > 0) {
return <span>{el.expiration.days} days</span>;
} else if (el.expiration.noncurrent_expiration_days) {
return <span>{el.expiration.noncurrent_expiration_days} days</span>;
}
}
if (el.transition) {
if (el.transition.days > 0) {
return <span>{el.transition.days} days</span>;
} else if (el.transition.noncurrent_transition_days) {
return <span>{el.transition.noncurrent_transition_days} days</span>;
}
}
},
},
{ {
label: "Status", label: "Status",
elementKey: "status", elementKey: "status",
}, },
{
label: "Expiration",
elementKey: "expiration",
renderFunction: expirationRender,
},
{
label: "Transition",
elementKey: "transition",
renderFunction: transitionRender,
},
{
label: "Storage Class",
elementKey: "storage_class",
renderFunction: renderStorageClass,
renderFullObject: true,
},
]; ];
const lifecycleActions = [ const lifecycleActions = [
@@ -226,7 +259,7 @@ const BucketLifecyclePanel = ({
open={editLifecycleOpen} open={editLifecycleOpen}
closeModalAndRefresh={closeEditLCAndRefresh} closeModalAndRefresh={closeEditLCAndRefresh}
selectedBucket={bucketName} selectedBucket={bucketName}
lifecycle={selectedLifecycleRule} lifecycleRule={selectedLifecycleRule}
/> />
)} )}
{addLifecycleOpen && ( {addLifecycleOpen && (

View File

@@ -16,7 +16,15 @@
import React, { useEffect, useState, Fragment } from "react"; import React, { useEffect, useState, Fragment } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Button, LinearProgress, SelectChangeEvent } from "@mui/material"; import {
Accordion,
AccordionDetails,
AccordionSummary,
Button,
LinearProgress,
SelectChangeEvent,
Typography,
} from "@mui/material";
import { Theme } from "@mui/material/styles"; import { Theme } from "@mui/material/styles";
import get from "lodash/get"; import get from "lodash/get";
import Grid from "@mui/material/Grid"; import Grid from "@mui/material/Grid";
@@ -62,6 +70,9 @@ const styles = (theme: Theme) =>
}, },
}, },
}, },
formFieldRowAccordion: {
"& .MuiPaper-root": { padding: 0 },
},
...spacingUtils, ...spacingUtils,
...modalStyleUtils, ...modalStyleUtils,
...formFieldStyles, ...formFieldStyles,
@@ -72,7 +83,7 @@ interface IAddUserContentProps {
classes: any; classes: any;
closeModalAndRefresh: (reload: boolean) => void; closeModalAndRefresh: (reload: boolean) => void;
selectedBucket: string; selectedBucket: string;
lifecycle: LifeCycleItem; lifecycleRule: LifeCycleItem;
open: boolean; open: boolean;
setModalErrorSnackMessage: typeof setModalErrorSnackMessage; setModalErrorSnackMessage: typeof setModalErrorSnackMessage;
} }
@@ -81,7 +92,7 @@ const EditLifecycleConfiguration = ({
classes, classes,
closeModalAndRefresh, closeModalAndRefresh,
selectedBucket, selectedBucket,
lifecycle, lifecycleRule,
open, open,
setModalErrorSnackMessage, setModalErrorSnackMessage,
}: IAddUserContentProps) => { }: IAddUserContentProps) => {
@@ -141,40 +152,66 @@ const EditLifecycleConfiguration = ({
}, [ilmType, expiryDays, transitionDays, storageClass]); }, [ilmType, expiryDays, transitionDays, storageClass]);
useEffect(() => { useEffect(() => {
if (lifecycle.status === "Enabled") { if (lifecycleRule.status === "Enabled") {
setEnabled(true); setEnabled(true);
} }
let transitionMode = false; let transitionMode = false;
if (lifecycle.transition) { if (lifecycleRule.transition) {
if (lifecycle.transition.days && lifecycle.transition.days !== 0) { if (
setTransitionDays(lifecycle.transition.days.toString()); lifecycleRule.transition.days &&
lifecycleRule.transition.days !== 0
) {
setTransitionDays(lifecycleRule.transition.days.toString());
setIlmType("transition");
transitionMode = true;
}
if (
lifecycleRule.transition.noncurrent_transition_days &&
lifecycleRule.transition.noncurrent_transition_days !== 0
) {
setNCTransitionDays(
lifecycleRule.transition.noncurrent_transition_days.toString()
);
setIlmType("transition"); setIlmType("transition");
transitionMode = true; transitionMode = true;
} }
// Fallback to old rules by date // Fallback to old rules by date
if ( if (
lifecycle.transition.date && lifecycleRule.transition.date &&
lifecycle.transition.date !== "0001-01-01T00:00:00Z" lifecycleRule.transition.date !== "0001-01-01T00:00:00Z"
) { ) {
setIlmType("transition"); setIlmType("transition");
transitionMode = true; transitionMode = true;
} }
} }
if (lifecycle.expiration) { if (lifecycleRule.expiration) {
if (lifecycle.expiration.days && lifecycle.expiration.days !== 0) { if (
setExpiryDays(lifecycle.expiration.days.toString()); lifecycleRule.expiration.days &&
lifecycleRule.expiration.days !== 0
) {
setExpiryDays(lifecycleRule.expiration.days.toString());
setIlmType("expiry");
transitionMode = false;
}
if (
lifecycleRule.expiration.noncurrent_expiration_days &&
lifecycleRule.expiration.noncurrent_expiration_days !== 0
) {
setNCExpirationDays(
lifecycleRule.expiration.noncurrent_expiration_days.toString()
);
setIlmType("expiry"); setIlmType("expiry");
transitionMode = false; transitionMode = false;
} }
// Fallback to old rules by date // Fallback to old rules by date
if ( if (
lifecycle.expiration.date && lifecycleRule.expiration.date &&
lifecycle.expiration.date !== "0001-01-01T00:00:00Z" lifecycleRule.expiration.date !== "0001-01-01T00:00:00Z"
) { ) {
setIlmType("expiry"); setIlmType("expiry");
transitionMode = false; transitionMode = false;
@@ -183,23 +220,25 @@ const EditLifecycleConfiguration = ({
// Transition fields // Transition fields
if (transitionMode) { if (transitionMode) {
setStorageClass(lifecycle.transition?.storage_class || ""); setStorageClass(lifecycleRule.transition?.storage_class || "");
setNCTransitionDays( setNCTransitionDays(
lifecycle.transition?.noncurrent_transition_days?.toString() || "0" lifecycleRule.transition?.noncurrent_transition_days?.toString() || "0"
);
setNCTransitionSC(
lifecycleRule.transition?.noncurrent_storage_class || ""
); );
setNCTransitionSC(lifecycle.transition?.noncurrent_storage_class || "");
} else { } else {
// Expiry fields // Expiry fields
setNCExpirationDays( setNCExpirationDays(
lifecycle.expiration?.noncurrent_expiration_days?.toString() || "0" lifecycleRule.expiration?.noncurrent_expiration_days?.toString() || "0"
); );
} }
setExpiredObjectDM(!!lifecycle.expiration?.delete_marker); setExpiredObjectDM(!!lifecycleRule.expiration?.delete_marker);
setPrefix(lifecycle.prefix || ""); setPrefix(lifecycleRule.prefix || "");
if (lifecycle.tags) { if (lifecycleRule.tags) {
const tgs = lifecycle.tags.reduce( const tgs = lifecycleRule.tags.reduce(
(stringLab: string, currItem: any, index: number) => { (stringLab: string, currItem: any, index: number) => {
return `${stringLab}${index !== 0 ? "&" : ""}${currItem.key}=${ return `${stringLab}${index !== 0 ? "&" : ""}${currItem.key}=${
currItem.value currItem.value
@@ -210,7 +249,7 @@ const EditLifecycleConfiguration = ({
setTags(tgs); setTags(tgs);
} }
}, [lifecycle]); }, [lifecycleRule]);
const saveRecord = (event: React.FormEvent) => { const saveRecord = (event: React.FormEvent) => {
event.preventDefault(); event.preventDefault();
@@ -219,28 +258,45 @@ const EditLifecycleConfiguration = ({
return; return;
} }
setAddLoading(true); setAddLoading(true);
if (selectedBucket !== null && lifecycle !== null) { if (selectedBucket !== null && lifecycleRule !== null) {
let rules = {}; let rules = {};
if (ilmType === "expiry") { if (ilmType === "expiry") {
let expiry = { let expiry: { [key: string]: number } = {};
expiry_days: parseInt(expiryDays),
}; if (
lifecycleRule.expiration?.days &&
lifecycleRule.expiration?.days > 0
) {
expiry["expiry_days"] = parseInt(expiryDays);
}
if (lifecycleRule.expiration?.noncurrent_expiration_days) {
expiry["noncurrentversion_expiration_days"] =
parseInt(NCExpirationDays);
}
rules = { rules = {
...expiry, ...expiry,
noncurrentversion_expiration_days: parseInt(NCExpirationDays),
}; };
} else { } else {
let transition = { let transition: { [key: string]: number | string } = {};
transition_days: parseInt(transitionDays),
}; if (
lifecycleRule.expiration?.days &&
lifecycleRule.expiration?.days > 0
) {
transition["transition_days"] = parseInt(expiryDays);
transition["storage_class"] = storageClass;
}
if (lifecycleRule.expiration?.noncurrent_expiration_days) {
transition["noncurrentversion_transition_days"] =
parseInt(NCExpirationDays);
transition["noncurrentversion_transition_storage_class"] =
NCTransitionSC;
}
rules = { rules = {
...transition, ...transition,
noncurrentversion_transition_days: parseInt(NCTransitionDays),
noncurrentversion_transition_storage_class: NCTransitionSC,
storage_class: storageClass,
}; };
} }
@@ -256,7 +312,7 @@ const EditLifecycleConfiguration = ({
api api
.invoke( .invoke(
"PUT", "PUT",
`/api/v1/buckets/${selectedBucket}/lifecycle/${lifecycle.id}`, `/api/v1/buckets/${selectedBucket}/lifecycle/${lifecycleRule.id}`,
lifecycleUpdate lifecycleUpdate
) )
.then((res) => { .then((res) => {
@@ -288,95 +344,111 @@ const EditLifecycleConfiguration = ({
> >
<Grid container> <Grid container>
<Grid item xs={12} className={classes.formScrollable}> <Grid item xs={12} className={classes.formScrollable}>
<Grid item xs={12} className={classes.formFieldRow}> <Grid container spacing={1}>
<InputBoxWrapper <Grid item xs={12}>
id="id" <InputBoxWrapper
name="id" id="id"
label="Id" name="id"
value={lifecycle.id} label="Id"
onChange={() => {}} value={lifecycleRule.id}
disabled onChange={() => {}}
/> disabled
</Grid> />
<Grid item xs={12} className={classes.formFieldRow}> </Grid>
<FormSwitchWrapper <Grid item xs={12}>
label="Rule State" <FormSwitchWrapper
indicatorLabels={["Enabled", "Disabled"]} label="Status"
checked={enabled} indicatorLabels={["Enabled", "Disabled"]}
value={"user_enabled"} checked={enabled}
id="user-status" value={"user_enabled"}
name="user-status" id="rule_status"
onChange={(e) => { name="rule_status"
setEnabled(e.target.checked); onChange={(e) => {
}} setEnabled(e.target.checked);
/> }}
</Grid> />
<Grid item xs={12} className={classes.formFieldRow}> </Grid>
<fieldset className={classes.fieldGroup}> <Grid item xs={12}>
<legend className={classes.descriptionText}> <RadioGroupSelector
Lifecycle Configuration currentSelection={ilmType}
</legend> id="rule_type"
name="rule_type"
label="Rule Type"
selectorOptions={[
{ value: "expiry", label: "Expiry" },
{ value: "transition", label: "Transition" },
]}
onChange={() => {}}
disableOptions
/>
</Grid>
{ilmType === "expiry" && lifecycleRule.expiration?.days && (
<Grid item xs={12}> <Grid item xs={12}>
<RadioGroupSelector <InputBoxWrapper
currentSelection={ilmType} type="number"
id="quota_type" id="expiry_days"
name="quota_type" name="expiry_days"
label="ILM Rule" onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
selectorOptions={[ setExpiryDays(e.target.value);
{ value: "expiry", label: "Expiry" }, }}
{ value: "transition", label: "Transition" }, label="Expiry Days"
]} value={expiryDays}
onChange={() => {}} min="0"
disableOptions
/> />
</Grid> </Grid>
{ilmType === "expiry" ? ( )}
<Fragment>
<Grid item xs={12} className={classes.formFieldRow}>
<InputBoxWrapper
type="number"
id="expiry_days"
name="expiry_days"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setExpiryDays(e.target.value);
}}
label="Expiry Days"
value={expiryDays}
min="0"
/>
</Grid>
<Grid item xs={12} className={classes.formFieldRow}> {ilmType === "expiry" &&
<InputBoxWrapper lifecycleRule.expiration?.noncurrent_expiration_days && (
type="number" <Grid item xs={12}>
id="noncurrentversion_expiration_days" <InputBoxWrapper
name="noncurrentversion_expiration_days" type="number"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => { id="noncurrentversion_expiration_days"
setNCExpirationDays(e.target.value); name="noncurrentversion_expiration_days"
}} onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
label="Non-current Expiration Days" setNCExpirationDays(e.target.value);
value={NCExpirationDays} }}
min="0" label="Non-current Expiration Days"
/> value={NCExpirationDays}
</Grid> min="0"
</Fragment> />
) : ( </Grid>
)}
{ilmType === "transition" && lifecycleRule.transition?.days && (
<Fragment>
<Grid item xs={12}>
<InputBoxWrapper
type="number"
id="transition_days"
name="transition_days"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setTransitionDays(e.target.value);
}}
label="Transition Days"
value={transitionDays}
min="0"
/>
</Grid>
<Grid item xs={12}>
<SelectWrapper
label="Storage Class"
id="storage_class"
name="storage_class"
value={storageClass}
onChange={(e: SelectChangeEvent<string>) => {
setStorageClass(e.target.value as string);
}}
options={tiersList}
/>
</Grid>
</Fragment>
)}
{ilmType === "transition" &&
lifecycleRule.transition?.noncurrent_transition_days && (
<Fragment> <Fragment>
<Grid item xs={12} className={classes.formFieldRow}> <Grid item xs={12}>
<InputBoxWrapper
type="number"
id="transition_days"
name="transition_days"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setTransitionDays(e.target.value);
}}
label="Transition Days"
value={transitionDays}
min="0"
/>
</Grid>
<Grid item xs={12} className={classes.formFieldRow}>
<InputBoxWrapper <InputBoxWrapper
type="number" type="number"
id="noncurrentversion_transition_days" id="noncurrentversion_transition_days"
@@ -389,7 +461,8 @@ const EditLifecycleConfiguration = ({
min="0" min="0"
/> />
</Grid> </Grid>
<Grid item xs={12} className={classes.formFieldRow}>
<Grid item xs={12}>
<InputBoxWrapper <InputBoxWrapper
id="noncurrentversion_t_SC" id="noncurrentversion_t_SC"
name="noncurrentversion_t_SC" name="noncurrentversion_t_SC"
@@ -401,65 +474,69 @@ const EditLifecycleConfiguration = ({
value={NCTransitionSC} value={NCTransitionSC}
/> />
</Grid> </Grid>
<Grid item xs={12} className={classes.formFieldRow}>
<SelectWrapper
label="Storage Class"
id="storage_class"
name="storage_class"
value={storageClass}
onChange={(e: SelectChangeEvent<string>) => {
setStorageClass(e.target.value as string);
}}
options={tiersList}
/>
</Grid>
</Fragment> </Fragment>
)} )}
</fieldset> <Grid item xs={12} className={classes.formFieldRowAccordion}>
</Grid> <Accordion>
<Grid item xs={12} className={classes.formFieldRow}> <AccordionSummary>
<fieldset className={classes.fieldGroup}> <Typography>Filters</Typography>
<legend className={classes.descriptionText}> </AccordionSummary>
File Configuration
</legend>
<Grid item xs={12}> <AccordionDetails>
<InputBoxWrapper <Grid item xs={12}>
id="prefix" <InputBoxWrapper
name="prefix" id="prefix"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => { name="prefix"
setPrefix(e.target.value); onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
}} setPrefix(e.target.value);
label="Prefix" }}
value={prefix} label="Prefix"
/> value={prefix}
</Grid> />
<Grid item xs={12}> </Grid>
<QueryMultiSelector <Grid item xs={12}>
name="tags" <QueryMultiSelector
label="Tags" name="tags"
elements={tags} label="Tags"
onChange={(vl: string) => { elements={tags}
setTags(vl); onChange={(vl: string) => {
}} setTags(vl);
keyPlaceholder="Tag Key" }}
valuePlaceholder="Tag Value" keyPlaceholder="Tag Key"
withBorder valuePlaceholder="Tag Value"
/> withBorder
</Grid> />
<Grid item xs={12}> </Grid>
<FormSwitchWrapper </AccordionDetails>
value="expired_delete_marker" </Accordion>
id="expired_delete_marker" </Grid>
name="expired_delete_marker" {ilmType === "expiry" &&
checked={expiredObjectDM} lifecycleRule.expiration?.noncurrent_expiration_days && (
onChange={(event: React.ChangeEvent<HTMLInputElement>) => { <Grid item xs={12} className={classes.formFieldRowAccordion}>
setExpiredObjectDM(event.target.checked); <Accordion>
}} <AccordionSummary>
label={"Expired Object Delete Marker"} <Typography>Advanced</Typography>
/> </AccordionSummary>
</Grid>
</fieldset> <AccordionDetails>
<Grid item xs={12}>
<FormSwitchWrapper
value="expired_delete_marker"
id="expired_delete_marker"
name="expired_delete_marker"
checked={expiredObjectDM}
onChange={(
event: React.ChangeEvent<HTMLInputElement>
) => {
setExpiredObjectDM(event.target.checked);
}}
label={"Expired Object Delete Marker"}
/>
</Grid>
</AccordionDetails>
</Accordion>
</Grid>
)}
</Grid> </Grid>
</Grid> </Grid>
<Grid item xs={12} className={classes.modalButtonBar}> <Grid item xs={12} className={classes.modalButtonBar}>

View File

@@ -50,10 +50,6 @@ interface ICodeWrapper {
const styles = (theme: Theme) => const styles = (theme: Theme) =>
createStyles({ createStyles({
...fieldBasic, ...fieldBasic,
inputLabel: {
...fieldBasic.inputLabel,
fontWeight: "normal",
},
}); });
const langHighlight: Record<string, any> = { const langHighlight: Record<string, any> = {

View File

@@ -174,48 +174,40 @@ const FormSwitchWrapper = ({
return ( return (
<div className={classes.divContainer}> <div className={classes.divContainer}>
<Grid container alignItems={"center"}> <Grid container alignItems={"center"}>
<Grid item xs> <Grid item xs={12} sm={8} md={8}>
<Grid container> {label !== "" && (
<Grid <InputLabel htmlFor={id} className={classes.inputLabel}>
item <span>{label}</span>
xs={12} {tooltip !== "" && (
sm={description !== "" ? 4 : 10} <div className={classes.tooltipContainer}>
md={description !== "" ? 3 : 9} <Tooltip title={tooltip} placement="top-start">
> <div className={classes.tooltip}>
{label !== "" && ( <HelpIcon />
<InputLabel htmlFor={id} className={classes.inputLabel}>
<span>{label}</span>
{tooltip !== "" && (
<div className={classes.tooltipContainer}>
<Tooltip title={tooltip} placement="top-start">
<div className={classes.tooltip}>
<HelpIcon />
</div>
</Tooltip>
</div> </div>
)} </Tooltip>
</InputLabel> </div>
)} )}
</Grid> </InputLabel>
<Grid item xs={12} sm textAlign={"left"}> )}
{description !== "" && (
<Typography component="p" className={classes.fieldDescription}>
{description}
</Typography>
)}
</Grid>
</Grid>
</Grid> </Grid>
<Grid <Grid
item item
xs={12} xs={12}
sm={2} sm={4}
md={4}
textAlign={"right"} textAlign={"right"}
justifyContent={"end"}
className={classes.switchContainer} className={classes.switchContainer}
> >
{switchComponent} {switchComponent}
</Grid> </Grid>
{description !== "" && (
<Grid item xs={12} textAlign={"left"}>
<Typography component="p" className={classes.fieldDescription}>
{description}
</Typography>
</Grid>
)}
</Grid> </Grid>
</div> </div>
); );

View File

@@ -86,10 +86,6 @@ const styles = (theme: Theme) =>
top: 5, top: 5,
}, },
}, },
inputLabel: {
...fieldBasic.inputLabel,
fontWeight: "normal",
},
}); });
const inputStyles = makeStyles((theme: Theme) => const inputStyles = makeStyles((theme: Theme) =>

View File

@@ -51,12 +51,6 @@ const styles = (theme: Theme) =>
createStyles({ createStyles({
...fieldBasic, ...fieldBasic,
...tooltipHelper, ...tooltipHelper,
inputLabel: {
...fieldBasic.inputLabel,
"& span": {
fontWeight: "normal",
},
},
fieldContainer: { fieldContainer: {
display: "flex", display: "flex",
"@media (max-width: 600px)": { "@media (max-width: 600px)": {

View File

@@ -181,19 +181,24 @@ func addBucketLifecycle(ctx context.Context, client MinioClient, params user_api
} }
opts = ilm.LifecycleOptions{ opts = ilm.LifecycleOptions{
ID: id, ID: id,
Prefix: params.Body.Prefix, Prefix: params.Body.Prefix,
Status: !params.Body.Disable, Status: !params.Body.Disable,
IsTagsSet: params.Body.Tags != "", IsTagsSet: params.Body.Tags != "",
Tags: params.Body.Tags, Tags: params.Body.Tags,
TransitionDays: strconv.Itoa(int(params.Body.TransitionDays)), ExpiredObjectDeleteMarker: params.Body.ExpiredObjectDeleteMarker,
StorageClass: strings.ToUpper(params.Body.StorageClass), IsTransitionDaysSet: params.Body.TransitionDays != 0,
ExpiredObjectDeleteMarker: params.Body.ExpiredObjectDeleteMarker, IsNoncurrentVersionTransitionDaysSet: params.Body.NoncurrentversionTransitionDays != 0,
NoncurrentVersionTransitionDays: int(params.Body.NoncurrentversionTransitionDays),
NoncurrentVersionTransitionStorageClass: strings.ToUpper(params.Body.NoncurrentversionTransitionStorageClass),
IsTransitionDaysSet: params.Body.TransitionDays != 0,
IsNoncurrentVersionTransitionDaysSet: params.Body.NoncurrentversionTransitionDays != 0,
} }
if params.Body.NoncurrentversionTransitionDays > 0 {
opts.NoncurrentVersionTransitionDays = int(params.Body.NoncurrentversionTransitionDays)
opts.NoncurrentVersionTransitionStorageClass = strings.ToUpper(params.Body.NoncurrentversionTransitionStorageClass)
} else {
opts.TransitionDays = strconv.Itoa(int(params.Body.TransitionDays))
opts.StorageClass = strings.ToUpper(params.Body.StorageClass)
}
} else if params.Body.Type == models.AddBucketLifecycleTypeExpiry { } else if params.Body.Type == models.AddBucketLifecycleTypeExpiry {
// Verify if expiry items are set // Verify if expiry items are set
if params.Body.NoncurrentversionTransitionDays != 0 { if params.Body.NoncurrentversionTransitionDays != 0 {
@@ -205,14 +210,18 @@ func addBucketLifecycle(ctx context.Context, client MinioClient, params user_api
} }
opts = ilm.LifecycleOptions{ opts = ilm.LifecycleOptions{
ID: id, ID: id,
Prefix: params.Body.Prefix, Prefix: params.Body.Prefix,
Status: !params.Body.Disable, Status: !params.Body.Disable,
IsTagsSet: params.Body.Tags != "", IsTagsSet: params.Body.Tags != "",
Tags: params.Body.Tags, Tags: params.Body.Tags,
ExpiryDays: strconv.Itoa(int(params.Body.ExpiryDays)), ExpiredObjectDeleteMarker: params.Body.ExpiredObjectDeleteMarker,
ExpiredObjectDeleteMarker: params.Body.ExpiredObjectDeleteMarker, }
NoncurrentVersionExpirationDays: int(params.Body.NoncurrentversionExpirationDays),
if params.Body.NoncurrentversionExpirationDays > 0 {
opts.NoncurrentVersionExpirationDays = int(params.Body.NoncurrentversionExpirationDays)
} else {
opts.ExpiryDays = strconv.Itoa(int(params.Body.ExpiryDays))
} }
} else { } else {
@@ -271,19 +280,24 @@ func editBucketLifecycle(ctx context.Context, client MinioClient, params user_ap
} }
opts = ilm.LifecycleOptions{ opts = ilm.LifecycleOptions{
ID: id, ID: id,
Prefix: params.Body.Prefix, Prefix: params.Body.Prefix,
Status: !params.Body.Disable, Status: !params.Body.Disable,
IsTagsSet: params.Body.Tags != "", IsTagsSet: params.Body.Tags != "",
Tags: params.Body.Tags, Tags: params.Body.Tags,
TransitionDays: strconv.Itoa(int(params.Body.TransitionDays)), ExpiredObjectDeleteMarker: params.Body.ExpiredObjectDeleteMarker,
StorageClass: strings.ToUpper(params.Body.StorageClass), IsTransitionDaysSet: params.Body.TransitionDays != 0,
ExpiredObjectDeleteMarker: params.Body.ExpiredObjectDeleteMarker, IsNoncurrentVersionTransitionDaysSet: params.Body.NoncurrentversionTransitionDays != 0,
NoncurrentVersionTransitionDays: int(params.Body.NoncurrentversionTransitionDays),
NoncurrentVersionTransitionStorageClass: strings.ToUpper(params.Body.NoncurrentversionTransitionStorageClass),
IsTransitionDaysSet: params.Body.TransitionDays != 0,
IsNoncurrentVersionTransitionDaysSet: params.Body.NoncurrentversionTransitionDays != 0,
} }
if params.Body.NoncurrentversionTransitionDays > 0 {
opts.NoncurrentVersionTransitionDays = int(params.Body.NoncurrentversionTransitionDays)
opts.NoncurrentVersionTransitionStorageClass = strings.ToUpper(params.Body.NoncurrentversionTransitionStorageClass)
} else {
opts.TransitionDays = strconv.Itoa(int(params.Body.TransitionDays))
opts.StorageClass = strings.ToUpper(params.Body.StorageClass)
}
} else if *params.Body.Type == models.UpdateBucketLifecycleTypeExpiry { // Verify if expiry configuration is set } else if *params.Body.Type == models.UpdateBucketLifecycleTypeExpiry { // Verify if expiry configuration is set
if params.Body.NoncurrentversionTransitionDays != 0 { if params.Body.NoncurrentversionTransitionDays != 0 {
return errors.New("non current version Transition Days cannot be set when expiry is being configured") return errors.New("non current version Transition Days cannot be set when expiry is being configured")
@@ -294,14 +308,18 @@ func editBucketLifecycle(ctx context.Context, client MinioClient, params user_ap
} }
opts = ilm.LifecycleOptions{ opts = ilm.LifecycleOptions{
ID: id, ID: id,
Prefix: params.Body.Prefix, Prefix: params.Body.Prefix,
Status: !params.Body.Disable, Status: !params.Body.Disable,
IsTagsSet: params.Body.Tags != "", IsTagsSet: params.Body.Tags != "",
Tags: params.Body.Tags, Tags: params.Body.Tags,
ExpiryDays: strconv.Itoa(int(params.Body.ExpiryDays)), ExpiredObjectDeleteMarker: params.Body.ExpiredObjectDeleteMarker,
ExpiredObjectDeleteMarker: params.Body.ExpiredObjectDeleteMarker, }
NoncurrentVersionExpirationDays: int(params.Body.NoncurrentversionExpirationDays),
if params.Body.NoncurrentversionExpirationDays > 0 {
opts.NoncurrentVersionExpirationDays = int(params.Body.NoncurrentversionExpirationDays)
} else {
opts.ExpiryDays = strconv.Itoa(int(params.Body.ExpiryDays))
} }
} else { } else {