Files
kay delaney bad048b7ba Performance: Standardize lodash imports to use destructured members (#33040)
* Performance: Standardize lodash imports to use destructured members
Changes lodash imports of the form `import x from 'lodash/x'` to
`import { x } from 'lodash'` to reduce bundle size.

* Remove unnecessary _ import from Graph component

* Enforce lodash import style

* Fix remaining lodash imports
2021-04-21 09:38:00 +02:00

233 lines
5.9 KiB
TypeScript

import React, { PureComponent } from 'react';
import { css } from '@emotion/css';
import { uniqueId } from 'lodash';
import { DataSourceSettings } from '@grafana/data';
import { Button } from '../Button';
import { FormField } from '../FormField/FormField';
import { Icon } from '../Icon/Icon';
import { SecretFormField } from '../SecretFormField/SecretFormField';
import { stylesFactory } from '../../themes';
export interface CustomHeader {
id: string;
name: string;
value: string;
configured: boolean;
}
export type CustomHeaders = CustomHeader[];
export interface Props {
dataSourceConfig: DataSourceSettings<any, any>;
onChange: (config: DataSourceSettings) => void;
}
export interface State {
headers: CustomHeaders;
}
interface CustomHeaderRowProps {
header: CustomHeader;
onReset: (id: string) => void;
onRemove: (id: string) => void;
onChange: (value: CustomHeader) => void;
onBlur: () => void;
}
const getCustomHeaderRowStyles = stylesFactory(() => {
return {
layout: css`
display: flex;
align-items: center;
margin-bottom: 4px;
> * {
margin-left: 4px;
margin-bottom: 0;
height: 100%;
&:first-child,
&:last-child {
margin-left: 0;
}
}
`,
};
});
const CustomHeaderRow: React.FC<CustomHeaderRowProps> = ({ header, onBlur, onChange, onRemove, onReset }) => {
const styles = getCustomHeaderRowStyles();
return (
<div className={styles.layout}>
<FormField
label="Header"
name="name"
placeholder="X-Custom-Header"
labelWidth={5}
value={header.name || ''}
onChange={(e) => onChange({ ...header, name: e.target.value })}
onBlur={onBlur}
/>
<SecretFormField
label="Value"
name="value"
isConfigured={header.configured}
value={header.value}
labelWidth={5}
inputWidth={header.configured ? 11 : 12}
placeholder="Header Value"
onReset={() => onReset(header.id)}
onChange={(e) => onChange({ ...header, value: e.target.value })}
onBlur={onBlur}
/>
<Button
type="button"
aria-label="Remove header"
variant="secondary"
size="xs"
onClick={(_e) => onRemove(header.id)}
>
<Icon name="trash-alt" />
</Button>
</div>
);
};
CustomHeaderRow.displayName = 'CustomHeaderRow';
export class CustomHeadersSettings extends PureComponent<Props, State> {
state: State = {
headers: [],
};
constructor(props: Props) {
super(props);
const { jsonData, secureJsonData, secureJsonFields } = this.props.dataSourceConfig;
this.state = {
headers: Object.keys(jsonData)
.sort()
.filter((key) => key.startsWith('httpHeaderName'))
.map((key, index) => {
return {
id: uniqueId(),
name: jsonData[key],
value: secureJsonData !== undefined ? secureJsonData[key] : '',
configured: (secureJsonFields && secureJsonFields[`httpHeaderValue${index + 1}`]) || false,
};
}),
};
}
updateSettings = () => {
const { headers } = this.state;
// we remove every httpHeaderName* field
const newJsonData = Object.fromEntries(
Object.entries(this.props.dataSourceConfig.jsonData).filter(([key, val]) => !key.startsWith('httpHeaderName'))
);
// we remove every httpHeaderValue* field
const newSecureJsonData = Object.fromEntries(
Object.entries(this.props.dataSourceConfig.secureJsonData || {}).filter(
([key, val]) => !key.startsWith('httpHeaderValue')
)
);
// then we add the current httpHeader-fields
for (const [index, header] of headers.entries()) {
newJsonData[`httpHeaderName${index + 1}`] = header.name;
if (!header.configured) {
newSecureJsonData[`httpHeaderValue${index + 1}`] = header.value;
}
}
this.props.onChange({
...this.props.dataSourceConfig,
jsonData: newJsonData,
secureJsonData: newSecureJsonData,
});
};
onHeaderAdd = () => {
this.setState((prevState) => {
return { headers: [...prevState.headers, { id: uniqueId(), name: '', value: '', configured: false }] };
});
};
onHeaderChange = (headerIndex: number, value: CustomHeader) => {
this.setState(({ headers }) => {
return {
headers: headers.map((item, index) => {
if (headerIndex !== index) {
return item;
}
return { ...value };
}),
};
});
};
onHeaderReset = (headerId: string) => {
this.setState(({ headers }) => {
return {
headers: headers.map((h, i) => {
if (h.id !== headerId) {
return h;
}
return {
...h,
value: '',
configured: false,
};
}),
};
});
};
onHeaderRemove = (headerId: string) => {
this.setState(
({ headers }) => ({
headers: headers.filter((h) => h.id !== headerId),
}),
this.updateSettings
);
};
render() {
const { headers } = this.state;
return (
<div className={'gf-form-group'}>
<div className="gf-form">
<h6>Custom HTTP Headers</h6>
</div>
<div>
{headers.map((header, i) => (
<CustomHeaderRow
key={header.id}
header={header}
onChange={(h) => {
this.onHeaderChange(i, h);
}}
onBlur={this.updateSettings}
onRemove={this.onHeaderRemove}
onReset={this.onHeaderReset}
/>
))}
</div>
<div className="gf-form">
<Button
variant="secondary"
icon="plus"
type="button"
onClick={(e) => {
this.onHeaderAdd();
}}
>
Add header
</Button>
</div>
</div>
);
}
}
export default CustomHeadersSettings;