Added buckets-object browser view (#307)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
@@ -49,6 +49,7 @@ interface IColumns {
|
||||
elementKey: string;
|
||||
sortable?: boolean;
|
||||
renderFunction?: (input: any) => any;
|
||||
globalClass?: any;
|
||||
}
|
||||
|
||||
interface IPaginatorConfig {
|
||||
@@ -161,7 +162,10 @@ const styles = (theme: Theme) =>
|
||||
const titleColumnsMap = (columns: IColumns[]) => {
|
||||
return columns.map((column: IColumns, index: number) => {
|
||||
return (
|
||||
<TableCell key={`tbCT-${column.elementKey}-${index}`}>
|
||||
<TableCell
|
||||
key={`tbCT-${column.elementKey}-${index}`}
|
||||
className={column.globalClass}
|
||||
>
|
||||
{column.label}
|
||||
</TableCell>
|
||||
);
|
||||
@@ -279,7 +283,10 @@ const TableWrapper = ({
|
||||
</TableCell>
|
||||
)}
|
||||
{titleColumnsMap(columns)}
|
||||
{itemActions && itemActions.length > 0 && (
|
||||
{((itemActions && itemActions.length > 1) ||
|
||||
(itemActions &&
|
||||
itemActions.length === 1 &&
|
||||
itemActions[0].type !== "view")) && (
|
||||
<TableCell
|
||||
align="center"
|
||||
className={classes.actionsContainer}
|
||||
@@ -329,7 +336,10 @@ const TableWrapper = ({
|
||||
</TableCell>
|
||||
)}
|
||||
{rowColumnsMap(columns, record, classes, isSelected)}
|
||||
{itemActions && itemActions.length > 0 && (
|
||||
{((itemActions && itemActions.length > 1) ||
|
||||
(itemActions &&
|
||||
itemActions.length === 1 &&
|
||||
itemActions[0].type !== "view")) && (
|
||||
<TableCell
|
||||
align="center"
|
||||
className={classes.actionsContainer}
|
||||
|
||||
239
portal-ui/src/screens/Console/ObjectBrowser/BrowseBuckets.tsx
Normal file
239
portal-ui/src/screens/Console/ObjectBrowser/BrowseBuckets.tsx
Normal file
@@ -0,0 +1,239 @@
|
||||
// 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/>.
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import get from "lodash/get";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import AddBucket from "../Buckets/ListBuckets/AddBucket";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import InputAdornment from "@material-ui/core/InputAdornment";
|
||||
import SearchIcon from "@material-ui/icons/Search";
|
||||
import { Button } from "@material-ui/core";
|
||||
import { CreateIcon } from "../../../icons";
|
||||
import { niceBytes } from "../../../common/utils";
|
||||
import { MinTablePaginationActions } from "../../../common/MinTablePaginationActions";
|
||||
import { Bucket, BucketList } from "../Buckets/types";
|
||||
import TableWrapper from "../Common/TableWrapper/TableWrapper";
|
||||
import api from "../../../common/api";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
seeMore: {
|
||||
marginTop: theme.spacing(3),
|
||||
},
|
||||
paper: {
|
||||
display: "flex",
|
||||
overflow: "auto",
|
||||
flexDirection: "column",
|
||||
},
|
||||
|
||||
addSideBar: {
|
||||
width: "320px",
|
||||
padding: "20px",
|
||||
},
|
||||
errorBlock: {
|
||||
color: "red",
|
||||
},
|
||||
tableToolbar: {
|
||||
paddingLeft: theme.spacing(2),
|
||||
paddingRight: theme.spacing(0),
|
||||
},
|
||||
minTableHeader: {
|
||||
color: "#393939",
|
||||
"& tr": {
|
||||
"& th": {
|
||||
fontWeight: "bold",
|
||||
},
|
||||
},
|
||||
},
|
||||
actionsTray: {
|
||||
textAlign: "right",
|
||||
"& button": {
|
||||
marginLeft: 10,
|
||||
},
|
||||
},
|
||||
searchField: {
|
||||
background: "#FFFFFF",
|
||||
padding: 12,
|
||||
borderRadius: 5,
|
||||
boxShadow: "0px 3px 6px #00000012",
|
||||
},
|
||||
usedSpaceCol: {
|
||||
width: 150,
|
||||
},
|
||||
subTitleLabel: {
|
||||
alignItems: "center",
|
||||
display: "flex",
|
||||
},
|
||||
});
|
||||
|
||||
interface IBrowseBucketsProps {
|
||||
classes: any;
|
||||
}
|
||||
|
||||
const BrowseBuckets = ({ classes }: IBrowseBucketsProps) => {
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [page, setPage] = useState<number>(0);
|
||||
const [rowsPerPage, setRowsPerPage] = useState<number>(10);
|
||||
const [error, setError] = useState<string>("");
|
||||
const [records, setRecords] = useState<Bucket[]>([]);
|
||||
const [addScreenOpen, setAddScreenOpen] = useState<boolean>(false);
|
||||
const [filterBuckets, setFilterBuckets] = useState<string>("");
|
||||
|
||||
const offset = page * rowsPerPage;
|
||||
|
||||
useEffect(() => {
|
||||
if (loading) {
|
||||
api
|
||||
.invoke("GET", `/api/v1/buckets?offset=${offset}&limit=${rowsPerPage}`)
|
||||
.then((res: BucketList) => {
|
||||
const buckets = get(res, "buckets", []);
|
||||
|
||||
setLoading(false);
|
||||
setRecords(buckets);
|
||||
setError("");
|
||||
// if we get 0 results, and page > 0 , go down 1 page
|
||||
if (
|
||||
(res.buckets === undefined ||
|
||||
res.buckets == null ||
|
||||
res.buckets.length === 0) &&
|
||||
page > 0
|
||||
) {
|
||||
const newPage = page - 1;
|
||||
setPage(newPage);
|
||||
setLoading(true);
|
||||
}
|
||||
})
|
||||
.catch((err: any) => {
|
||||
setLoading(false);
|
||||
setError(err);
|
||||
});
|
||||
}
|
||||
}, [loading]);
|
||||
|
||||
const closeAddModalAndRefresh = () => {
|
||||
setAddScreenOpen(false);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const filteredRecords = records
|
||||
.filter((b: Bucket) => {
|
||||
if (filterBuckets === "") {
|
||||
return true;
|
||||
}
|
||||
return b.name.indexOf(filterBuckets) >= 0;
|
||||
})
|
||||
.slice(offset, offset + rowsPerPage);
|
||||
|
||||
const handleChangePage = (event: unknown, newPage: number) => {
|
||||
setPage(newPage);
|
||||
};
|
||||
|
||||
const handleChangeRowsPerPage = (
|
||||
event: React.ChangeEvent<HTMLInputElement>
|
||||
) => {
|
||||
const rPP = parseInt(event.target.value, 10);
|
||||
setPage(0);
|
||||
setRowsPerPage(rPP);
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{addScreenOpen && (
|
||||
<AddBucket
|
||||
open={addScreenOpen}
|
||||
closeModalAndRefresh={closeAddModalAndRefresh}
|
||||
/>
|
||||
)}
|
||||
<Grid container>
|
||||
<Grid item xs={6} className={classes.subTitleLabel}>
|
||||
<Typography variant="h6">Buckets</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6} className={classes.actionsTray}>
|
||||
<TextField
|
||||
placeholder="Search Buckets"
|
||||
className={classes.searchField}
|
||||
id="search-resource"
|
||||
label=""
|
||||
onChange={(val) => {
|
||||
setFilterBuckets(val.target.value);
|
||||
}}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
startIcon={<CreateIcon />}
|
||||
onClick={() => {
|
||||
setAddScreenOpen(true);
|
||||
}}
|
||||
>
|
||||
Add Bucket
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{error !== "" && <span className={classes.errorBlock}>{error}</span>}
|
||||
<TableWrapper
|
||||
itemActions={[
|
||||
{ type: "view", to: `/object-browser`, sendOnlyId: true },
|
||||
]}
|
||||
columns={[
|
||||
{ label: "Name", elementKey: "name" },
|
||||
{
|
||||
label: "Used Space",
|
||||
elementKey: "size",
|
||||
renderFunction: niceBytes,
|
||||
globalClass: classes.usedSpaceCol,
|
||||
},
|
||||
]}
|
||||
isLoading={loading}
|
||||
records={filteredRecords}
|
||||
entityName="Buckets"
|
||||
idField="name"
|
||||
paginatorConfig={{
|
||||
rowsPerPageOptions: [5, 10, 25],
|
||||
colSpan: 3,
|
||||
count: filteredRecords.length,
|
||||
rowsPerPage: rowsPerPage,
|
||||
page: page,
|
||||
SelectProps: {
|
||||
inputProps: { "aria-label": "rows per page" },
|
||||
native: true,
|
||||
},
|
||||
onChangePage: handleChangePage,
|
||||
onChangeRowsPerPage: handleChangeRowsPerPage,
|
||||
ActionsComponent: MinTablePaginationActions,
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(BrowseBuckets);
|
||||
@@ -1,9 +1,87 @@
|
||||
// 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/>.
|
||||
|
||||
import React from "react";
|
||||
import get from "lodash/get";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { Grid, Typography } from "@material-ui/core";
|
||||
import BrowseBuckets from "./BrowseBuckets";
|
||||
|
||||
const ObjectBrowser = (props: any) => {
|
||||
console.log(props);
|
||||
interface IObjectBrowserProps {
|
||||
match: any;
|
||||
classes: any;
|
||||
}
|
||||
|
||||
return <React.Fragment>Object Browser</React.Fragment>;
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
watchList: {
|
||||
background: "white",
|
||||
maxHeight: "400",
|
||||
overflow: "auto",
|
||||
"& ul": {
|
||||
margin: "4",
|
||||
padding: "0",
|
||||
},
|
||||
"& ul li": {
|
||||
listStyle: "none",
|
||||
margin: "0",
|
||||
padding: "0",
|
||||
borderBottom: "1px solid #dedede",
|
||||
},
|
||||
},
|
||||
actionsTray: {
|
||||
textAlign: "right",
|
||||
"& button": {
|
||||
marginLeft: 10,
|
||||
},
|
||||
},
|
||||
inputField: {
|
||||
background: "#FFFFFF",
|
||||
padding: 12,
|
||||
borderRadius: 5,
|
||||
marginLeft: 10,
|
||||
boxShadow: "0px 3px 6px #00000012",
|
||||
},
|
||||
fieldContainer: {
|
||||
background: "#FFFFFF",
|
||||
padding: 0,
|
||||
borderRadius: 5,
|
||||
marginLeft: 10,
|
||||
textAlign: "left",
|
||||
minWidth: "206",
|
||||
boxShadow: "0px 3px 6px #00000012",
|
||||
},
|
||||
lastElementWPadding: {
|
||||
paddingRight: "78",
|
||||
},
|
||||
});
|
||||
|
||||
const ObjectBrowser = ({ match, classes }: IObjectBrowserProps) => {
|
||||
const pathIn = get(match, "path", "");
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h6">Object Browser</Typography>
|
||||
</Grid>
|
||||
{pathIn === "/object-browser" && <BrowseBuckets />}
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default ObjectBrowser;
|
||||
export default withStyles(styles)(ObjectBrowser);
|
||||
|
||||
Reference in New Issue
Block a user