Skip to content

Commit 7e6e64c

Browse files
authored
Add download objects api and integrate it with UI (#321)
1 parent 9007c7d commit 7e6e64c

File tree

15 files changed

+799
-104
lines changed

15 files changed

+799
-104
lines changed

portal-ui/bindata_assetfs.go

Lines changed: 99 additions & 99 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import { CreateIcon } from "../../../../icons";
3333
import { niceBytes } from "../../../../common/utils";
3434
import { AppState } from "../../../../store";
3535
import { connect } from "react-redux";
36-
import { logMessageReceived, logResetMessages } from "../../Logs/actions";
3736
import { addBucketOpen, addBucketReset } from "../actions";
3837
import {
3938
actionsTray,

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import {
2626
LinearProgress,
2727
} from "@material-ui/core";
2828
import api from "../../../../../../common/api";
29-
import { BucketObjectsList } from "../ListObjects/types";
3029
import Typography from "@material-ui/core/Typography";
3130

3231
const styles = (theme: Theme) =>
@@ -68,13 +67,14 @@ class DeleteObject extends React.Component<
6867
if (selectedObject.endsWith("/")) {
6968
recursive = true;
7069
}
70+
7171
this.setState({ deleteLoading: true }, () => {
7272
api
7373
.invoke(
7474
"DELETE",
7575
`/api/v1/buckets/${selectedBucket}/objects?path=${selectedObject}&recursive=${recursive}`
7676
)
77-
.then((res: BucketObjectsList) => {
77+
.then((res: any) => {
7878
this.setState(
7979
{
8080
deleteLoading: false,
@@ -142,10 +142,12 @@ class DeleteObject extends React.Component<
142142
</Button>
143143
<Button
144144
onClick={() => {
145-
this.removeRecord();
145+
this.setState({ deleteError: "" }, () => {
146+
this.removeRecord();
147+
});
146148
}}
147149
color="secondary"
148-
autoFocus
150+
disabled={deleteLoading}
149151
>
150152
Delete
151153
</Button>

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
searchField,
3737
} from "../../../../Common/FormComponents/common/styleLibrary";
3838
import PageHeader from "../../../../Common/PageHeader/PageHeader";
39+
import storage from "local-storage-fallback";
3940

4041
const styles = (theme: Theme) =>
4142
createStyles({
@@ -140,6 +141,38 @@ class ListObjects extends React.Component<
140141
});
141142
}
142143

144+
download(bucketName: string, objectName: string) {
145+
var anchor = document.createElement("a");
146+
document.body.appendChild(anchor);
147+
const token: string = storage.getItem("token")!;
148+
var xhr = new XMLHttpRequest();
149+
150+
xhr.open(
151+
"GET",
152+
`/api/v1/buckets/${bucketName}/objects/download?prefix=${objectName}`,
153+
true
154+
);
155+
xhr.setRequestHeader("Authorization", `Bearer ${token}`);
156+
xhr.responseType = "blob";
157+
158+
xhr.onload = function(e) {
159+
if (this.status == 200) {
160+
var blob = new Blob([this.response], {
161+
type: "octet/stream",
162+
});
163+
var blobUrl = window.URL.createObjectURL(blob);
164+
165+
anchor.href = blobUrl;
166+
anchor.download = objectName;
167+
168+
anchor.click();
169+
window.URL.revokeObjectURL(blobUrl);
170+
anchor.remove();
171+
}
172+
};
173+
xhr.send();
174+
}
175+
143176
bucketFilter(): void {}
144177

145178
render() {
@@ -160,7 +193,12 @@ class ListObjects extends React.Component<
160193
this.setState({ deleteOpen: true, selectedObject: object });
161194
};
162195

196+
const downloadObject = (object: string) => {
197+
this.download(selectedBucket, object);
198+
};
199+
163200
const tableActions = [
201+
{ type: "download", onClick: downloadObject, sendOnlyId: true },
164202
{ type: "delete", onClick: confirmDeleteObject, sendOnlyId: true },
165203
];
166204

portal-ui/src/screens/Console/Common/TableWrapper/TableActionButton.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import DeleteIcon from "./TableActionIcons/DeleteIcon";
2222
import DescriptionIcon from "./TableActionIcons/DescriptionIcon";
2323
import CloudIcon from "./TableActionIcons/CloudIcon";
2424
import ConsoleIcon from "./TableActionIcons/ConsoleIcon";
25+
import GetAppIcon from "@material-ui/icons/GetApp";
26+
import SvgIcon from "@material-ui/core/SvgIcon";
2527
import { Link } from "react-router-dom";
2628

2729
interface IActionButton {
@@ -48,6 +50,10 @@ const defineIcon = (type: string, selected: boolean) => {
4850
return <CloudIcon active={selected} />;
4951
case "console":
5052
return <ConsoleIcon active={selected} />;
53+
case "download":
54+
return (
55+
<SvgIcon component={GetAppIcon} fontSize="small" color="primary" />
56+
);
5157
}
5258

5359
return null;

restapi/client.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package restapi
1919
import (
2020
"context"
2121
"fmt"
22+
"io"
2223
"strings"
2324
"time"
2425

@@ -136,6 +137,7 @@ type MCClient interface {
136137
watch(ctx context.Context, options mc.WatchOptions) (*mc.WatchObject, *probe.Error)
137138
remove(ctx context.Context, isIncomplete, isRemoveBucket, isBypass bool, contentCh <-chan *mc.ClientContent) <-chan *probe.Error
138139
list(ctx context.Context, opts mc.ListOptions) <-chan *mc.ClientContent
140+
get(ctx context.Context, opts mc.GetOptions) (io.ReadCloser, *probe.Error)
139141
}
140142

141143
// Interface implementation
@@ -172,6 +174,10 @@ func (c mcClient) list(ctx context.Context, opts mc.ListOptions) <-chan *mc.Clie
172174
return c.client.List(ctx, opts)
173175
}
174176

177+
func (c mcClient) get(ctx context.Context, opts mc.GetOptions) (io.ReadCloser, *probe.Error) {
178+
return c.client.Get(ctx, opts)
179+
}
180+
175181
// ConsoleCredentials interface with all functions to be implemented
176182
// by mock when testing, it should include all needed consoleCredentials.Login api calls
177183
// that are used within this project.

restapi/embedded_spec.go

Lines changed: 80 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

restapi/operations/console_api.go

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

restapi/operations/user_api/download_object.go

Lines changed: 90 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)