diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ObjectDetails.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ObjectDetails.tsx
index d56f8e4ab..f11087955 100644
--- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ObjectDetails.tsx
+++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ObjectDetails.tsx
@@ -15,6 +15,7 @@
// along with this program. If not, see .
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(false);
const [deleteTagModalOpen, setDeleteTagModalOpen] = useState(false);
const [selectedTag, setSelectedTag] = useState<[string, string]>(["", ""]);
+ const [legalholdOpen, setLegalholdOpen] = useState(false);
const [actualInfo, setActualInfo] = useState(emptyFile);
const [versions, setVersions] = useState([]);
const [filterVersion, setFilterVersion] = useState("");
@@ -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 && (
+
+ )}
@@ -350,7 +354,7 @@ const ObjectDetails = ({
size="small"
className={classes.propertiesIcon}
onClick={() => {
- console.log("open legal hold modal");
+ setLegalholdOpen(true);
}}
>
diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetLegalHoldModal.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetLegalHoldModal.tsx
new file mode 100644
index 000000000..612de79fc
--- /dev/null
+++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetLegalHoldModal.tsx
@@ -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(false);
+ const [isSaving, setIsSaving] = useState(false);
+ const [error, setError] = useState("");
+ 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 (
+ {
+ resetForm();
+ closeModalAndRefresh(false);
+ }}
+ >
+ {error !== "" && {error}}
+
+ {objectName}
+
+
+
+ );
+};
+
+export default withStyles(styles)(SetLegalHoldModal);
diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/types.ts b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/types.ts
new file mode 100644
index 000000000..e4f243f9c
--- /dev/null
+++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/types.ts
@@ -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 .
+
+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;
+}