Added virtualized render to buckets & tenants lists (#1386)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
@@ -51,7 +51,8 @@
|
||||
"react-redux": "^7.1.3",
|
||||
"react-router-dom": "^5.1.2",
|
||||
"react-virtualized": "^9.22.2",
|
||||
"react-window-infinite-loader": "^1.0.5",
|
||||
"react-window": "^1.8.6",
|
||||
"react-window-infinite-loader": "^1.0.7",
|
||||
"recharts": "^2.1.1",
|
||||
"redux": "^4.0.5",
|
||||
"redux-thunk": "^2.3.0",
|
||||
@@ -84,6 +85,8 @@
|
||||
},
|
||||
"proxy": "http://localhost:9090/",
|
||||
"devDependencies": {
|
||||
"@types/react-window": "^1.8.5",
|
||||
"@types/react-window-infinite-loader": "^1.0.5",
|
||||
"@types/recharts": "^1.8.22",
|
||||
"prettier": "2.3.2",
|
||||
"react-app-rewire-hot-loader": "^2.0.1",
|
||||
|
||||
@@ -55,7 +55,6 @@ const styles = (theme: Theme) =>
|
||||
wordWrap: "break-word",
|
||||
overflowWrap: "break-word",
|
||||
wordBreak: "break-all",
|
||||
// height: 90,
|
||||
font: "normal normal bold 24px/27px Lato",
|
||||
color: theme.palette.primary.main,
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ import {
|
||||
} from "../../../../common/SecureComponent/permissions";
|
||||
import PageLayout from "../../Common/Layout/PageLayout";
|
||||
import SearchBox from "../../Common/SearchBox";
|
||||
import VirtualizedList from "../../Common/VirtualizedList/VirtualizedList";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -66,6 +67,7 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
bucketList: {
|
||||
marginTop: 25,
|
||||
height: "calc(100vh - 210px)",
|
||||
},
|
||||
searchField: {
|
||||
...searchField.searchField,
|
||||
@@ -172,6 +174,24 @@ const ListBuckets = ({
|
||||
}
|
||||
};
|
||||
|
||||
const renderItemLine = (index: number) => {
|
||||
const bucket = filteredRecords[index] || null;
|
||||
|
||||
if (bucket) {
|
||||
return (
|
||||
<BucketListItem
|
||||
bucket={bucket}
|
||||
onDelete={confirmDeleteBucket}
|
||||
onSelect={selectListBuckets}
|
||||
selected={selectedBuckets.includes(bucket.name)}
|
||||
bulkSelect={bulkSelect}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{deleteOpen && (
|
||||
@@ -262,18 +282,12 @@ const ListBuckets = ({
|
||||
{loading && <LinearProgress />}
|
||||
{!loading && (
|
||||
<Grid item xs={12} className={classes.bucketList}>
|
||||
{filteredRecords.map((bucket, index) => {
|
||||
return (
|
||||
<BucketListItem
|
||||
bucket={bucket}
|
||||
key={`bucketListItem-${index.toString()}`}
|
||||
onDelete={confirmDeleteBucket}
|
||||
onSelect={selectListBuckets}
|
||||
selected={selectedBuckets.includes(bucket.name)}
|
||||
bulkSelect={bulkSelect}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{filteredRecords.length !== 0 && (
|
||||
<VirtualizedList
|
||||
rowRenderFunction={renderItemLine}
|
||||
totalItems={filteredRecords.length}
|
||||
/>
|
||||
)}
|
||||
{filteredRecords.length === 0 && filterBuckets !== "" && (
|
||||
<Grid
|
||||
container
|
||||
|
||||
@@ -21,11 +21,11 @@ export interface RwAccess {
|
||||
|
||||
export interface Bucket {
|
||||
name: string;
|
||||
creation_date: Date;
|
||||
creation_date: string;
|
||||
size?: number;
|
||||
objects?: number;
|
||||
rw_access?: RwAccess;
|
||||
manage: boolean;
|
||||
manage?: boolean;
|
||||
details?: Details;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,10 @@ export interface BucketEncryptionInfo {
|
||||
}
|
||||
|
||||
export interface Details {
|
||||
tags: object;
|
||||
tags?: object;
|
||||
locking?: boolean;
|
||||
quota?: object;
|
||||
versioning?: boolean;
|
||||
}
|
||||
|
||||
export interface BucketInfo {
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 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, { Fragment, ReactElement, useState } from "react";
|
||||
import { FixedSizeList as List } from "react-window";
|
||||
import InfiniteLoader from "react-window-infinite-loader";
|
||||
import { AutoSizer } from "react-virtualized";
|
||||
|
||||
interface IVirtualizedList {
|
||||
rowRenderFunction: (index: number) => ReactElement | null;
|
||||
totalItems: number;
|
||||
defaultHeight?: number;
|
||||
}
|
||||
|
||||
let itemStatusMap: any = {};
|
||||
const LOADING = 1;
|
||||
const LOADED = 2;
|
||||
|
||||
const VirtualizedList = ({
|
||||
rowRenderFunction,
|
||||
totalItems,
|
||||
defaultHeight,
|
||||
}: IVirtualizedList) => {
|
||||
const isItemLoaded = (index: any) => !!itemStatusMap[index];
|
||||
|
||||
const loadMoreItems = (startIndex: number, stopIndex: number) => {
|
||||
for (let index = startIndex; index <= stopIndex; index++) {
|
||||
itemStatusMap[index] = LOADING;
|
||||
}
|
||||
|
||||
for (let index = startIndex; index <= stopIndex; index++) {
|
||||
itemStatusMap[index] = LOADED;
|
||||
}
|
||||
};
|
||||
|
||||
const RenderItemLine = ({ index, style }: any) => {
|
||||
return <div style={style}>{rowRenderFunction(index)}</div>;
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<InfiniteLoader
|
||||
isItemLoaded={isItemLoaded}
|
||||
loadMoreItems={loadMoreItems}
|
||||
itemCount={totalItems}
|
||||
>
|
||||
{({ onItemsRendered, ref }) => (
|
||||
<AutoSizer>
|
||||
{({ width, height }) => {
|
||||
return (
|
||||
<List
|
||||
itemSize={defaultHeight || 220}
|
||||
height={height}
|
||||
itemCount={totalItems}
|
||||
width={width}
|
||||
ref={ref}
|
||||
onItemsRendered={onItemsRendered}
|
||||
>
|
||||
{RenderItemLine}
|
||||
</List>
|
||||
);
|
||||
}}
|
||||
</AutoSizer>
|
||||
)}
|
||||
</InfiniteLoader>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default VirtualizedList;
|
||||
@@ -45,6 +45,8 @@ import BoxIconButton from "../../Common/BoxIconButton/BoxIconButton";
|
||||
import AButton from "../../Common/AButton/AButton";
|
||||
|
||||
import withSuspense from "../../Common/Components/withSuspense";
|
||||
import VirtualizedList from "../../Common/VirtualizedList/VirtualizedList";
|
||||
import BucketListItem from "../../Buckets/ListBuckets/BucketListItem";
|
||||
|
||||
const CredentialsPrompt = withSuspense(
|
||||
React.lazy(() => import("../../Common/CredentialsPrompt/CredentialsPrompt"))
|
||||
@@ -94,6 +96,10 @@ const styles = (theme: Theme) =>
|
||||
textAlign: "right",
|
||||
marginBottom: 8,
|
||||
},
|
||||
tenantsList: {
|
||||
marginTop: 25,
|
||||
height: "calc(100vh - 195px)",
|
||||
},
|
||||
});
|
||||
|
||||
const ListTenants = ({ classes, setErrorSnackMessage }: ITenantsList) => {
|
||||
@@ -158,6 +164,16 @@ const ListTenants = ({ classes, setErrorSnackMessage }: ITenantsList) => {
|
||||
setIsLoading(true);
|
||||
}, []);
|
||||
|
||||
const renderItemLine = (index: number) => {
|
||||
const tenant = filteredRecords[index] || null;
|
||||
|
||||
if (tenant) {
|
||||
return <TenantListItem tenant={tenant} />;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{showNewCredentials && (
|
||||
@@ -259,13 +275,16 @@ const ListTenants = ({ classes, setErrorSnackMessage }: ITenantsList) => {
|
||||
</BoxIconButton>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Grid item xs={12} className={classes.tenantsList}>
|
||||
{isLoading && <LinearProgress />}
|
||||
{!isLoading && (
|
||||
<Fragment>
|
||||
{filteredRecords.map((t) => {
|
||||
return <TenantListItem tenant={t} />;
|
||||
})}
|
||||
{filteredRecords.length !== 0 && (
|
||||
<VirtualizedList
|
||||
rowRenderFunction={renderItemLine}
|
||||
totalItems={filteredRecords.length}
|
||||
/>
|
||||
)}
|
||||
{filteredRecords.length === 0 && (
|
||||
<Grid
|
||||
container
|
||||
|
||||
@@ -1015,7 +1015,7 @@
|
||||
core-js-pure "^3.19.0"
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
|
||||
version "7.16.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa"
|
||||
integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==
|
||||
@@ -2442,6 +2442,21 @@
|
||||
"@types/prop-types" "*"
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-window-infinite-loader@^1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-window-infinite-loader/-/react-window-infinite-loader-1.0.5.tgz#32469a6a47438d9ebf1b5f5719943f494ea0abdf"
|
||||
integrity sha512-3v45+4oBNJpSroULtb2EgTJyyK4pCjOMCg+RT/HnA3or5zY4jYufv6uH9NWPyLv0nx8dqt1s4nJqHilfthwKSw==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
"@types/react-window" "*"
|
||||
|
||||
"@types/react-window@*", "@types/react-window@^1.8.5":
|
||||
version "1.8.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-window/-/react-window-1.8.5.tgz#285fcc5cea703eef78d90f499e1457e9b5c02fc1"
|
||||
integrity sha512-V9q3CvhC9Jk9bWBOysPGaWy/Z0lxYcTXLtLipkt2cnRj1JOSFNF7wqGpkScSXMgBwC+fnVRg/7shwgddBG5ICw==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*":
|
||||
version "17.0.38"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.38.tgz#f24249fefd89357d5fa71f739a686b8d7c7202bd"
|
||||
@@ -6827,6 +6842,11 @@ memfs@^3.1.2, memfs@^3.2.2:
|
||||
dependencies:
|
||||
fs-monkey "1.0.3"
|
||||
|
||||
"memoize-one@>=3.1.1 <6":
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
|
||||
integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
|
||||
|
||||
merge-descriptors@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
|
||||
@@ -8373,11 +8393,19 @@ react-virtualized@^9.22.2:
|
||||
prop-types "^15.7.2"
|
||||
react-lifecycles-compat "^3.0.4"
|
||||
|
||||
react-window-infinite-loader@^1.0.5:
|
||||
react-window-infinite-loader@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/react-window-infinite-loader/-/react-window-infinite-loader-1.0.7.tgz#958ef1a689d20dce122ef377583acd987760aee8"
|
||||
integrity sha512-wg3LWkUpG21lhv+cZvNy+p0+vtclZw+9nP2vO6T9PKT50EN1cUq37Dq6FzcM38h/c2domE0gsUhb6jHXtGogAA==
|
||||
|
||||
react-window@^1.8.6:
|
||||
version "1.8.6"
|
||||
resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.6.tgz#d011950ac643a994118632665aad0c6382e2a112"
|
||||
integrity sha512-8VwEEYyjz6DCnGBsd+MgkD0KJ2/OXFULyDtorIiTz+QzwoP94tBoA7CnbtyXMm+cCeAUER5KJcPtWl9cpKbOBg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0"
|
||||
memoize-one ">=3.1.1 <6"
|
||||
|
||||
react@^17.0.2:
|
||||
version "17.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
|
||||
|
||||
Reference in New Issue
Block a user