Changed position of search box for list objects module (#1497)

- Changed the searchbox component to be a controlled component
- Added reducer to control searchbox in objects list
- Adjusted styles to search box component & placeholders
- Fixed navigation of folders

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
Alex
2022-01-31 20:46:57 -07:00
committed by GitHub
parent ce989e39ab
commit 780cf7240b
22 changed files with 150 additions and 39 deletions

View File

@@ -197,6 +197,7 @@ const Account = ({ classes, displayErrorMessage }: IServiceAccountsProps) => {
placeholder={"Search Service Accounts"}
onChange={setFilter}
overrideClass={classes.searchField}
value={filter}
/>
<Box

View File

@@ -24,7 +24,10 @@ import { Grid, IconButton, Tooltip } from "@mui/material";
import get from "lodash/get";
import { AppState } from "../../../../store";
import { containerForHeader } from "../../Common/FormComponents/common/styleLibrary";
import { setFileModeEnabled } from "../../ObjectBrowser/actions";
import {
setFileModeEnabled,
setSearchObjects,
} from "../../ObjectBrowser/actions";
import ObjectDetails from "../ListBuckets/Objects/ObjectDetails/ObjectDetails";
import ListObjects from "../ListBuckets/Objects/ListObjects/ListObjects";
import PageHeader from "../../Common/PageHeader/PageHeader";
@@ -35,7 +38,9 @@ import SecureComponent from "../../../../common/SecureComponent/SecureComponent"
import {
IAM_PERMISSIONS,
IAM_ROLES,
IAM_SCOPES,
} from "../../../../common/SecureComponent/permissions";
import SearchBox from "../../Common/SearchBox";
interface IBrowserHandlerProps {
fileMode: boolean;
@@ -45,6 +50,8 @@ interface IBrowserHandlerProps {
setFileModeEnabled: typeof setFileModeEnabled;
setErrorSnackMessage: typeof setErrorSnackMessage;
bucketInfo: BucketInfo | null;
searchObjects: string;
setSearchObjects: typeof setSearchObjects;
}
const styles = (theme: Theme) =>
@@ -62,7 +69,8 @@ const BrowserHandler = ({
history,
classes,
setFileModeEnabled,
bucketInfo,
searchObjects,
setSearchObjects,
}: IBrowserHandlerProps) => {
const bucketName = match.params["bucketName"];
const internalPaths = get(match.params, "subpaths", "");
@@ -105,6 +113,25 @@ const BrowserHandler = ({
</Tooltip>
</SecureComponent>
}
middleComponent={
<Fragment>
{!fileMode && (
<SecureComponent
scopes={[IAM_SCOPES.S3_LIST_BUCKET]}
resource={bucketName}
errorProps={{ disabled: true }}
>
<SearchBox
placeholder={"Start typing to filter objects in bucket"}
onChange={(value) => {
setSearchObjects(value);
}}
value={searchObjects}
/>
</SecureComponent>
)}
</Fragment>
}
/>
<Grid>{fileMode ? <ObjectDetails /> : <ListObjects />}</Grid>
</Fragment>
@@ -115,11 +142,13 @@ const mapStateToProps = ({ objectBrowser, buckets }: AppState) => ({
fileMode: get(objectBrowser, "fileMode", false),
bucketToRewind: get(objectBrowser, "rewind.bucketToRewind", ""),
bucketInfo: buckets.bucketDetails.bucketInfo,
searchObjects: objectBrowser.searchObjects,
});
const mapDispatchToProps = {
setFileModeEnabled,
setErrorSnackMessage,
setSearchObjects,
};
const connector = connect(mapStateToProps, mapDispatchToProps);

View File

@@ -217,6 +217,7 @@ const ListBuckets = ({
onChange={setFilterBuckets}
placeholder="Search Buckets"
overrideClass={classes.searchField}
value={filterBuckets}
/>
<Grid

View File

@@ -63,6 +63,7 @@ import {
resetRewind,
setFileModeEnabled,
setNewObject,
setSearchObjects,
updateProgress,
} from "../../../../ObjectBrowser/actions";
import { Route } from "../../../../ObjectBrowser/reducers";
@@ -85,7 +86,6 @@ import { IAM_SCOPES } from "../../../../../../common/SecureComponent/permissions
import SecureComponent, {
hasPermission,
} from "../../../../../../common/SecureComponent/SecureComponent";
import SearchBox from "../../../../Common/SearchBox";
import withSuspense from "../../../../Common/Components/withSuspense";
import { displayName } from "./utils";
@@ -196,6 +196,7 @@ interface IListObjectsProps {
rewindEnabled: boolean;
rewindDate: any;
bucketToRewind: string;
searchObjects: string;
setSnackBarMessage: typeof setSnackBarMessage;
setErrorSnackMessage: typeof setErrorSnackMessage;
resetRewind: typeof resetRewind;
@@ -208,6 +209,7 @@ interface IListObjectsProps {
updateProgress: typeof updateProgress;
completeObject: typeof completeObject;
openList: typeof openList;
setSearchObjects: typeof setSearchObjects;
}
function useInterval(callback: any, delay: number) {
@@ -253,6 +255,8 @@ const ListObjects = ({
setNewObject,
updateProgress,
completeObject,
setSearchObjects,
searchObjects,
openList,
}: IListObjectsProps) => {
const [records, setRecords] = useState<BucketObject[]>([]);
@@ -261,7 +265,6 @@ const ListObjects = ({
const [loadingRewind, setLoadingRewind] = useState<boolean>(false);
const [deleteMultipleOpen, setDeleteMultipleOpen] = useState<boolean>(false);
const [createFolderOpen, setCreateFolderOpen] = useState<boolean>(false);
const [filterObjects, setFilterObjects] = useState<string>("");
const [loadingStartTime, setLoadingStartTime] = useState<number>(0);
const [loadingMessage, setLoadingMessage] =
useState<React.ReactNode>(defLoading);
@@ -434,7 +437,9 @@ const ListObjects = ({
useEffect(() => {
setLoading(true);
}, [internalPaths]);
setDetailsOpen(false);
setSearchObjects("");
}, [internalPaths, setSearchObjects]);
useEffect(() => {
if (loading) {
@@ -685,6 +690,14 @@ const ListObjects = ({
};
const openPath = (idElement: string) => {
if(idElement.endsWith("/")) {
const newPath = `/buckets/${bucketName}/browse${
idElement ? `/${encodeFileName(idElement)}` : ``
}`;
history.push(newPath);
return;
}
setDetailsOpen(true);
setSelectedInternalPaths(
`${idElement ? `${encodeFileName(idElement)}` : ``}`
@@ -923,11 +936,11 @@ const ListObjects = ({
];
const filteredRecords = records.filter((b: BucketObject) => {
if (filterObjects === "") {
if (searchObjects === "") {
return true;
} else {
const objectName = b.name.toLowerCase();
if (objectName.indexOf(filterObjects.toLowerCase()) >= 0) {
if (objectName.indexOf(searchObjects.toLowerCase()) >= 0) {
return true;
} else {
return false;
@@ -1181,19 +1194,6 @@ const ListObjects = ({
}
/>
</Grid>
<Grid item xs={12} className={classes.actionsTray}>
<SecureComponent
scopes={[IAM_SCOPES.S3_LIST_BUCKET]}
resource={bucketName}
errorProps={{ disabled: true }}
>
<SearchBox
onChange={setFilterObjects}
placeholder="Search Objects"
overrideClass={classes.searchField}
/>
</SecureComponent>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
@@ -1321,11 +1321,11 @@ const ListObjects = ({
}}
>
{selectedInternalPaths !== null && (
<ObjectDetailPanel
internalPaths={selectedInternalPaths}
bucketName={bucketName}
/>
)}
<ObjectDetailPanel
internalPaths={selectedInternalPaths}
bucketName={bucketName}
/>
)}
</DetailsListPanel>
</SecureComponent>
</Grid>
@@ -1343,6 +1343,7 @@ const mapStateToProps = ({ objectBrowser, buckets }: AppState) => ({
bucketToRewind: get(objectBrowser, "rewind.bucketToRewind", ""),
loadingBucket: buckets.bucketDetails.loadingBucket,
bucketInfo: buckets.bucketDetails.bucketInfo,
searchObjects: objectBrowser.searchObjects,
});
const mapDispatchToProps = {
@@ -1356,6 +1357,7 @@ const mapDispatchToProps = {
updateProgress,
completeObject,
openList,
setSearchObjects,
};
const connector = connect(mapStateToProps, mapDispatchToProps);

View File

@@ -748,6 +748,7 @@ const ObjectDetails = ({
<SearchBox
placeholder={`Search ${currentItem}`}
onChange={setFilterVersion}
value={filterVersion}
/>
)}
</Grid>

View File

@@ -13,6 +13,7 @@
//
// 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 { Grid, InputLabel, TextField, Tooltip } from "@mui/material";
import { Theme } from "@mui/material/styles";
@@ -72,8 +73,9 @@ const styles = (theme: Theme) =>
fontSize: 13,
fontWeight: 600,
"&:placeholder": {
color: "#393939",
color: "#858585",
opacity: 1,
fontWeight: 400,
},
},
},

View File

@@ -280,8 +280,9 @@ export const searchField = {
fontWeight: 700,
color: "#000",
"&::placeholder": {
color: "#a6a5a5",
color: "#858585",
opacity: 1,
fontWeight: 400,
},
},
"&:hover": {
@@ -898,8 +899,9 @@ export const inputFieldStyles = {
fontSize: 13,
fontWeight: 600,
"&:placeholder": {
color: "#393939",
color: "#858585",
opacity: 1,
fontWeight: 400,
},
},
error: {

View File

@@ -1,7 +1,22 @@
// 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 from "react";
import { Theme } from "@mui/material/styles";
import { connect } from "react-redux";
import { Box } from "@mui/material";
import Grid from "@mui/material/Grid";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
@@ -22,12 +37,12 @@ interface IPageHeader {
actions?: any;
managerObjects?: IFileItem[];
toggleList: typeof toggleList;
middleComponent?: React.ReactNode;
}
const styles = (theme: Theme) =>
createStyles({
headerContainer: {
// position: "absolute",
width: "100%",
minHeight: 79,
display: "flex",
@@ -57,6 +72,11 @@ const styles = (theme: Theme) =>
width: 120,
},
},
middleComponent: {
display: "flex",
justifyContent: "center",
alignItems: "center",
}
});
const PageHeader = ({
@@ -67,6 +87,7 @@ const PageHeader = ({
operatorMode,
managerObjects,
toggleList,
middleComponent,
}: IPageHeader) => {
return (
<Grid
@@ -75,12 +96,9 @@ const PageHeader = ({
direction="row"
alignItems="center"
>
<Box display={{ xs: "block", sm: "block", md: "none" }}>
<Grid item xs={12} style={{ height: 10 }}>
&nbsp;
</Grid>
</Box>
<Grid item xs={12} sm={12} md={6} className={classes.label}>
<Grid item xs={12} sm={12} md={middleComponent? 3: 6} className={classes.label} sx={{
paddingTop: ["15px", "15px", "0", "0"],
}}>
{!sidebarOpen && (
<div className={classes.logo}>
{operatorMode ? <OperatorLogo /> : <ConsoleLogo />}
@@ -90,7 +108,12 @@ const PageHeader = ({
{label}
</Typography>
</Grid>
<Grid item xs={12} sm={12} md={6} className={classes.rightMenu}>
{middleComponent && (
<Grid item xs={12} sm={12} md={6} className={classes.middleComponent}>
{middleComponent}
</Grid>
)}
<Grid item xs={12} sm={12} md={middleComponent? 3:6} className={classes.rightMenu}>
{actions && actions}
{managerObjects && managerObjects.length > 0 && (
<IconButton

View File

@@ -1,3 +1,19 @@
// 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 from "react";
import InputAdornment from "@mui/material/InputAdornment";
import SearchIcon from "../../../icons/SearchIcon";
@@ -17,6 +33,7 @@ const styles = (theme: Theme) =>
type SearchBoxProps = {
placeholder?: string;
value: string;
classes: any;
onChange: (value: string) => void;
adornmentPosition?: "start" | "end";
@@ -29,6 +46,7 @@ const SearchBox = ({
onChange,
adornmentPosition = "end",
overrideClass,
value,
}: SearchBoxProps) => {
const inputProps = {
disableUnderline: true,
@@ -52,6 +70,7 @@ const SearchBox = ({
onChange(e.target.value);
}}
variant="standard"
value={value}
/>
);
};

View File

@@ -245,6 +245,7 @@ const ListTiersConfiguration = ({
placeholder="Filter"
onChange={setFilter}
overrideClass={classes.searchField}
value={filter}
/>
<div className={classes.rightActionButtons}>
<RBIconButton

View File

@@ -211,6 +211,7 @@ const Groups = ({ classes, setErrorSnackMessage }: IGroupsProps) => {
placeholder={"Search Groups"}
onChange={setFilter}
overrideClass={classes.searchField}
value={filter}
/>
</SecureComponent>

View File

@@ -191,6 +191,7 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
setMemberFilter(searchText);
}}
overrideClass={classes.searchField}
value={memberFilter}
/>
<SecureComponent
resource={CONSOLE_UI_RESOURCE}

View File

@@ -161,6 +161,7 @@ const UsersSelectors = ({
placeholder="Filter Users"
adornmentPosition="end"
onChange={setFilter}
value={filter}
/>
</div>
</Grid>

View File

@@ -331,7 +331,7 @@ const ErrorLogs = ({
<PageLayout>
<Grid xs={12}>
<Grid item xs={12} className={classes.actionsTray}>
<SearchBox placeholder="Highlight Line" onChange={setHighlight} />
<SearchBox placeholder="Highlight Line" onChange={setHighlight} value={highlight} />
</Grid>
<Grid item xs={12}>
<div id="logs-container" className={classes.logList}>

View File

@@ -147,6 +147,7 @@ const ListNotificationEndpoints = ({
placeholder="Search target"
onChange={setFilter}
overrideClass={classes.searchField}
value={filter}
/>
<div className={classes.rightActionItems}>
<RBIconButton

View File

@@ -30,6 +30,7 @@ export const OBJECT_MANAGER_CLEAN_LIST = "OBJECT_MANAGER/CLEAN_LIST";
export const OBJECT_MANAGER_TOGGLE_LIST = "OBJECT_MANAGER/TOGGLE_LIST";
export const OBJECT_MANAGER_OPEN_LIST = "OBJECT_MANAGER/OPEN_LIST";
export const OBJECT_MANAGER_CLOSE_LIST = "OBJECT_MANAGER/CLOSE_LIST";
export const OBJECT_MANAGER_SET_SEARCH_OBJECT = "OBJECT_MANAGER/SET_SEARCH_OBJECT";
interface RewindSetEnabled {
type: typeof REWIND_SET_ENABLE;
@@ -82,6 +83,11 @@ interface OMCloseList {
type: typeof OBJECT_MANAGER_CLOSE_LIST;
}
interface SetSearchObjects {
type: typeof OBJECT_MANAGER_SET_SEARCH_OBJECT;
searchString: string;
}
export type ObjectBrowserActionTypes =
| RewindSetEnabled
| RewindReset
@@ -93,7 +99,7 @@ export type ObjectBrowserActionTypes =
| OMCleanList
| OMToggleList
| OMOpenList
| OMCloseList;
| OMCloseList | SetSearchObjects;
export const setRewindEnable = (
state: boolean,
@@ -173,3 +179,10 @@ export const closeList = () => {
type: OBJECT_MANAGER_CLOSE_LIST,
};
};
export const setSearchObjects = (searchString: string) => {
return {
type: OBJECT_MANAGER_SET_SEARCH_OBJECT,
searchString,
}
};

View File

@@ -26,6 +26,7 @@ import {
OBJECT_MANAGER_TOGGLE_LIST,
OBJECT_MANAGER_CLOSE_LIST,
OBJECT_MANAGER_OPEN_LIST,
OBJECT_MANAGER_SET_SEARCH_OBJECT,
} from "./actions";
export interface Route {
@@ -44,6 +45,7 @@ export interface ObjectBrowserState {
fileMode: boolean;
rewind: RewindItem;
objectManager: ObjectManager;
searchObjects: string;
}
export interface ObjectBrowserReducer {
@@ -80,6 +82,7 @@ const initialState: ObjectBrowserState = {
objectsToManage: [],
managerOpen: false,
},
searchObjects: "",
};
export function objectBrowserReducer(
@@ -212,6 +215,11 @@ export function objectBrowserReducer(
managerOpen: false,
},
};
case OBJECT_MANAGER_SET_SEARCH_OBJECT:
return {
...state,
searchObjects: action.searchString,
};
default:
return state;
}

View File

@@ -202,6 +202,7 @@ const ListPolicies = ({ classes, setErrorSnackMessage }: IPoliciesProps) => {
onChange={setFilterPolicies}
placeholder="Search Policies"
overrideClass={classes.searchField}
value={filterPolicies}
/>
<SecureComponent

View File

@@ -149,6 +149,7 @@ const PolicySelectors = ({
onChange={(value) => {
setFilter(value);
}}
value={filter}
/>
</div>
</Grid>

View File

@@ -204,6 +204,7 @@ const ListTenants = ({ classes, setErrorSnackMessage }: ITenantsList) => {
setFilterTenants(val);
}}
overrideClass={classes.searchField}
value={filterTenants}
/>
<RBIconButton

View File

@@ -148,6 +148,7 @@ const GroupsSelectors = ({
placeholder="Filter Groups"
adornmentPosition="end"
onChange={setFilter}
value={filter}
/>
</div>
</Grid>

View File

@@ -244,6 +244,7 @@ const ListUsers = ({ classes, setErrorSnackMessage, history }: IUsersProps) => {
placeholder={"Search Users"}
onChange={setFilter}
overrideClass={classes.searchField}
value={filter}
/>
<SecureComponent
scopes={[IAM_SCOPES.ADMIN_ADD_USER_TO_GROUP]}