mirror of
https://github.com/grafana/grafana.git
synced 2025-07-29 16:43:08 +08:00

* 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
233 lines
5.9 KiB
TypeScript
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;
|