Autocomplete component replacement (#3104)

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
Alex
2023-10-26 11:54:34 -06:00
committed by GitHub
parent 39e94c890e
commit 3ad3bccadb
10 changed files with 93 additions and 520 deletions

View File

@@ -15,14 +15,20 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useCallback, useEffect, useState, Fragment } from "react";
import { Button, DataTable, EventSubscriptionIcon, Grid, InputBox } from "mds";
import {
Autocomplete,
Button,
DataTable,
EventSubscriptionIcon,
Grid,
InputBox,
} from "mds";
import { ErrorResponseHandler } from "../../../../common/types";
import { setModalErrorSnackMessage } from "../../../../systemSlice";
import { useAppDispatch } from "../../../../store";
import { api } from "api";
import { NotificationEventType } from "api/consoleApi";
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
import AutocompleteWrapper from "../../Common/FormComponents/AutocompleteWrapper/AutocompleteWrapper";
import {
formFieldStyles,
modalBasic,
@@ -161,7 +167,7 @@ const AddEvent = ({
},
}}
>
<AutocompleteWrapper
<Autocomplete
onChange={(value: string) => {
setArn(value);
}}
@@ -170,7 +176,7 @@ const AddEvent = ({
label={"ARN"}
value={arn}
options={arnValues || []}
helptip={
helpTip={
<Fragment>
<a
target="blank"

View File

@@ -1,138 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 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 } from "react";
import Grid from "@mui/material/Grid";
import {
FormControl,
InputLabel,
OutlinedInputProps,
TextField,
TextFieldProps,
Tooltip,
} from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import Autocomplete from "@mui/material/Autocomplete";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import {
fieldBasic,
inputFieldStyles,
tooltipHelper,
} from "../common/styleLibrary";
import { HelpIcon, HelpTip } from "mds";
interface selectorTypes {
label: string;
value: string;
}
interface SelectProps {
options: selectorTypes[];
value: string;
label: string;
id: string;
name: string;
tooltip?: string;
onChange: (returnedValue: string) => void;
disabled?: boolean;
classes: any;
helptip?: any;
}
const styles = (theme: Theme) =>
createStyles({
...fieldBasic,
...tooltipHelper,
});
const inputStyles = makeStyles((theme: Theme) =>
createStyles({
...inputFieldStyles,
}),
);
function InputField(props: TextFieldProps) {
const classes = inputStyles();
return (
<TextField
InputProps={{ classes } as Partial<OutlinedInputProps>}
{...props}
/>
);
}
const AutocompleteWrapper = ({
classes,
id,
name,
onChange,
options,
label,
tooltip = "",
value,
disabled = false,
helptip,
}: SelectProps) => {
const [internalValue, setInternalValue] = useState<selectorTypes>(options[0]);
const executeOnSelect = (_: any, selectedValue: any) => {
if (selectedValue) {
onChange(selectedValue.value);
setInternalValue(selectedValue);
}
};
return (
<React.Fragment>
<Grid item xs={12} className={classes.fieldContainer}>
{label !== "" && (
<InputLabel htmlFor={id} className={classes.inputLabel}>
<HelpTip content={helptip} placement="right">
{" "}
<span>{label}</span>
</HelpTip>
{tooltip !== "" && (
<div className={classes.tooltipContainer}>
<Tooltip title={tooltip} placement="top-start">
<div className={classes.tooltip}>
<HelpIcon />
</div>
</Tooltip>
</div>
)}
</InputLabel>
)}
<FormControl fullWidth>
<Autocomplete
id={id}
options={options}
getOptionLabel={(option) => option.label}
isOptionEqualToValue={(option) => option.value === value}
disabled={disabled}
renderInput={(params) => <InputField {...params} name={name} />}
value={internalValue}
onChange={executeOnSelect}
autoHighlight
/>
</FormControl>
</Grid>
</React.Fragment>
);
};
export default withStyles(styles)(AutocompleteWrapper);

View File

@@ -315,50 +315,6 @@ export const snackBarCommon = {
},
};
export const inputFieldStyles = {
root: {
borderRadius: 3,
"&::before": {
borderColor: "#9c9c9c",
},
"& fieldset": {
borderColor: "#e5e5e5",
},
"&:hover fieldset": {
borderColor: "#07193E",
},
"&.Mui-focused .MuiOutlinedInput-notchedOutline": {
borderColor: "#07193E",
borderWidth: 1,
},
"&.Mui-error + p": {
marginLeft: 3,
},
},
disabled: {
"&.MuiOutlinedInput-root::before": {
borderColor: "#e5e5e5",
borderBottomStyle: "solid" as const,
borderRadius: 3,
},
},
input: {
height: 38,
padding: "0 35px 0 15px",
color: "#07193E",
fontSize: 13,
fontWeight: 600,
"&:placeholder": {
color: "#858585",
opacity: 1,
fontWeight: 400,
},
},
error: {
color: "#b53b4b",
},
};
export const formFieldStyles: any = {
formFieldRow: {
marginBottom: ".8rem",

View File

@@ -454,7 +454,6 @@ const AddTierConfiguration = () => {
required={type !== "minio"}
label={"Region"}
id="region"
name="region"
type={type as "azure" | "s3" | "minio" | "gcs"}
/>
{type === s3ServiceName && (

View File

@@ -1,159 +0,0 @@
// 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 { Autocomplete, Box, TextField } from "@mui/material";
import s3Regions from "./s3-regions";
import gcsRegions from "./gcs-regions";
import azRegions from "./azure-regions";
const getRegions = (type: string): any => {
if (type === "s3") {
return s3Regions;
}
if (type === "gcs") {
return gcsRegions;
}
if (type === "azure") {
return azRegions;
}
return [];
};
const RegionSelect = ({
type,
onChange,
inputProps,
}: {
type: "minio" | "s3" | "gcs" | "azure" | "unsupported";
onChange: (obj: any) => void;
inputProps?: any;
}) => {
const regionList = getRegions(type);
const [value, setValue] = React.useState("");
return (
<Autocomplete
sx={{
"& .MuiOutlinedInput-root": {
padding: 0,
paddingLeft: "10px",
fontSize: 13,
fontWeight: 600,
},
"& .MuiAutocomplete-inputRoot": {
"& .MuiOutlinedInput-notchedOutline": {
borderColor: "#e5e5e5",
borderWidth: 1,
},
"&:hover .MuiOutlinedInput-notchedOutline": {
borderColor: "#07193E",
borderWidth: 1,
},
"&.Mui-focused .MuiOutlinedInput-notchedOutline": {
borderColor: "#07193E",
borderWidth: 1,
},
},
}}
freeSolo
selectOnFocus
handleHomeEndKeys
onChange={(event, newValue) => {
let newVal: any = newValue;
if (typeof newValue === "string") {
newVal = {
label: newValue,
};
} else if (newValue && newValue.inputValue) {
// Create a new value from the user input
newVal = {
label: newValue.inputValue,
};
} else {
newVal = newValue;
}
setValue(newVal);
onChange(newVal?.value);
}}
value={value}
onInputChange={(e: any) => {
const { target: { value = "" } = {} } = e || {};
onChange(value);
}}
getOptionLabel={(option) => {
// Value selected with enter, right from the input
if (typeof option === "string") {
return option;
}
// Add "xxx" option created dynamically
if (option.inputValue) {
return option.inputValue;
}
// Regular option
return option.value;
}}
options={regionList}
filterOptions={(opts: any[], state: any) => {
const filterText = state.inputValue.toLowerCase();
return opts.filter((opt) =>
`${opt.label.toLowerCase()}${opt.value.toLowerCase()}`.includes(
filterText,
),
);
}}
renderOption={(props: any, opt: any) => {
return (
<li {...props}>
<Box
sx={{
display: "flex",
flexFlow: "column",
alignItems: "baseline",
padding: "4px",
borderBottom: "1px solid #eaeaea",
cursor: "pointer",
width: "100%",
"& .label": {
fontSize: "13px",
fontWeight: 500,
},
"& .value": {
fontSize: "11px",
fontWeight: 400,
},
}}
>
<span className="label">{opt.value}</span>
<span className="value">{opt.label}</span>
</Box>
</li>
);
}}
renderInput={(params) => (
<TextField {...params} {...inputProps} fullWidth />
)}
/>
);
};
export default RegionSelect;

View File

@@ -14,177 +14,90 @@
// 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, IconButton, InputLabel, Tooltip } from "mds";
import { InputProps as StandardInputProps } from "@mui/material/Input";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import makeStyles from "@mui/styles/makeStyles";
import withStyles from "@mui/styles/withStyles";
import {
fieldBasic,
inputFieldStyles,
tooltipHelper,
} from "../../Common/FormComponents/common/styleLibrary";
import { HelpIcon } from "mds";
import clsx from "clsx";
import RegionSelect from "./RegionSelect";
import React, { useState } from "react";
import { Autocomplete, InputBox, SelectorType } from "mds";
import s3Regions from "./s3-regions";
import gcsRegions from "./gcs-regions";
import azRegions from "./azure-regions";
const getRegions = (type: string): any => {
let regions: SelectorType[] = [];
if (type === "s3") {
regions = s3Regions;
}
if (type === "gcs") {
regions = gcsRegions;
}
if (type === "azure") {
regions = azRegions;
}
return regions.map((item) => ({
value: item.value,
label: `${item.label} - ${item.value}`,
}));
};
interface RegionSelectBoxProps {
label: string;
classes?: any;
onChange: (value: string) => void;
onKeyPress?: (e: any) => void;
value?: string | boolean;
id: string;
name: string;
disabled?: boolean;
type: "minio" | "s3" | "gcs" | "azure";
tooltip?: string;
index?: number;
error?: string;
required?: boolean;
placeholder?: string;
overlayId?: string;
overlayIcon?: any;
overlayAction?: () => void;
overlayObject?: any;
extraInputProps?: StandardInputProps["inputProps"];
noLabelMinWidth?: boolean;
pattern?: string;
autoFocus?: boolean;
className?: string;
}
const styles = (theme: Theme) =>
createStyles({
...fieldBasic,
...tooltipHelper,
textBoxContainer: {
flexGrow: 1,
position: "relative",
minWidth: 160,
},
overlayAction: {
position: "absolute",
right: 5,
top: 6,
"& svg": {
maxWidth: 15,
maxHeight: 15,
},
"&.withLabel": {
top: 5,
},
},
inputLabel: {
...fieldBasic.inputLabel,
fontWeight: "normal",
},
});
const inputStyles = makeStyles((theme: Theme) =>
createStyles({
...inputFieldStyles,
}),
);
const RegionSelectWrapper = ({
label,
onChange,
id,
name,
type,
tooltip = "",
index = 0,
error = "",
required = false,
overlayId,
overlayIcon = null,
overlayObject = null,
extraInputProps = {},
overlayAction,
noLabelMinWidth = false,
classes,
className = "",
disabled,
placeholder,
}: RegionSelectBoxProps) => {
const inputClasses = inputStyles();
const regionList = getRegions(type);
const [value, setValue] = useState<string>("");
let inputProps: any = {
"data-index": index,
...extraInputProps,
name: name,
id: id,
classes: inputClasses,
};
if (type === "minio") {
return (
<InputBox
label={label}
disabled={disabled}
required={required}
tooltip={tooltip}
value={value}
placeholder={placeholder}
id={"region-list"}
onChange={(e) => {
setValue(e.target.value);
onChange(e.target.value);
}}
/>
);
}
return (
<React.Fragment>
<Grid
container
className={clsx(
className !== "" ? className : "",
error !== "" ? classes.errorInField : classes.inputBoxContainer,
)}
>
{label !== "" && (
<InputLabel htmlFor={id} noMinWidth={noLabelMinWidth}>
<span>
{label}
{required ? "*" : ""}
</span>
{tooltip !== "" && (
<div className={classes.tooltipContainer}>
<Tooltip tooltip={tooltip} placement="top">
<div className={classes.tooltip}>
<HelpIcon />
</div>
</Tooltip>
</div>
)}
</InputLabel>
)}
<div className={classes.textBoxContainer}>
<RegionSelect
type={type}
inputProps={inputProps}
onChange={onChange}
/>
{overlayIcon && (
<div
className={`${classes.overlayAction} ${
label !== "" ? "withLabel" : ""
}`}
>
<IconButton
onClick={
overlayAction
? () => {
overlayAction();
}
: () => null
}
id={overlayId}
size={"small"}
>
{overlayIcon}
</IconButton>
</div>
)}
{overlayObject && (
<div
className={`${classes.overlayAction} ${
label !== "" ? "withLabel" : ""
}`}
>
{overlayObject}
</div>
)}
</div>
</Grid>
</React.Fragment>
<Autocomplete
label={label}
disabled={disabled}
required={required}
tooltip={tooltip}
options={regionList}
value={value}
placeholder={placeholder}
id={"region-list"}
onChange={(newValue) => {
setValue(newValue);
onChange(newValue);
}}
/>
);
};
export default withStyles(styles)(RegionSelectWrapper);
export default RegionSelectWrapper;

View File

@@ -14,9 +14,9 @@
// 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 { RegionEntry } from "./types";
import { SelectorType } from "mds";
const azureRegions: RegionEntry[] = [
const azureRegions: SelectorType[] = [
{
label: "Asia",
value: "asia",

View File

@@ -1,6 +1,22 @@
import { RegionEntry } from "./types";
// 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/>.
const gcsRegions: RegionEntry[] = [
import { SelectorType } from "mds";
const gcsRegions: SelectorType[] = [
{ label: "Montréal", value: "NORTHAMERICA-NORTHEAST1" },
{ label: "Toronto", value: "NORTHAMERICA-NORTHEAST2" },
{ label: "Iowa", value: "US-CENTRAL1" },

View File

@@ -14,9 +14,9 @@
// 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 { RegionEntry } from "./types";
import { SelectorType } from "mds";
const s3Regions: RegionEntry[] = [
const s3Regions: SelectorType[] = [
{ label: "US East (Ohio)", value: "us-east-2" },
{ label: "US East (N. Virginia)", value: "us-east-1" },
{ label: "US West (N. California)", value: "us-west-1" },

View File

@@ -1,20 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 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/>.
export interface RegionEntry {
label: string;
value: string;
}