Cloud Watch: Standardize Config Editor Implementation (#20489)

* remove anon funcs, removed options from state, removed update method, static selects as constants

* cancellable promise

* cancel promise on unmount

* use new datasource funcs for dryer component
This commit is contained in:
Shavonn Brown
2020-01-08 08:57:52 -05:00
committed by GitHub
parent cf2dd51827
commit cd5d5bcbba
@@ -1,18 +1,26 @@
import React, { PureComponent, ChangeEvent } from 'react'; import React, { PureComponent, ChangeEvent } from 'react';
import { FormLabel, Select, Input, Button } from '@grafana/ui'; import { FormLabel, Select, Input, Button } from '@grafana/ui';
import { DataSourcePluginOptionsEditorProps, DataSourceSettings } from '@grafana/data'; import {
DataSourcePluginOptionsEditorProps,
updateDatasourcePluginJsonDataOption,
updateDatasourcePluginResetKeyOption,
updateDatasourcePluginOption,
} from '@grafana/data';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import CloudWatchDatasource from '../datasource'; import CloudWatchDatasource from '../datasource';
import { CloudWatchJsonData, CloudWatchSecureJsonData } from '../types'; import { CloudWatchJsonData, CloudWatchSecureJsonData } from '../types';
import { CancelablePromise, makePromiseCancelable } from 'app/core/utils/CancelablePromise';
export type Props = DataSourcePluginOptionsEditorProps<CloudWatchJsonData>; const authProviderOptions = [
{ label: 'Access & secret key', value: 'keys' },
{ label: 'Credentials file', value: 'credentials' },
{ label: 'ARN', value: 'arn' },
] as SelectableValue[];
type CloudwatchSettings = DataSourceSettings<CloudWatchJsonData, CloudWatchSecureJsonData>; export type Props = DataSourcePluginOptionsEditorProps<CloudWatchJsonData, CloudWatchSecureJsonData>;
export interface State { export interface State {
config: CloudwatchSettings;
authProviderOptions: SelectableValue[];
regions: SelectableValue[]; regions: SelectableValue[];
} }
@@ -20,54 +28,39 @@ export class ConfigEditor extends PureComponent<Props, State> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
const { options } = this.props;
this.state = { this.state = {
config: ConfigEditor.defaults(options),
authProviderOptions: [
{ label: 'Access & secret key', value: 'keys' },
{ label: 'Credentials file', value: 'credentials' },
{ label: 'ARN', value: 'arn' },
],
regions: [], regions: [],
}; };
this.updateDatasource(this.state.config);
} }
static getDerivedStateFromProps(props: Props, state: State) { loadRegionsPromise: CancelablePromise<any> = null;
return {
...state, componentDidMount() {
config: ConfigEditor.defaults(props.options), this.loadRegionsPromise = makePromiseCancelable(this.loadRegions());
}; this.loadRegionsPromise.promise.catch(({ isCanceled }) => {
if (isCanceled) {
console.warn('Cloud Watch ConfigEditor has unmounted, intialization was canceled');
}
});
} }
static defaults = (options: any) => { componentWillUnmount() {
options.jsonData.authType = options.jsonData.authType || 'credentials'; if (this.loadRegionsPromise) {
options.jsonData.timeField = options.jsonData.timeField || '@timestamp'; this.loadRegionsPromise.cancel();
if (!options.hasOwnProperty('secureJsonData')) {
options.secureJsonData = {};
} }
}
if (!options.hasOwnProperty('jsonData')) { onUpdateOption = (key: string, val: any, secure: boolean) => {
options.jsonData = {}; updateDatasourcePluginJsonDataOption(this.props, key, val, secure);
}
if (!options.hasOwnProperty('secureJsonFields')) {
options.secureJsonFields = {};
}
return options;
}; };
async componentDidMount() { onResetKey = (key: string) => {
this.loadRegions(); updateDatasourcePluginResetKeyOption(this.props, key);
} };
loadRegions() { async loadRegions() {
getDatasourceSrv() await getDatasourceSrv()
.loadDatasource(this.state.config.name) .loadDatasource(this.props.options.name)
.then((ds: CloudWatchDatasource) => { .then((ds: CloudWatchDatasource) => {
return ds.getRegions(); return ds.getRegions();
}) })
@@ -126,113 +119,46 @@ export class ConfigEditor extends PureComponent<Props, State> {
); );
} }
updateDatasource = async (config: any) => {
for (const j in config.jsonData) {
if (config.jsonData[j].length === 0) {
delete config.jsonData[j];
}
}
for (const k in config.secureJsonData) {
if (config.secureJsonData[k].length === 0) {
delete config.secureJsonData[k];
}
}
this.props.onOptionsChange({
...config,
});
};
onAuthProviderChange = (authType: SelectableValue<string>) => { onAuthProviderChange = (authType: SelectableValue<string>) => {
this.updateDatasource({ this.onUpdateOption('authType', authType.value, false);
...this.state.config,
jsonData: {
...this.state.config.jsonData,
authType: authType.value,
},
});
}; };
onRegionChange = (defaultRegion: SelectableValue<string>) => { onRegionChange = (defaultRegion: SelectableValue<string>) => {
this.updateDatasource({ this.onUpdateOption('defaultRegion', defaultRegion.value, false);
...this.state.config,
jsonData: {
...this.state.config.jsonData,
defaultRegion: defaultRegion.value,
},
});
}; };
onResetAccessKey = () => { onResetAccessKey = () => {
this.updateDatasource({ this.onResetKey('accessKey');
...this.state.config,
secureJsonFields: {
...this.state.config.secureJsonFields,
accessKey: false,
},
});
}; };
onAccessKeyChange = (accessKey: string) => { onAccessKeyChange = (event: ChangeEvent<HTMLInputElement>) => {
this.updateDatasource({ this.onUpdateOption('accessKey', event.target.value, true);
...this.state.config,
secureJsonData: {
...this.state.config.secureJsonData,
accessKey,
},
});
}; };
onResetSecretKey = () => { onResetSecretKey = () => {
this.updateDatasource({ this.onResetKey('secretKey');
...this.state.config,
secureJsonFields: {
...this.state.config.secureJsonFields,
secretKey: false,
},
});
}; };
onSecretKeyChange = (secretKey: string) => { onSecretKeyChange = (event: ChangeEvent<HTMLInputElement>) => {
this.updateDatasource({ this.onUpdateOption('secretKey', event.target.value, true);
...this.state.config,
secureJsonData: {
...this.state.config.secureJsonData,
secretKey,
},
});
}; };
onCredentialProfileNameChange = (database: string) => { onCredentialProfileNameChange = (event: ChangeEvent<HTMLInputElement>) => {
this.updateDatasource({ updateDatasourcePluginOption(this.props, 'database', event.target.value);
...this.state.config,
database,
});
}; };
onArnAssumeRoleChange = (assumeRoleArn: string) => { onArnAssumeRoleChange = (event: ChangeEvent<HTMLInputElement>) => {
this.updateDatasource({ this.onUpdateOption('assumeRoleArn', event.target.value, false);
...this.state.config,
jsonData: {
...this.state.config.jsonData,
assumeRoleArn,
},
});
}; };
onCustomMetricsNamespacesChange = (customMetricsNamespaces: string) => { onCustomMetricsNamespacesChange = (event: ChangeEvent<HTMLInputElement>) => {
this.updateDatasource({ this.onUpdateOption('customMetricsNamespaces', event.target.value, false);
...this.state.config,
jsonData: {
...this.state.config.jsonData,
customMetricsNamespaces,
},
});
}; };
render() { render() {
const { config, authProviderOptions, regions } = this.state; const { regions } = this.state;
const { options } = this.props;
const secureJsonData = (options.secureJsonData || {}) as CloudWatchSecureJsonData;
return ( return (
<> <>
@@ -243,14 +169,14 @@ export class ConfigEditor extends PureComponent<Props, State> {
<FormLabel className="width-14">Auth Provider</FormLabel> <FormLabel className="width-14">Auth Provider</FormLabel>
<Select <Select
className="width-30" className="width-30"
value={authProviderOptions.find(authProvider => authProvider.value === config.jsonData.authType)} value={authProviderOptions.find(authProvider => authProvider.value === options.jsonData.authType)}
options={authProviderOptions} options={authProviderOptions}
defaultValue={config.jsonData.authType} defaultValue={options.jsonData.authType}
onChange={this.onAuthProviderChange} onChange={this.onAuthProviderChange}
/> />
</div> </div>
</div> </div>
{config.jsonData.authType === 'credentials' && ( {options.jsonData.authType === 'credentials' && (
<div className="gf-form-inline"> <div className="gf-form-inline">
<div className="gf-form"> <div className="gf-form">
<FormLabel <FormLabel
@@ -263,18 +189,16 @@ export class ConfigEditor extends PureComponent<Props, State> {
<Input <Input
className="width-30" className="width-30"
placeholder="default" placeholder="default"
value={config.jsonData.database} value={options.jsonData.database}
onChange={(event: ChangeEvent<HTMLInputElement>) => onChange={this.onCredentialProfileNameChange}
this.onCredentialProfileNameChange(event.target.value)
}
/> />
</div> </div>
</div> </div>
</div> </div>
)} )}
{config.jsonData.authType === 'keys' && ( {options.jsonData.authType === 'keys' && (
<div> <div>
{config.secureJsonFields.accessKey ? ( {options.secureJsonFields.accessKey ? (
<div className="gf-form-inline"> <div className="gf-form-inline">
<div className="gf-form"> <div className="gf-form">
<FormLabel className="width-14">Access Key ID</FormLabel> <FormLabel className="width-14">Access Key ID</FormLabel>
@@ -295,14 +219,14 @@ export class ConfigEditor extends PureComponent<Props, State> {
<div className="width-30"> <div className="width-30">
<Input <Input
className="width-30" className="width-30"
value={config.secureJsonData.accessKey || ''} value={secureJsonData.accessKey || ''}
onChange={(event: ChangeEvent<HTMLInputElement>) => this.onAccessKeyChange(event.target.value)} onChange={this.onAccessKeyChange}
/> />
</div> </div>
</div> </div>
</div> </div>
)} )}
{config.secureJsonFields.secretKey ? ( {options.secureJsonFields.secretKey ? (
<div className="gf-form-inline"> <div className="gf-form-inline">
<div className="gf-form"> <div className="gf-form">
<FormLabel className="width-14">Secret Access Key</FormLabel> <FormLabel className="width-14">Secret Access Key</FormLabel>
@@ -323,8 +247,8 @@ export class ConfigEditor extends PureComponent<Props, State> {
<div className="width-30"> <div className="width-30">
<Input <Input
className="width-30" className="width-30"
value={config.secureJsonData.secretKey || ''} value={secureJsonData.secretKey || ''}
onChange={(event: ChangeEvent<HTMLInputElement>) => this.onSecretKeyChange(event.target.value)} onChange={this.onSecretKeyChange}
/> />
</div> </div>
</div> </div>
@@ -332,7 +256,7 @@ export class ConfigEditor extends PureComponent<Props, State> {
)} )}
</div> </div>
)} )}
{config.jsonData.authType === 'arn' && ( {options.jsonData.authType === 'arn' && (
<div className="gf-form-inline"> <div className="gf-form-inline">
<div className="gf-form"> <div className="gf-form">
<FormLabel className="width-14" tooltip="ARN of Assume Role"> <FormLabel className="width-14" tooltip="ARN of Assume Role">
@@ -342,8 +266,8 @@ export class ConfigEditor extends PureComponent<Props, State> {
<Input <Input
className="width-30" className="width-30"
placeholder="arn:aws:iam:*" placeholder="arn:aws:iam:*"
value={config.jsonData.assumeRoleArn || ''} value={options.jsonData.assumeRoleArn || ''}
onChange={(event: ChangeEvent<HTMLInputElement>) => this.onArnAssumeRoleChange(event.target.value)} onChange={this.onArnAssumeRoleChange}
/> />
</div> </div>
</div> </div>
@@ -359,9 +283,9 @@ export class ConfigEditor extends PureComponent<Props, State> {
</FormLabel> </FormLabel>
<Select <Select
className="width-30" className="width-30"
value={regions.find(region => region.value === config.jsonData.defaultRegion)} value={regions.find(region => region.value === options.jsonData.defaultRegion)}
options={regions} options={regions}
defaultValue={config.jsonData.defaultRegion} defaultValue={options.jsonData.defaultRegion}
onChange={this.onRegionChange} onChange={this.onRegionChange}
/> />
</div> </div>
@@ -374,10 +298,8 @@ export class ConfigEditor extends PureComponent<Props, State> {
<Input <Input
className="width-30" className="width-30"
placeholder="Namespace1,Namespace2" placeholder="Namespace1,Namespace2"
value={config.jsonData.customMetricsNamespaces || ''} value={options.jsonData.customMetricsNamespaces || ''}
onChange={(event: ChangeEvent<HTMLInputElement>) => onChange={this.onCustomMetricsNamespacesChange}
this.onCustomMetricsNamespacesChange(event.target.value)
}
/> />
</div> </div>
</div> </div>