16
16
17
17
import { createStyles , Theme , withStyles } from "@material-ui/core/styles" ;
18
18
import Grid from "@material-ui/core/Grid" ;
19
- import { Button } from "@material-ui/core" ;
20
- import Typography from "@material-ui/core/Typography" ;
21
19
import TextField from "@material-ui/core/TextField" ;
22
20
import InputAdornment from "@material-ui/core/InputAdornment" ;
23
21
import SearchIcon from "@material-ui/icons/Search" ;
24
22
import { BucketObject , BucketObjectsList } from "./types" ;
25
23
import api from "../../../../../../common/api" ;
26
- import React , { useEffect , useState } from "react" ;
24
+ import React from "react" ;
27
25
import TableWrapper from "../../../../Common/TableWrapper/TableWrapper" ;
28
- import { MinTablePaginationActions } from "../../../../../../common/MinTablePaginationActions" ;
29
- import { CreateIcon } from "../../.././../../../icons" ;
30
26
import { niceBytes } from "../../../../../../common/utils" ;
31
- import Moment from "react-moment" ;
32
27
import DeleteObject from "./DeleteObject" ;
28
+
33
29
import {
34
30
actionsTray ,
35
31
containerForHeader ,
36
32
searchField ,
37
33
} from "../../../../Common/FormComponents/common/styleLibrary" ;
38
34
import PageHeader from "../../../../Common/PageHeader/PageHeader" ;
39
35
import storage from "local-storage-fallback" ;
36
+ import { isNullOrUndefined } from "util" ;
37
+ import { Button , Input } from "@material-ui/core" ;
38
+ import * as reactMoment from "react-moment" ;
39
+ import { CreateIcon } from "../../../../../../icons" ;
40
+ import Snackbar from "@material-ui/core/Snackbar" ;
40
41
41
42
const styles = ( theme : Theme ) =>
42
43
createStyles ( {
@@ -88,6 +89,8 @@ interface IListObjectsState {
88
89
selectedObject : string ;
89
90
selectedBucket : string ;
90
91
filterObjects : string ;
92
+ openSnackbar : boolean ;
93
+ snackBarMessage : string ;
91
94
}
92
95
93
96
class ListObjects extends React . Component <
@@ -104,6 +107,8 @@ class ListObjects extends React.Component<
104
107
selectedObject : "" ,
105
108
selectedBucket : "" ,
106
109
filterObjects : "" ,
110
+ openSnackbar : false ,
111
+ snackBarMessage : "" ,
107
112
} ;
108
113
109
114
fetchRecords = ( ) => {
@@ -141,6 +146,73 @@ class ListObjects extends React.Component<
141
146
} ) ;
142
147
}
143
148
149
+ showSnackBarMessage ( text : string ) {
150
+ this . setState ( { openSnackbar : true , snackBarMessage : text } ) ;
151
+ }
152
+
153
+ closeSnackBar ( ) {
154
+ this . setState ( { openSnackbar : false , snackBarMessage : `` } ) ;
155
+ }
156
+
157
+ upload ( e : any , bucketName : string , path : string ) {
158
+ let listObjects = this ;
159
+ if ( isNullOrUndefined ( e ) || isNullOrUndefined ( e . target ) ) {
160
+ return ;
161
+ }
162
+ const token : string = storage . getItem ( "token" ) ! ;
163
+ e . preventDefault ( ) ;
164
+ let file = e . target . files [ 0 ] ;
165
+ const fileName = file . name ;
166
+
167
+ const objectName = `${ path } ${ fileName } ` ;
168
+ let uploadUrl = `/api/v1/buckets/${ bucketName } /objects/upload?prefix=${ objectName } ` ;
169
+ let xhr = new XMLHttpRequest ( ) ;
170
+
171
+ xhr . open ( "POST" , uploadUrl , true ) ;
172
+ xhr . setRequestHeader ( "Authorization" , `Bearer ${ token } ` ) ;
173
+
174
+ xhr . withCredentials = false ;
175
+ xhr . onload = function ( event ) {
176
+ // TODO: handle status
177
+ if ( xhr . status == 401 || xhr . status == 403 ) {
178
+ listObjects . showSnackBarMessage (
179
+ "An error occurred while uploading the file."
180
+ ) ;
181
+ }
182
+ if ( xhr . status == 500 ) {
183
+ listObjects . showSnackBarMessage (
184
+ "An error occurred while uploading the file."
185
+ ) ;
186
+ }
187
+ if ( xhr . status == 200 ) {
188
+ listObjects . showSnackBarMessage ( "Object uploaded successfully." ) ;
189
+ listObjects . fetchRecords ( ) ;
190
+ }
191
+ } ;
192
+
193
+ xhr . upload . addEventListener ( "error" , ( event ) => {
194
+ // TODO: handle error
195
+ this . showSnackBarMessage ( "An error occurred while uploading the file." ) ;
196
+ } ) ;
197
+
198
+ xhr . upload . addEventListener ( "progress" , ( event ) => {
199
+ // TODO: handle progress with event.loaded, event.total
200
+ } ) ;
201
+
202
+ xhr . onerror = ( ) => {
203
+ listObjects . showSnackBarMessage (
204
+ "An error occurred while uploading the file."
205
+ ) ;
206
+ } ;
207
+
208
+ var formData = new FormData ( ) ;
209
+ var blobFile = new Blob ( [ file ] ) ;
210
+
211
+ formData . append ( "upfile" , blobFile ) ;
212
+ xhr . send ( formData ) ;
213
+ e . target . value = null ;
214
+ }
215
+
144
216
download ( bucketName : string , objectName : string ) {
145
217
var anchor = document . createElement ( "a" ) ;
146
218
document . body . appendChild ( anchor ) ;
@@ -184,9 +256,11 @@ class ListObjects extends React.Component<
184
256
selectedBucket,
185
257
deleteOpen,
186
258
filterObjects,
259
+ snackBarMessage,
260
+ openSnackbar,
187
261
} = this . state ;
188
262
const displayParsedDate = ( date : string ) => {
189
- return < Moment > { date } </ Moment > ;
263
+ return < reactMoment . default > { date } </ reactMoment . default > ;
190
264
} ;
191
265
192
266
const confirmDeleteObject = ( object : string ) => {
@@ -197,6 +271,25 @@ class ListObjects extends React.Component<
197
271
this . download ( selectedBucket , object ) ;
198
272
} ;
199
273
274
+ const uploadObject = ( e : any ) : void => {
275
+ // TODO: handle deeper paths/folders
276
+ let file = e . target . files [ 0 ] ;
277
+ this . showSnackBarMessage ( `Uploading: ${ file . name } ` ) ;
278
+ this . upload ( e , selectedBucket , "" ) ;
279
+ } ;
280
+
281
+ const snackBarAction = (
282
+ < Button
283
+ color = "secondary"
284
+ size = "small"
285
+ onClick = { ( ) => {
286
+ this . closeSnackBar ( ) ;
287
+ } }
288
+ >
289
+ Dismiss
290
+ </ Button >
291
+ ) ;
292
+
200
293
const tableActions = [
201
294
{ type : "download" , onClick : downloadObject , sendOnlyId : true } ,
202
295
{ type : "delete" , onClick : confirmDeleteObject , sendOnlyId : true } ,
@@ -226,6 +319,11 @@ class ListObjects extends React.Component<
226
319
} }
227
320
/>
228
321
) }
322
+ < Snackbar
323
+ open = { openSnackbar }
324
+ message = { snackBarMessage }
325
+ action = { snackBarAction }
326
+ />
229
327
< PageHeader label = "Objects" />
230
328
< Grid container >
231
329
< Grid item xs = { 12 } className = { classes . container } >
@@ -249,6 +347,23 @@ class ListObjects extends React.Component<
249
347
) ,
250
348
} }
251
349
/>
350
+
351
+ < >
352
+ < Button
353
+ variant = "contained"
354
+ color = "primary"
355
+ startIcon = { < CreateIcon /> }
356
+ component = "label"
357
+ >
358
+ Upload Object
359
+ < Input
360
+ type = "file"
361
+ onChange = { ( e ) => uploadObject ( e ) }
362
+ id = "file-input"
363
+ style = { { display : "none" } }
364
+ />
365
+ </ Button >
366
+ </ >
252
367
</ Grid >
253
368
< Grid item xs = { 12 } >
254
369
< br />
0 commit comments