1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-03 01:18:43 +02:00

refactor: improve GeneralSelect prop types (#883)

* refactor: improve GeneralSelect prop types

* refactor: Remove unused propTypes
This commit is contained in:
olav 2022-04-20 11:47:17 +02:00 committed by GitHub
parent cb8add5c30
commit 9bb0ce8cad
17 changed files with 72 additions and 94 deletions

View File

@ -87,7 +87,7 @@ const ApiTokenForm: React.FC<IApiTokenFormProps> = ({
<GeneralSelect <GeneralSelect
options={selectableTypes} options={selectableTypes}
value={type} value={type}
onChange={e => setTokenType(e.target.value as string)} onChange={setTokenType}
label="Token Type" label="Token Type"
id="api_key_type" id="api_key_type"
name="type" name="type"
@ -113,7 +113,7 @@ const ApiTokenForm: React.FC<IApiTokenFormProps> = ({
disabled={type === TYPE_ADMIN} disabled={type === TYPE_ADMIN}
options={selectableEnvs} options={selectableEnvs}
value={environment} value={environment}
onChange={e => setEnvironment(e.target.value as string)} onChange={setEnvironment}
label="Environment" label="Environment"
id="api_key_environment" id="api_key_environment"
name="environment" name="environment"

View File

@ -22,12 +22,12 @@ export const ApplicationUpdate = ({ application }: IApplicationUpdateProps) => {
const { setToastData, setToastApiError } = useToast(); const { setToastData, setToastApiError } = useToast();
const commonStyles = useCommonStyles(); const commonStyles = useCommonStyles();
const handleChange = async ( const onChange = async (
evt: ChangeEvent<{ name?: string | undefined; value: unknown }>,
field: string, field: string,
value: string value: string,
event?: ChangeEvent
) => { ) => {
evt.preventDefault(); event?.preventDefault();
try { try {
await storeApplicationMetaData(appName, field, value); await storeApplicationMetaData(appName, field, value);
refetchApplication(); refetchApplication();
@ -51,9 +51,7 @@ export const ApplicationUpdate = ({ application }: IApplicationUpdateProps) => {
label="Icon" label="Icon"
options={icons.map(v => ({ key: v, label: v }))} options={icons.map(v => ({ key: v, label: v }))}
value={icon || 'apps'} value={icon || 'apps'}
onChange={e => onChange={key => onChange('icon', key)}
handleChange(e, 'icon', e.target.value as string)
}
/> />
</Grid> </Grid>
<Grid item> <Grid item>
@ -65,7 +63,7 @@ export const ApplicationUpdate = ({ application }: IApplicationUpdateProps) => {
type="url" type="url"
variant="outlined" variant="outlined"
size="small" size="small"
onBlur={e => handleChange(e, 'url', localUrl)} onBlur={e => onChange('url', localUrl, e)}
/> />
</Grid> </Grid>
<Grid item> <Grid item>
@ -77,7 +75,7 @@ export const ApplicationUpdate = ({ application }: IApplicationUpdateProps) => {
rows={2} rows={2}
onChange={e => setLocalDescription(e.target.value)} onChange={e => setLocalDescription(e.target.value)}
onBlur={e => onBlur={e =>
handleChange(e, 'description', localDescription) onChange('description', localDescription, e)
} }
/> />
</Grid> </Grid>

View File

@ -94,7 +94,7 @@ export const ConstraintAccordionEditHeader = ({
autoFocus autoFocus
options={constraintNameOptions} options={constraintNameOptions}
value={contextName || ''} value={contextName || ''}
onChange={e => setContextName(String(e.target.value))} onChange={setContextName}
className={styles.headerSelect} className={styles.headerSelect}
/> />
</div> </div>

View File

@ -8,6 +8,7 @@ import {
} from '@material-ui/core'; } from '@material-ui/core';
import { SELECT_ITEM_ID } from 'utils/testIds'; import { SELECT_ITEM_ID } from 'utils/testIds';
import { KeyboardArrowDownOutlined } from '@material-ui/icons'; import { KeyboardArrowDownOutlined } from '@material-ui/icons';
import { SelectInputProps } from '@material-ui/core/Select/SelectInput';
export interface ISelectOption { export interface ISelectOption {
key: string; key: string;
@ -16,24 +17,19 @@ export interface ISelectOption {
disabled?: boolean; disabled?: boolean;
} }
export interface ISelectMenuProps extends SelectProps { export interface IGeneralSelectProps extends Omit<SelectProps, 'onChange'> {
name?: string; name?: string;
value?: string; value?: string;
label?: string; label?: string;
options: ISelectOption[]; options: ISelectOption[];
onChange?: OnGeneralSelectChange; onChange: (key: string) => void;
disabled?: boolean; disabled?: boolean;
fullWidth?: boolean; fullWidth?: boolean;
classes?: any; classes?: any;
defaultValue?: string; defaultValue?: string;
} }
export type OnGeneralSelectChange = ( const GeneralSelect: React.FC<IGeneralSelectProps> = ({
event: React.ChangeEvent<{ name?: string; value: unknown }>,
child: React.ReactNode
) => void;
const GeneralSelect: React.FC<ISelectMenuProps> = ({
name, name,
value = '', value = '',
label = '', label = '',
@ -59,6 +55,11 @@ const GeneralSelect: React.FC<ISelectMenuProps> = ({
</MenuItem> </MenuItem>
)); ));
const onSelectChange: SelectInputProps['onChange'] = event => {
event.preventDefault();
onChange(String(event.target.value));
};
return ( return (
<FormControl <FormControl
variant="outlined" variant="outlined"
@ -70,7 +71,7 @@ const GeneralSelect: React.FC<ISelectMenuProps> = ({
<Select <Select
name={name} name={name}
disabled={disabled} disabled={disabled}
onChange={onChange} onChange={onSelectChange}
className={className} className={className}
label={label} label={label}
id={id} id={id}

View File

@ -1,10 +1,14 @@
import React from 'react'; import React from 'react';
import GeneralSelect from '../GeneralSelect/GeneralSelect'; import GeneralSelect, {
IGeneralSelectProps,
} from '../GeneralSelect/GeneralSelect';
import useTagTypes from 'hooks/api/getters/useTagTypes/useTagTypes'; import useTagTypes from 'hooks/api/getters/useTagTypes/useTagTypes';
interface ITagSelect extends React.SelectHTMLAttributes<HTMLSelectElement> { interface ITagSelect {
name: string;
value: string; value: string;
onChange: (val: any) => void; onChange: IGeneralSelectProps['onChange'];
autoFocus?: boolean;
} }
const TagSelect = ({ value, onChange, ...rest }: ITagSelect) => { const TagSelect = ({ value, onChange, ...rest }: ITagSelect) => {
@ -18,10 +22,8 @@ const TagSelect = ({ value, onChange, ...rest }: ITagSelect) => {
return ( return (
<> <>
{/* @ts-expect-error */}
<GeneralSelect <GeneralSelect
label="Tag type" label="Tag type"
name="tag-select"
id="tag-select" id="tag-select"
options={options} options={options}
value={value} value={value}

View File

@ -92,8 +92,7 @@ const FeatureForm: React.FC<IFeatureToggleForm> = ({
</p> </p>
<FeatureTypeSelect <FeatureTypeSelect
value={type} value={type}
// @ts-expect-error onChange={setType}
onChange={(e: React.ChangeEvent) => setType(e.target.value)}
label={'Toggle type'} label={'Toggle type'}
id="feature-type-select" id="feature-type-select"
editable editable
@ -114,15 +113,12 @@ const FeatureForm: React.FC<IFeatureToggleForm> = ({
/> />
<FeatureProjectSelect <FeatureProjectSelect
value={project} value={project}
onChange={e => { onChange={projectId => {
setProject(e.target.value); setProject(projectId);
history.replace( history.replace(`/projects/${projectId}/create-toggle`);
`/projects/${e.target.value}/create-toggle`
);
}} }}
enabled={editable} enabled={editable}
filter={projectFilterGenerator(permissions, CREATE_FEATURE)} filter={projectFilterGenerator(permissions, CREATE_FEATURE)}
// @ts-expect-error
IconComponent={KeyboardArrowDownOutlined} IconComponent={KeyboardArrowDownOutlined}
className={styles.selectInput} className={styles.selectInput}
/> />

View File

@ -1,5 +1,5 @@
import GeneralSelect, { import GeneralSelect, {
OnGeneralSelectChange, IGeneralSelectProps,
} from 'component/common/GeneralSelect/GeneralSelect'; } from 'component/common/GeneralSelect/GeneralSelect';
interface IFeatureMetricsHoursProps { interface IFeatureMetricsHoursProps {
@ -13,8 +13,8 @@ export const FeatureMetricsHours = ({
hoursBack, hoursBack,
setHoursBack, setHoursBack,
}: IFeatureMetricsHoursProps) => { }: IFeatureMetricsHoursProps) => {
const onChange: OnGeneralSelectChange = event => { const onChange: IGeneralSelectProps['onChange'] = key => {
setHoursBack(parseFeatureMetricsHour(event.target.value)); setHoursBack(parseFeatureMetricsHour(key));
}; };
return ( return (

View File

@ -94,7 +94,7 @@ const AddTagDialog = ({ open, setOpen }: IAddTagDialogProps) => {
autoFocus autoFocus
name="type" name="type"
value={tag.type} value={tag.type}
onChange={e => setValue('type', e.target.value)} onChange={type => setValue('type', type)}
/> />
<br /> <br />
<Input <Input

View File

@ -65,8 +65,7 @@ const FeatureSettingsMetadata = () => {
<FeatureTypeSelect <FeatureTypeSelect
value={type} value={type}
id="feature-type-select" id="feature-type-select"
// @ts-expect-error onChange={setType}
onChange={e => setType(e.target.value)}
label="Feature type" label="Feature type"
editable={editable} editable={editable}
/> />

View File

@ -1,21 +1,23 @@
import useFeatureTypes from 'hooks/api/getters/useFeatureTypes/useFeatureTypes'; import useFeatureTypes from 'hooks/api/getters/useFeatureTypes/useFeatureTypes';
import GeneralSelect, { import GeneralSelect, {
ISelectOption, ISelectOption,
IGeneralSelectProps,
} from 'component/common/GeneralSelect/GeneralSelect'; } from 'component/common/GeneralSelect/GeneralSelect';
interface IFeatureTypeSelectProps
extends Omit<IGeneralSelectProps, 'options' | 'value'> {
value: string;
editable: boolean;
}
const FeatureTypeSelect = ({ const FeatureTypeSelect = ({
// @ts-expect-error
editable, editable,
// @ts-expect-error
value, value,
// @ts-expect-error
id, id,
// @ts-expect-error
label, label,
// @ts-expect-error
onChange, onChange,
...rest ...rest
}) => { }: IFeatureTypeSelectProps) => {
const { featureTypes } = useFeatureTypes(); const { featureTypes } = useFeatureTypes();
const options: ISelectOption[] = featureTypes.map(t => ({ const options: ISelectOption[] = featureTypes.map(t => ({

View File

@ -1,11 +1,15 @@
import useProjects from 'hooks/api/getters/useProjects/useProjects'; import useProjects from 'hooks/api/getters/useProjects/useProjects';
import { IProject } from 'interfaces/project'; import { IProjectCard } from 'interfaces/project';
import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect'; import GeneralSelect, {
ISelectOption,
IGeneralSelectProps,
} from 'component/common/GeneralSelect/GeneralSelect';
import React from 'react';
interface IFeatureProjectSelect { interface IFeatureProjectSelectProps
extends Omit<IGeneralSelectProps, 'options'> {
enabled: boolean; enabled: boolean;
value: string; value: string;
onChange: (e: any) => void;
filter: (project: string) => void; filter: (project: string) => void;
} }
@ -15,14 +19,14 @@ const FeatureProjectSelect = ({
onChange, onChange,
filter, filter,
...rest ...rest
}: IFeatureProjectSelect) => { }: IFeatureProjectSelectProps) => {
const { projects } = useProjects(); const { projects } = useProjects();
if (!enabled) { if (!enabled) {
return null; return null;
} }
const formatOption = (project: IProject) => { const formatOption = (project: IProjectCard) => {
return { return {
key: project.id, key: project.id,
label: project.name, label: project.name,
@ -30,28 +34,23 @@ const FeatureProjectSelect = ({
}; };
}; };
let options; let options: ISelectOption[];
if (filter) { if (filter) {
options = projects options = projects
.filter(project => { .filter(project => filter(project.id))
return filter(project.id);
})
// @ts-expect-error
.map(formatOption); .map(formatOption);
} else { } else {
// @ts-expect-error
options = projects.map(formatOption); options = projects.map(formatOption);
} }
if (value && !options.find(o => o.key === value)) { if (value && !options.find(o => o.key === value)) {
// @ts-expect-error
options.push({ key: value, label: value }); options.push({ key: value, label: value });
} }
return ( return (
<GeneralSelect <GeneralSelect
label="Project" label="Project"
// @ts-expect-error
options={options} options={options}
value={value} value={value}
onChange={onChange} onChange={onChange}

View File

@ -92,8 +92,7 @@ const FeatureSettingsProject = () => {
<> <>
<FeatureProjectSelect <FeatureProjectSelect
value={project} value={project}
onChange={e => setProject(e.target.value)} onChange={setProject}
// @ts-expect-error
label="Project" label="Project"
enabled={editable} enabled={editable}
filter={filterProjects()} filter={filterProjects()}

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState, ChangeEvent } from 'react'; import React, { useEffect, useState } from 'react';
import { import {
Button, Button,
FormControl, FormControl,
@ -189,14 +189,9 @@ export const AddVariant = ({
} }
}; };
const onPayload = (e: ChangeEvent<{ name?: string; value: unknown }>) => { const onPayload = (name: string) => (value: string) => {
e.preventDefault();
setError({ payload: '' }); setError({ payload: '' });
setPayload({ setPayload({ ...payload, [name]: value });
...payload,
// @ts-expect-error
[e.target.name]: e.target.value,
});
}; };
const onCancel = (e: React.SyntheticEvent) => { const onCancel = (e: React.SyntheticEvent) => {
@ -206,13 +201,12 @@ export const AddVariant = ({
}; };
const updateOverrideType = const updateOverrideType =
(index: number) => (e: ChangeEvent<HTMLInputElement>) => { (index: number, contextName: string) => (value: string) => {
e.preventDefault();
setOverrides( setOverrides(
overrides.map((o, i) => { overrides.map((o, i) => {
if (i === index) { if (i === index) {
// @ts-expect-error // @ts-expect-error
o[e.target.name] = e.target.value; o[contextName] = value;
} }
return o; return o;
@ -367,7 +361,7 @@ export const AddVariant = ({
className={styles.select} className={styles.select}
value={payload.type} value={payload.type}
options={payloadOptions} options={payloadOptions}
onChange={onPayload} onChange={onPayload('type')}
/> />
</Grid> </Grid>
<Grid item md={8} sm={8} xs={6}> <Grid item md={8} sm={8} xs={6}>
@ -377,7 +371,7 @@ export const AddVariant = ({
name="value" name="value"
className={commonStyles.fullWidth} className={commonStyles.fullWidth}
value={payload.value} value={payload.value}
onChange={onPayload} onChange={e => onPayload('value')(e.target.value)}
data-testid={'VARIANT_PAYLOAD_VALUE'} data-testid={'VARIANT_PAYLOAD_VALUE'}
placeholder={ placeholder={
payload.type === 'json' payload.type === 'json'

View File

@ -54,7 +54,7 @@ export const OverrideConfig = ({
classes={{ classes={{
root: classnames(commonStyles.fullWidth), root: classnames(commonStyles.fullWidth),
}} }}
onChange={updateOverrideType(i)} onChange={updateOverrideType(i, o.contextName)}
/> />
</Grid> </Grid>
<Grid md={7} sm={7} xs={6} item> <Grid md={7} sm={7} xs={6} item>

View File

@ -90,9 +90,7 @@ const StrategyConstraintInputField = ({
label="Context Field" label="Context Field"
options={constraintContextNames} options={constraintContextNames}
value={constraint.contextName || ''} value={constraint.contextName || ''}
onChange={evt => onChange={value => updateConstraint(value, 'contextName')}
updateConstraint(evt.target.value, 'contextName')
}
className={styles.contextField} className={styles.contextField}
/> />
</td> </td>
@ -102,9 +100,7 @@ const StrategyConstraintInputField = ({
label="Operator" label="Operator"
options={constraintOperators} options={constraintOperators}
value={constraint.operator} value={constraint.operator}
onChange={evt => onChange={value => updateConstraint(value, 'operator')}
updateConstraint(evt.target.value, 'operator')
}
className={styles.operator} className={styles.operator}
/> />
</td> </td>

View File

@ -57,10 +57,9 @@ export const StrategyParameter = ({
errors, errors,
}: IStrategyParameterProps) => { }: IStrategyParameterProps) => {
const styles = useStyles(); const styles = useStyles();
const handleTypeChange = (
event: React.ChangeEvent<{ name?: string; value: unknown }> const onTypeChange = (type: string) => {
) => { set({ type });
set({ type: event.target.value });
}; };
const renderParamTypeDescription = () => { const renderParamTypeDescription = () => {
@ -102,7 +101,7 @@ export const StrategyParameter = ({
name="type" name="type"
options={paramTypesOptions} options={paramTypesOptions}
value={input.type} value={input.type}
onChange={handleTypeChange} onChange={onTypeChange}
id={`prop-type-${index}-select`} id={`prop-type-${index}-select`}
className={styles.input} className={styles.input}
/> />

View File

@ -1,5 +1,4 @@
import { useContext, useState } from 'react'; import { useContext, useState } from 'react';
import PropTypes from 'prop-types';
import { Link, useHistory } from 'react-router-dom'; import { Link, useHistory } from 'react-router-dom';
import { import {
Button, Button,
@ -161,9 +160,3 @@ export const TagTypeList = () => {
</PageContent> </PageContent>
); );
}; };
TagTypeList.propTypes = {
tagTypes: PropTypes.array.isRequired,
fetchTagTypes: PropTypes.func.isRequired,
removeTagType: PropTypes.func.isRequired,
};