mirror of
https://github.com/OpenMaxIO/openmaxio-object-browser
synced 2026-07-01 07:41:18 -07:00
The new doc site has launched, and all docs have new URLs. This PR updates the documentation URLs in the Console to point to the new locations.
351 lines
11 KiB
TypeScript
351 lines
11 KiB
TypeScript
// This file is part of MinIO Console Server
|
|
// Copyright (c) 2021 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 { useSelector } from "react-redux";
|
|
import { Theme } from "@mui/material/styles";
|
|
import createStyles from "@mui/styles/createStyles";
|
|
import withStyles from "@mui/styles/withStyles";
|
|
import get from "lodash/get";
|
|
import Grid from "@mui/material/Grid";
|
|
import { LifeCycleItem } from "../types";
|
|
import { AddIcon, TiersIcon } from "../../../../icons";
|
|
import {
|
|
actionsTray,
|
|
searchField,
|
|
} from "../../Common/FormComponents/common/styleLibrary";
|
|
import { ErrorResponseHandler } from "../../../../common/types";
|
|
import api from "../../../../common/api";
|
|
import EditLifecycleConfiguration from "./EditLifecycleConfiguration";
|
|
import AddLifecycleModal from "./AddLifecycleModal";
|
|
import TableWrapper from "../../Common/TableWrapper/TableWrapper";
|
|
import HelpBox from "../../../../common/HelpBox";
|
|
import PanelTitle from "../../Common/PanelTitle/PanelTitle";
|
|
import {
|
|
hasPermission,
|
|
SecureComponent,
|
|
} from "../../../../common/SecureComponent";
|
|
import { IAM_SCOPES } from "../../../../common/SecureComponent/permissions";
|
|
import DeleteBucketLifecycleRule from "./DeleteBucketLifecycleRule";
|
|
import { selBucketDetailsLoading } from "./bucketDetailsSlice";
|
|
import { useParams } from "react-router-dom";
|
|
import TooltipWrapper from "../../Common/TooltipWrapper/TooltipWrapper";
|
|
import { Button } from "mds";
|
|
|
|
const styles = (theme: Theme) =>
|
|
createStyles({
|
|
...searchField,
|
|
...actionsTray,
|
|
twHeight: {
|
|
minHeight: 400,
|
|
},
|
|
});
|
|
|
|
interface IBucketLifecyclePanelProps {
|
|
classes: any;
|
|
}
|
|
|
|
const BucketLifecyclePanel = ({ classes }: IBucketLifecyclePanelProps) => {
|
|
const loadingBucket = useSelector(selBucketDetailsLoading);
|
|
const params = useParams();
|
|
|
|
const [loadingLifecycle, setLoadingLifecycle] = useState<boolean>(true);
|
|
const [lifecycleRecords, setLifecycleRecords] = useState<LifeCycleItem[]>([]);
|
|
const [addLifecycleOpen, setAddLifecycleOpen] = useState<boolean>(false);
|
|
const [editLifecycleOpen, setEditLifecycleOpen] = useState<boolean>(false);
|
|
const [selectedLifecycleRule, setSelectedLifecycleRule] =
|
|
useState<LifeCycleItem | null>(null);
|
|
const [deleteLifecycleOpen, setDeleteLifecycleOpen] =
|
|
useState<boolean>(false);
|
|
const [selectedID, setSelectedID] = useState<string | null>(null);
|
|
|
|
const bucketName = params.bucketName || "";
|
|
|
|
const displayLifeCycleRules = hasPermission(bucketName, [
|
|
IAM_SCOPES.S3_GET_LIFECYCLE_CONFIGURATION,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
if (loadingBucket) {
|
|
setLoadingLifecycle(true);
|
|
}
|
|
}, [loadingBucket, setLoadingLifecycle]);
|
|
|
|
useEffect(() => {
|
|
if (loadingLifecycle) {
|
|
if (displayLifeCycleRules) {
|
|
api
|
|
.invoke("GET", `/api/v1/buckets/${bucketName}/lifecycle`)
|
|
.then((res: any) => {
|
|
const records = get(res, "lifecycle", []);
|
|
|
|
setLifecycleRecords(records || []);
|
|
setLoadingLifecycle(false);
|
|
})
|
|
.catch((err: ErrorResponseHandler) => {
|
|
console.error(err);
|
|
setLifecycleRecords([]);
|
|
setLoadingLifecycle(false);
|
|
});
|
|
} else {
|
|
setLoadingLifecycle(false);
|
|
}
|
|
}
|
|
}, [
|
|
loadingLifecycle,
|
|
setLoadingLifecycle,
|
|
bucketName,
|
|
displayLifeCycleRules,
|
|
]);
|
|
|
|
const closeEditLCAndRefresh = (refresh: boolean) => {
|
|
setEditLifecycleOpen(false);
|
|
setSelectedLifecycleRule(null);
|
|
if (refresh) {
|
|
setLoadingLifecycle(true);
|
|
}
|
|
};
|
|
|
|
const closeAddLCAndRefresh = (refresh: boolean) => {
|
|
setAddLifecycleOpen(false);
|
|
if (refresh) {
|
|
setLoadingLifecycle(true);
|
|
}
|
|
};
|
|
|
|
const closeDelLCRefresh = (refresh: boolean) => {
|
|
setDeleteLifecycleOpen(false);
|
|
setSelectedID(null);
|
|
|
|
if (refresh) {
|
|
setLoadingLifecycle(true);
|
|
}
|
|
};
|
|
|
|
const renderStorageClass = (objectST: any) => {
|
|
let stClass = get(objectST, "transition.storage_class", "");
|
|
stClass = get(objectST, "transition.noncurrent_storage_class", stClass);
|
|
|
|
return stClass;
|
|
};
|
|
|
|
const lifecycleColumns = [
|
|
{
|
|
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",
|
|
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",
|
|
elementKey: "status",
|
|
},
|
|
];
|
|
|
|
const lifecycleActions = [
|
|
{
|
|
type: "view",
|
|
|
|
onClick(valueToSend: any): any {
|
|
setSelectedLifecycleRule(valueToSend);
|
|
setEditLifecycleOpen(true);
|
|
},
|
|
},
|
|
{
|
|
type: "delete",
|
|
onClick(valueToDelete: string): any {
|
|
setSelectedID(valueToDelete);
|
|
setDeleteLifecycleOpen(true);
|
|
},
|
|
sendOnlyId: true,
|
|
},
|
|
];
|
|
|
|
return (
|
|
<Fragment>
|
|
{editLifecycleOpen && selectedLifecycleRule && (
|
|
<EditLifecycleConfiguration
|
|
open={editLifecycleOpen}
|
|
closeModalAndRefresh={closeEditLCAndRefresh}
|
|
selectedBucket={bucketName}
|
|
lifecycleRule={selectedLifecycleRule}
|
|
/>
|
|
)}
|
|
{addLifecycleOpen && (
|
|
<AddLifecycleModal
|
|
open={addLifecycleOpen}
|
|
bucketName={bucketName}
|
|
closeModalAndRefresh={closeAddLCAndRefresh}
|
|
/>
|
|
)}
|
|
{deleteLifecycleOpen && selectedID && (
|
|
<DeleteBucketLifecycleRule
|
|
id={selectedID}
|
|
bucket={bucketName}
|
|
deleteOpen={deleteLifecycleOpen}
|
|
onCloseAndRefresh={closeDelLCRefresh}
|
|
/>
|
|
)}
|
|
<Grid container>
|
|
<Grid item xs={12} className={classes.actionsTray}>
|
|
<PanelTitle>Lifecycle Rules</PanelTitle>
|
|
<SecureComponent
|
|
scopes={[
|
|
IAM_SCOPES.S3_PUT_LIFECYCLE_CONFIGURATION,
|
|
IAM_SCOPES.ADMIN_LIST_TIERS,
|
|
]}
|
|
resource={bucketName}
|
|
matchAll
|
|
errorProps={{ disabled: true }}
|
|
>
|
|
<TooltipWrapper tooltip={"Add Lifecycle Rule"}>
|
|
<Button
|
|
id={"add-bucket-lifecycle-rule"}
|
|
onClick={() => {
|
|
setAddLifecycleOpen(true);
|
|
}}
|
|
label={"Add Lifecycle Rule"}
|
|
icon={<AddIcon />}
|
|
variant={"callAction"}
|
|
/>
|
|
</TooltipWrapper>
|
|
</SecureComponent>
|
|
</Grid>
|
|
<Grid item xs={12}>
|
|
<SecureComponent
|
|
scopes={[IAM_SCOPES.S3_GET_LIFECYCLE_CONFIGURATION]}
|
|
resource={bucketName}
|
|
errorProps={{ disabled: true }}
|
|
>
|
|
<TableWrapper
|
|
itemActions={lifecycleActions}
|
|
columns={lifecycleColumns}
|
|
isLoading={loadingLifecycle}
|
|
records={lifecycleRecords}
|
|
entityName="Lifecycle"
|
|
customEmptyMessage="There are no Lifecycle rules yet"
|
|
idField="id"
|
|
customPaperHeight={classes.twHeight}
|
|
/>
|
|
</SecureComponent>
|
|
</Grid>
|
|
{!loadingLifecycle && (
|
|
<Grid item xs={12}>
|
|
<br />
|
|
<HelpBox
|
|
title={"Lifecycle Rules"}
|
|
iconComponent={<TiersIcon />}
|
|
help={
|
|
<Fragment>
|
|
MinIO Object Lifecycle Management allows creating rules for
|
|
time or date based automatic transition or expiry of objects.
|
|
For object transition, MinIO automatically moves the object to
|
|
a configured remote storage tier.
|
|
<br />
|
|
<br />
|
|
You can learn more at our{" "}
|
|
<a
|
|
href="https://min.io/docs/minio/linux/administration/object-management/object-lifecycle-management.html?ref=con"
|
|
target="_blank"
|
|
rel="noreferrer"
|
|
>
|
|
documentation
|
|
</a>
|
|
.
|
|
</Fragment>
|
|
}
|
|
/>
|
|
</Grid>
|
|
)}
|
|
</Grid>
|
|
</Fragment>
|
|
);
|
|
};
|
|
|
|
export default withStyles(styles)(BucketLifecyclePanel);
|