Added legal hold modal (#436)
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import get from "lodash/get";
|
||||
import * as reactMoment from "react-moment";
|
||||
import clsx from "clsx";
|
||||
@@ -33,9 +34,11 @@ import {
|
||||
containerForHeader,
|
||||
searchField,
|
||||
} from "../../../../Common/FormComponents/common/styleLibrary";
|
||||
import history from "../../../../../../history";
|
||||
import { IFileInfo } from "./types";
|
||||
import { removeRouteLevel } from "../../../../ObjectBrowser/actions";
|
||||
import { Route } from "../../../../ObjectBrowser/reducers";
|
||||
import { download } from "../utils";
|
||||
import history from "../../../../../../history";
|
||||
import api from "../../../../../../common/api";
|
||||
import PageHeader from "../../../../Common/PageHeader/PageHeader";
|
||||
import ShareIcon from "../../../../../../icons/ShareIcon";
|
||||
@@ -46,10 +49,9 @@ import PencilIcon from "../../../../Common/TableWrapper/TableActionIcons/PencilI
|
||||
import SetRetention from "./SetRetention";
|
||||
import BrowserBreadcrumbs from "../../../../ObjectBrowser/BrowserBreadcrumbs";
|
||||
import DeleteObject from "../ListObjects/DeleteObject";
|
||||
import { removeRouteLevel } from "../../../../ObjectBrowser/actions";
|
||||
import { connect } from "react-redux";
|
||||
import AddTagModal from "./AddTagModal";
|
||||
import DeleteTagModal from "./DeleteTagModal";
|
||||
import SetLegalHoldModal from "./SetLegalHoldModal";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -136,18 +138,6 @@ interface IObjectDetailsProps {
|
||||
removeRouteLevel: (newRoute: string) => any;
|
||||
}
|
||||
|
||||
interface IFileInfo {
|
||||
is_latest?: boolean;
|
||||
last_modified: string;
|
||||
legal_hold_status?: string;
|
||||
name: string;
|
||||
retention_mode?: string;
|
||||
retention_until_date?: string;
|
||||
size?: string;
|
||||
tags?: object;
|
||||
version_id: string;
|
||||
}
|
||||
|
||||
const emptyFile: IFileInfo = {
|
||||
is_latest: true,
|
||||
last_modified: "",
|
||||
@@ -171,6 +161,7 @@ const ObjectDetails = ({
|
||||
const [tagModalOpen, setTagModalOpen] = useState<boolean>(false);
|
||||
const [deleteTagModalOpen, setDeleteTagModalOpen] = useState<boolean>(false);
|
||||
const [selectedTag, setSelectedTag] = useState<[string, string]>(["", ""]);
|
||||
const [legalholdOpen, setLegalholdOpen] = useState<boolean>(false);
|
||||
const [actualInfo, setActualInfo] = useState<IFileInfo>(emptyFile);
|
||||
const [versions, setVersions] = useState<IFileInfo[]>([]);
|
||||
const [filterVersion, setFilterVersion] = useState<string>("");
|
||||
@@ -213,22 +204,18 @@ const ObjectDetails = ({
|
||||
|
||||
const openRetentionModal = () => {
|
||||
setRetentionModalOpen(true);
|
||||
console.log("open retention modal");
|
||||
};
|
||||
|
||||
const closeRetentionModal = () => {
|
||||
setRetentionModalOpen(false);
|
||||
console.log("close retention modal");
|
||||
};
|
||||
|
||||
const shareObject = () => {
|
||||
setShareFileModalOpen(true);
|
||||
console.log("share object");
|
||||
};
|
||||
|
||||
const closeShareModal = () => {
|
||||
setShareFileModalOpen(false);
|
||||
console.log("close share modal");
|
||||
};
|
||||
|
||||
const deleteTag = (tagKey: string, tagLabel: string) => {
|
||||
@@ -272,6 +259,14 @@ const ObjectDetails = ({
|
||||
}
|
||||
};
|
||||
|
||||
const closeLegalholdModal = (reload: boolean) => {
|
||||
setLegalholdOpen(false);
|
||||
|
||||
if (reload) {
|
||||
setLoadObjectData(true);
|
||||
}
|
||||
};
|
||||
|
||||
const closeDeleteTagModal = (reloadObjectData: boolean) => {
|
||||
setDeleteTagModalOpen(false);
|
||||
|
||||
@@ -325,6 +320,15 @@ const ObjectDetails = ({
|
||||
selectedTag={selectedTag}
|
||||
/>
|
||||
)}
|
||||
{legalholdOpen && (
|
||||
<SetLegalHoldModal
|
||||
open={legalholdOpen}
|
||||
closeModalAndRefresh={closeLegalholdModal}
|
||||
objectName={pathInBucket}
|
||||
bucketName={bucketName}
|
||||
actualInfo={actualInfo}
|
||||
/>
|
||||
)}
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.container}>
|
||||
<Grid item xs={12} className={classes.obTitleSection}>
|
||||
@@ -350,7 +354,7 @@ const ObjectDetails = ({
|
||||
size="small"
|
||||
className={classes.propertiesIcon}
|
||||
onClick={() => {
|
||||
console.log("open legal hold modal");
|
||||
setLegalholdOpen(true);
|
||||
}}
|
||||
>
|
||||
<PencilIcon active={true} />
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import get from "lodash/get";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import { modalBasic } from "../../../../Common/FormComponents/common/styleLibrary";
|
||||
import { IFileInfo } from "./types";
|
||||
import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper";
|
||||
import FormSwitchWrapper from "../../../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
import api from "../../../../../../common/api";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
objectName: {
|
||||
fontSize: 18,
|
||||
fontWeight: 700,
|
||||
marginBottom: 40,
|
||||
},
|
||||
buttonContainer: {
|
||||
textAlign: "right",
|
||||
},
|
||||
errorBlock: {
|
||||
color: "red",
|
||||
},
|
||||
...modalBasic,
|
||||
});
|
||||
|
||||
interface ISetRetentionProps {
|
||||
classes: any;
|
||||
open: boolean;
|
||||
closeModalAndRefresh: (reload: boolean) => void;
|
||||
objectName: string;
|
||||
bucketName: string;
|
||||
actualInfo: IFileInfo;
|
||||
}
|
||||
|
||||
const SetLegalHoldModal = ({
|
||||
classes,
|
||||
open,
|
||||
closeModalAndRefresh,
|
||||
objectName,
|
||||
bucketName,
|
||||
actualInfo,
|
||||
}: ISetRetentionProps) => {
|
||||
const [legalHoldEnabled, setLegalHoldEnabled] = useState<boolean>(false);
|
||||
const [isSaving, setIsSaving] = useState<boolean>(false);
|
||||
const [error, setError] = useState<string>("");
|
||||
const versionId = actualInfo.version_id;
|
||||
|
||||
useEffect(() => {
|
||||
const status = get(actualInfo, "legal_hold_status", "OFF");
|
||||
setLegalHoldEnabled(status === "ON");
|
||||
}, []);
|
||||
|
||||
const onSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setIsSaving(true);
|
||||
|
||||
api
|
||||
.invoke(
|
||||
"PUT",
|
||||
`/api/v1/buckets/${bucketName}/objects/legalhold?prefix=${objectName}&version_id=${versionId}`,
|
||||
{ status: legalHoldEnabled ? "enabled" : "disabled" }
|
||||
)
|
||||
.then((res) => {
|
||||
setIsSaving(false);
|
||||
closeModalAndRefresh(true);
|
||||
})
|
||||
.catch((error) => {
|
||||
setError(error);
|
||||
setIsSaving(false);
|
||||
});
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
setLegalHoldEnabled(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalWrapper
|
||||
title="Set Legal Hold"
|
||||
modalOpen={open}
|
||||
onClose={() => {
|
||||
resetForm();
|
||||
closeModalAndRefresh(false);
|
||||
}}
|
||||
>
|
||||
{error !== "" && <span className={classes.errorBlock}>{error}</span>}
|
||||
<Grid item xs={12} className={classes.objectName}>
|
||||
{objectName}
|
||||
</Grid>
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
onSubmit(e);
|
||||
}}
|
||||
>
|
||||
<Grid item xs={12}>
|
||||
<FormSwitchWrapper
|
||||
value="legalhold"
|
||||
id="legalhold"
|
||||
name="legalhold"
|
||||
checked={legalHoldEnabled}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setLegalHoldEnabled(!legalHoldEnabled);
|
||||
}}
|
||||
label={"Legal Hold Status"}
|
||||
indicatorLabels={["Enabled", "Disabled"]}
|
||||
tooltip={
|
||||
"To enable this feature you need to enable versioning on the bucket before creation"
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<button
|
||||
type="button"
|
||||
color="primary"
|
||||
className={classes.clearButton}
|
||||
onClick={resetForm}
|
||||
>
|
||||
Reset
|
||||
</button>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={isSaving}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
</ModalWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(SetLegalHoldModal);
|
||||
@@ -0,0 +1,27 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 interface IFileInfo {
|
||||
is_latest?: boolean;
|
||||
last_modified: string;
|
||||
legal_hold_status?: string;
|
||||
name: string;
|
||||
retention_mode?: string;
|
||||
retention_until_date?: string;
|
||||
size?: string;
|
||||
tags?: object;
|
||||
version_id: string;
|
||||
}
|
||||
Reference in New Issue
Block a user