Skip to content

Commit b21123e

Browse files
bexsoftBenjamin Perezdvaldivia
authored
Connected delete & download buttons for object details (#399)
Co-authored-by: Benjamin Perez <[email protected]> Co-authored-by: Daniel Valdivia <[email protected]>
1 parent f1db949 commit b21123e

File tree

4 files changed

+126
-49
lines changed

4 files changed

+126
-49
lines changed

portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ListObjects.tsx

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import { connect } from "react-redux";
5151
import { ObjectBrowserState, Route } from "../../../../ObjectBrowser/reducers";
5252
import CreateFolderModal from "./CreateFolderModal";
5353
import UploadFile from "../../../../../../icons/UploadFile";
54+
import { download } from "../utils";
5455

5556
const commonIcon = {
5657
backgroundRepeat: "no-repeat",
@@ -297,37 +298,6 @@ const ListObjects = ({
297298
e.target.value = null;
298299
};
299300

300-
const download = (bucketName: string, objectName: string) => {
301-
const anchor = document.createElement("a");
302-
document.body.appendChild(anchor);
303-
const token: string = storage.getItem("token")!;
304-
const xhr = new XMLHttpRequest();
305-
306-
xhr.open(
307-
"GET",
308-
`/api/v1/buckets/${bucketName}/objects/download?prefix=${objectName}`,
309-
true
310-
);
311-
xhr.responseType = "blob";
312-
313-
xhr.onload = function (e) {
314-
if (this.status === 200) {
315-
const blob = new Blob([this.response], {
316-
type: "octet/stream",
317-
});
318-
const blobUrl = window.URL.createObjectURL(blob);
319-
320-
anchor.href = blobUrl;
321-
anchor.download = objectName;
322-
323-
anchor.click();
324-
window.URL.revokeObjectURL(blobUrl);
325-
anchor.remove();
326-
}
327-
};
328-
xhr.send();
329-
};
330-
331301
const displayParsedDate = (date: string) => {
332302
return <reactMoment.default>{date}</reactMoment.default>;
333303
};

portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ObjectRouting.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
// This file is part of MinIO Console Server
2+
// Copyright (c) 2020 MinIO, Inc.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
117
import React, { useEffect } from "react";
218
import ListObjects from "./ListObjects";
319
import ObjectDetails from "../ObjectDetails/ObjectDetails";

portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ObjectDetails.tsx

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
1+
// This file is part of MinIO Console Server
2+
// Copyright (c) 2020 MinIO, Inc.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
117
import React, { useState, useEffect } from "react";
2-
import { withRouter } from "react-router-dom";
18+
import get from "lodash/get";
319
import * as reactMoment from "react-moment";
420
import clsx from "clsx";
521
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
@@ -17,6 +33,10 @@ import {
1733
containerForHeader,
1834
searchField,
1935
} from "../../../../Common/FormComponents/common/styleLibrary";
36+
import history from "../../../../../../history";
37+
import { Route } from "../../../../ObjectBrowser/reducers";
38+
import { download } from "../utils";
39+
import api from "../../../../../../common/api";
2040
import PageHeader from "../../../../Common/PageHeader/PageHeader";
2141
import ShareIcon from "../../../../../../icons/ShareIcon";
2242
import DownloadIcon from "../../../../../../icons/DownloadIcon";
@@ -25,13 +45,9 @@ import TableWrapper from "../../../../Common/TableWrapper/TableWrapper";
2545
import PencilIcon from "../../../../Common/TableWrapper/TableActionIcons/PencilIcon";
2646
import SetRetention from "./SetRetention";
2747
import BrowserBreadcrumbs from "../../../../ObjectBrowser/BrowserBreadcrumbs";
28-
import { Button, Input } from "@material-ui/core";
29-
import { CreateIcon } from "../../../../../../icons";
30-
import UploadFile from "../../../../../../icons/UploadFile";
48+
import DeleteObject from "../ListObjects/DeleteObject";
49+
import { removeRouteLevel } from "../../../../ObjectBrowser/actions";
3150
import { connect } from "react-redux";
32-
import api from "../../../../../../common/api";
33-
import { ObjectBrowserState, Route } from "../../../../ObjectBrowser/reducers";
34-
import get from "lodash/get";
3551

3652
const styles = (theme: Theme) =>
3753
createStyles({
@@ -115,6 +131,7 @@ const styles = (theme: Theme) =>
115131
interface IObjectDetailsProps {
116132
classes: any;
117133
routesList: Route[];
134+
removeRouteLevel: (newRoute: string) => any;
118135
}
119136

120137
interface IFileInfo {
@@ -141,12 +158,17 @@ const emptyFile: IFileInfo = {
141158
version_id: "",
142159
};
143160

144-
const ObjectDetails = ({ classes, routesList }: IObjectDetailsProps) => {
161+
const ObjectDetails = ({
162+
classes,
163+
routesList,
164+
removeRouteLevel,
165+
}: IObjectDetailsProps) => {
145166
const [shareFileModalOpen, setShareFileModalOpen] = useState<boolean>(false);
146167
const [retentionModalOpen, setRetentionModalOpen] = useState<boolean>(false);
147168
const [actualInfo, setActualInfo] = useState<IFileInfo>(emptyFile);
148169
const [versions, setVersions] = useState<IFileInfo[]>([]);
149170
const [filterVersion, setFilterVersion] = useState<string>("");
171+
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
150172
const [error, setError] = useState<string>("");
151173

152174
const currentItem = routesList[routesList.length - 1];
@@ -197,12 +219,8 @@ const ObjectDetails = ({ classes, routesList }: IObjectDetailsProps) => {
197219
console.log("delete tag");
198220
};
199221

200-
const downloadObject = () => {
201-
console.log("download object");
202-
};
203-
204-
const confirmDeleteObject = () => {
205-
console.log("confirm delete object");
222+
const downloadObject = (path: string) => {
223+
download(bucketName, path);
206224
};
207225

208226
const tableActions = [
@@ -218,6 +236,17 @@ const ObjectDetails = ({ classes, routesList }: IObjectDetailsProps) => {
218236
return <reactMoment.default>{date}</reactMoment.default>;
219237
};
220238

239+
const closeDeleteModal = (redirectBack: boolean) => {
240+
setDeleteOpen(false);
241+
242+
if (redirectBack) {
243+
const newPath = allPathData.slice(0, -1).join("/");
244+
245+
removeRouteLevel(newPath);
246+
history.push(newPath);
247+
}
248+
};
249+
221250
return (
222251
<React.Fragment>
223252
<PageHeader label={"Object Browser"} />
@@ -234,6 +263,14 @@ const ObjectDetails = ({ classes, routesList }: IObjectDetailsProps) => {
234263
objectName={objectName}
235264
/>
236265
)}
266+
{deleteOpen && (
267+
<DeleteObject
268+
deleteOpen={deleteOpen}
269+
selectedBucket={bucketName}
270+
selectedObject={pathInBucket}
271+
closeDeleteModalAndRefresh={closeDeleteModal}
272+
/>
273+
)}
237274
<Grid container>
238275
<Grid item xs={12} className={classes.container}>
239276
<Grid item xs={12} className={classes.obTitleSection}>
@@ -307,11 +344,11 @@ const ObjectDetails = ({ classes, routesList }: IObjectDetailsProps) => {
307344
<div className={classes.actionsIconContainer}>
308345
<IconButton
309346
color="primary"
310-
aria-label="download/upload"
347+
aria-label="download"
311348
size="small"
312349
className={classes.actionsIcon}
313350
onClick={() => {
314-
console.log("download/upload");
351+
downloadObject(pathInBucket);
315352
}}
316353
>
317354
<DownloadIcon />
@@ -324,7 +361,7 @@ const ObjectDetails = ({ classes, routesList }: IObjectDetailsProps) => {
324361
size="small"
325362
className={classes.actionsIcon}
326363
onClick={() => {
327-
console.log("delete");
364+
setDeleteOpen(true);
328365
}}
329366
>
330367
<DeleteIcon />
@@ -404,4 +441,10 @@ const ObjectDetails = ({ classes, routesList }: IObjectDetailsProps) => {
404441
);
405442
};
406443

407-
export default withStyles(styles)(ObjectDetails);
444+
const mapDispatchToProps = {
445+
removeRouteLevel,
446+
};
447+
448+
const connector = connect(null, mapDispatchToProps);
449+
450+
export default connector(withStyles(styles)(ObjectDetails));
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// This file is part of MinIO Console Server
2+
// Copyright (c) 2020 MinIO, Inc.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
import storage from "local-storage-fallback";
18+
19+
export const download = (bucketName: string, objectName: string) => {
20+
const anchor = document.createElement("a");
21+
document.body.appendChild(anchor);
22+
const token: string = storage.getItem("token")!;
23+
const xhr = new XMLHttpRequest();
24+
25+
xhr.open(
26+
"GET",
27+
`/api/v1/buckets/${bucketName}/objects/download?prefix=${objectName}`,
28+
true
29+
);
30+
xhr.responseType = "blob";
31+
32+
xhr.onload = function (e) {
33+
if (this.status === 200) {
34+
const blob = new Blob([this.response], {
35+
type: "octet/stream",
36+
});
37+
const blobUrl = window.URL.createObjectURL(blob);
38+
39+
anchor.href = blobUrl;
40+
anchor.download = objectName;
41+
42+
anchor.click();
43+
window.URL.revokeObjectURL(blobUrl);
44+
anchor.remove();
45+
}
46+
};
47+
xhr.send();
48+
};

0 commit comments

Comments
 (0)