mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Azure Monitor and Log Analytics converted and separated into components (#18259)
* Azure Monitor and Log Analytics converted and separated into components * Insights creds converted * remove angular config * fix workspaces and missing sameas key * fix workspace save * set subscriptionId key * editor fields, load workspaces btn * workspace load req fields updated * added tooltip to switch, disable buttons instead of hide * master merge and tests
This commit is contained in:
committed by
Daniel Lee
parent
e3e2cd82d7
commit
f22aaa5518
@@ -1,5 +1,7 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import uniqueId from 'lodash/uniqueId';
|
||||
import { Tooltip } from '../Tooltip/Tooltip';
|
||||
import * as PopperJS from 'popper.js';
|
||||
|
||||
export interface Props {
|
||||
label: string;
|
||||
@@ -7,6 +9,8 @@ export interface Props {
|
||||
className?: string;
|
||||
labelClass?: string;
|
||||
switchClass?: string;
|
||||
tooltip?: string;
|
||||
tooltipPlacement?: PopperJS.Placement;
|
||||
transparent?: boolean;
|
||||
onChange: (event?: React.SyntheticEvent<HTMLInputElement>) => void;
|
||||
}
|
||||
@@ -26,7 +30,16 @@ export class Switch extends PureComponent<Props, State> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { labelClass = '', switchClass = '', label, checked, transparent, className } = this.props;
|
||||
const {
|
||||
labelClass = '',
|
||||
switchClass = '',
|
||||
label,
|
||||
checked,
|
||||
transparent,
|
||||
className,
|
||||
tooltip,
|
||||
tooltipPlacement,
|
||||
} = this.props;
|
||||
|
||||
const labelId = this.state.id;
|
||||
const labelClassName = `gf-form-label ${labelClass} ${transparent ? 'gf-form-label--transparent' : ''} pointer`;
|
||||
@@ -35,7 +48,18 @@ export class Switch extends PureComponent<Props, State> {
|
||||
return (
|
||||
<div className="gf-form-switch-container-react">
|
||||
<label htmlFor={labelId} className={`gf-form gf-form-switch-container ${className || ''}`}>
|
||||
{label && <div className={labelClassName}>{label}</div>}
|
||||
{label && (
|
||||
<div className={labelClassName}>
|
||||
{label}
|
||||
{tooltip && (
|
||||
<Tooltip placement={tooltipPlacement ? tooltipPlacement : 'auto'} content={tooltip} theme={'info'}>
|
||||
<div className="gf-form-help-icon gf-form-help-icon--right-normal">
|
||||
<i className="fa fa-info-circle" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className={switchClassName}>
|
||||
<input id={labelId} type="checkbox" checked={checked} onChange={this.internalOnChange} />
|
||||
<span className="gf-form-switch__slider" />
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import ConfigEditor, { Props } from './ConfigEditor';
|
||||
|
||||
const setup = () => {
|
||||
const props: Props = {
|
||||
options: {
|
||||
id: 21,
|
||||
orgId: 1,
|
||||
name: 'Azure Monitor-10-10',
|
||||
type: 'grafana-azure-monitor-datasource',
|
||||
typeLogoUrl: '',
|
||||
access: 'proxy',
|
||||
url: '',
|
||||
password: '',
|
||||
user: '',
|
||||
database: '',
|
||||
basicAuth: false,
|
||||
basicAuthUser: '',
|
||||
basicAuthPassword: '',
|
||||
withCredentials: false,
|
||||
isDefault: false,
|
||||
jsonData: {
|
||||
azureLogAnalyticsSameAs: true,
|
||||
cloudName: 'azuremonitor',
|
||||
},
|
||||
secureJsonFields: {},
|
||||
version: 1,
|
||||
readOnly: false,
|
||||
},
|
||||
onOptionsChange: jest.fn(),
|
||||
};
|
||||
|
||||
return shallow(<ConfigEditor {...props} />);
|
||||
};
|
||||
|
||||
describe('Render', () => {
|
||||
it('should render component', () => {
|
||||
const wrapper = setup();
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,306 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { DataSourcePluginOptionsEditorProps } from '@grafana/ui';
|
||||
import { MonitorConfig } from './components/MonitorConfig';
|
||||
import { AnalyticsConfig } from './components/AnalyticsConfig';
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { getBackendSrv, BackendSrv } from 'app/core/services/backend_srv';
|
||||
import AzureMonitorDatasource from './azure_monitor/azure_monitor_datasource';
|
||||
import AzureLogAnalyticsDatasource from './azure_log_analytics/azure_log_analytics_datasource';
|
||||
import { InsightsConfig } from './components/InsightsConfig';
|
||||
|
||||
export type Props = DataSourcePluginOptionsEditorProps<any>;
|
||||
|
||||
export interface State {
|
||||
config: any;
|
||||
subscriptions: SelectableValue[];
|
||||
logAnalyticsSubscriptions: SelectableValue[];
|
||||
logAnalyticsWorkspaces: SelectableValue[];
|
||||
}
|
||||
|
||||
export class ConfigEditor extends PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
const { options } = this.props;
|
||||
|
||||
this.state = {
|
||||
config: ConfigEditor.keyFill(options),
|
||||
subscriptions: [],
|
||||
logAnalyticsSubscriptions: [],
|
||||
logAnalyticsWorkspaces: [],
|
||||
};
|
||||
|
||||
this.backendSrv = getBackendSrv();
|
||||
this.templateSrv = new TemplateSrv();
|
||||
|
||||
if (options.id) {
|
||||
this.state.config.url = '/api/datasources/proxy/' + options.id;
|
||||
this.init();
|
||||
}
|
||||
|
||||
this.updateDatasource(this.state.config);
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(props: Props, state: State) {
|
||||
return {
|
||||
...state,
|
||||
config: ConfigEditor.keyFill(props.options),
|
||||
};
|
||||
}
|
||||
|
||||
static keyFill = (options: any) => {
|
||||
options.jsonData.cloudName = options.jsonData.cloudName || 'azuremonitor';
|
||||
|
||||
if (!options.jsonData.hasOwnProperty('azureLogAnalyticsSameAs')) {
|
||||
options.jsonData.azureLogAnalyticsSameAs = true;
|
||||
}
|
||||
|
||||
if (!options.hasOwnProperty('editorSecureJsonData')) {
|
||||
options.editorSecureJsonData = {
|
||||
clientSecret: '',
|
||||
logAnalyticsClientSecret: '',
|
||||
appInsightsApiKey: '',
|
||||
};
|
||||
}
|
||||
|
||||
if (!options.hasOwnProperty('editorJsonData')) {
|
||||
options.editorJsonData = {
|
||||
clientId: options.jsonData.clientId || '',
|
||||
tenantId: options.jsonData.tenantId || '',
|
||||
subscriptionId: options.jsonData.subscriptionId || '',
|
||||
logAnalyticsClientId: options.jsonData.logAnalyticsClientId || '',
|
||||
logAnalyticsDefaultWorkspace: options.jsonData.logAnalyticsDefaultWorkspace || '',
|
||||
logAnalyticsTenantId: options.jsonData.logAnalyticsTenantId || '',
|
||||
logAnalyticsSubscriptionId: options.jsonData.logAnalyticsSubscriptionId || '',
|
||||
appInsightsAppId: options.jsonData.appInsightsAppId || '',
|
||||
};
|
||||
}
|
||||
|
||||
if (!options.hasOwnProperty('secureJsonFields')) {
|
||||
options.secureJsonFields = {
|
||||
clientSecret: false,
|
||||
logAnalyticsClientSecret: false,
|
||||
appInsightsApiKey: false,
|
||||
};
|
||||
}
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
backendSrv: BackendSrv = null;
|
||||
templateSrv: TemplateSrv = null;
|
||||
|
||||
init = async () => {
|
||||
await this.getSubscriptions();
|
||||
|
||||
if (!this.state.config.jsonData.azureLogAnalyticsSameAs) {
|
||||
await this.getLogAnalyticsSubscriptions();
|
||||
}
|
||||
};
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
for (const m in config.editorJsonData) {
|
||||
if (!config.hasOwnProperty('jsonData')) {
|
||||
config.jsonData = {};
|
||||
}
|
||||
if (config.editorJsonData[m].length === 0) {
|
||||
if (config.hasOwnProperty('jsonData') && config.jsonData.hasOwnProperty(m)) {
|
||||
delete config.jsonData[m];
|
||||
}
|
||||
} else {
|
||||
config.jsonData[m] = config.editorJsonData[m];
|
||||
}
|
||||
}
|
||||
|
||||
for (const l in config.editorSecureJsonData) {
|
||||
if (!config.hasOwnProperty('secureJsonData')) {
|
||||
config.secureJsonData = {};
|
||||
}
|
||||
if (config.editorSecureJsonData[l].length === 0) {
|
||||
if (config.hasOwnProperty('secureJsonData') && config.secureJsonData.hasOwnProperty(l)) {
|
||||
delete config.secureJsonData[l];
|
||||
}
|
||||
} else {
|
||||
config.secureJsonData[l] = config.editorSecureJsonData[l];
|
||||
}
|
||||
}
|
||||
|
||||
this.props.onOptionsChange({
|
||||
...config,
|
||||
});
|
||||
};
|
||||
|
||||
hasNecessaryCredentials = () => {
|
||||
if (!this.state.config.secureJsonFields.clientSecret && !this.state.config.editorSecureJsonData.clientSecret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.state.config.jsonData.clientId || !this.state.config.jsonData.tenantId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
logAnalyticsHasNecessaryCredentials = () => {
|
||||
if (
|
||||
!this.state.config.secureJsonFields.logAnalyticsClientSecret &&
|
||||
!this.state.config.editorSecureJsonData.logAnalyticsClientSecret
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.state.config.jsonData.logAnalyticsClientId || !this.state.config.jsonData.logAnalyticsTenantId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
onConfigUpdate = (config: any) => {
|
||||
this.updateDatasource(config);
|
||||
};
|
||||
|
||||
onLoadSubscriptions = async (type?: string) => {
|
||||
await this.backendSrv.put(`/api/datasources/${this.state.config.id}`, this.state.config).then(() => {
|
||||
this.updateDatasource({
|
||||
...this.state.config,
|
||||
version: this.state.config.version + 1,
|
||||
});
|
||||
});
|
||||
|
||||
if (type && type === 'workspacesloganalytics') {
|
||||
this.getLogAnalyticsSubscriptions();
|
||||
} else {
|
||||
this.getSubscriptions();
|
||||
}
|
||||
};
|
||||
|
||||
getSubscriptions = async () => {
|
||||
if (!this.hasNecessaryCredentials()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const azureMonitorDatasource = new AzureMonitorDatasource(this.state.config, this.backendSrv, this.templateSrv);
|
||||
|
||||
let subscriptions = (await azureMonitorDatasource.getSubscriptions()) || [];
|
||||
subscriptions = subscriptions.map((subscription: any) => {
|
||||
return {
|
||||
value: subscription.value,
|
||||
label: subscription.text,
|
||||
};
|
||||
});
|
||||
|
||||
if (subscriptions && subscriptions.length > 0) {
|
||||
this.setState({ subscriptions });
|
||||
|
||||
this.state.config.editorJsonData.subscriptionId =
|
||||
this.state.config.editorJsonData.subscriptionId || subscriptions[0].value;
|
||||
}
|
||||
|
||||
if (this.state.config.editorJsonData.subscriptionId && this.state.config.jsonData.azureLogAnalyticsSameAs) {
|
||||
await this.getWorkspaces();
|
||||
}
|
||||
};
|
||||
|
||||
getLogAnalyticsSubscriptions = async () => {
|
||||
if (!this.logAnalyticsHasNecessaryCredentials()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const azureMonitorDatasource = new AzureMonitorDatasource(this.state.config, this.backendSrv, this.templateSrv);
|
||||
|
||||
let logAnalyticsSubscriptions = (await azureMonitorDatasource.getSubscriptions('workspacesloganalytics')) || [];
|
||||
logAnalyticsSubscriptions = logAnalyticsSubscriptions.map((subscription: any) => {
|
||||
return {
|
||||
value: subscription.value,
|
||||
label: subscription.text,
|
||||
};
|
||||
});
|
||||
|
||||
if (logAnalyticsSubscriptions && logAnalyticsSubscriptions.length > 0) {
|
||||
this.setState({ logAnalyticsSubscriptions });
|
||||
|
||||
this.state.config.editorJsonData.logAnalyticsSubscriptionId =
|
||||
this.state.config.editorJsonData.logAnalyticsSubscriptionId || logAnalyticsSubscriptions[0].value;
|
||||
}
|
||||
|
||||
if (this.state.config.editorJsonData.logAnalyticsSubscriptionId) {
|
||||
await this.getWorkspaces();
|
||||
}
|
||||
};
|
||||
|
||||
getWorkspaces = async () => {
|
||||
const sameAs =
|
||||
this.state.config.jsonData.azureLogAnalyticsSameAs && this.state.config.editorJsonData.subscriptionId;
|
||||
if (!sameAs && !this.state.config.editorJsonData.logAnalyticsSubscriptionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const azureLogAnalyticsDatasource = new AzureLogAnalyticsDatasource(
|
||||
this.state.config,
|
||||
this.backendSrv,
|
||||
this.templateSrv
|
||||
);
|
||||
|
||||
let logAnalyticsWorkspaces = await azureLogAnalyticsDatasource.getWorkspaces(
|
||||
sameAs
|
||||
? this.state.config.editorJsonData.subscriptionId
|
||||
: this.state.config.editorJsonData.logAnalyticsSubscriptionId
|
||||
);
|
||||
logAnalyticsWorkspaces = logAnalyticsWorkspaces.map((workspace: any) => {
|
||||
return {
|
||||
value: workspace.value,
|
||||
label: workspace.text,
|
||||
};
|
||||
});
|
||||
|
||||
if (logAnalyticsWorkspaces.length > 0) {
|
||||
this.setState({ logAnalyticsWorkspaces });
|
||||
|
||||
this.state.config.editorJsonData.logAnalyticsDefaultWorkspace =
|
||||
this.state.config.editorJsonData.logAnalyticsDefaultWorkspace || logAnalyticsWorkspaces[0].value;
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { config, subscriptions, logAnalyticsSubscriptions, logAnalyticsWorkspaces } = this.state;
|
||||
|
||||
return (
|
||||
<>
|
||||
<MonitorConfig
|
||||
datasourceConfig={config}
|
||||
subscriptions={subscriptions}
|
||||
onLoadSubscriptions={this.onLoadSubscriptions}
|
||||
onDatasourceUpdate={this.onConfigUpdate}
|
||||
/>
|
||||
|
||||
<AnalyticsConfig
|
||||
datasourceConfig={config}
|
||||
logAnalyticsWorkspaces={logAnalyticsWorkspaces}
|
||||
logAnalyticsSubscriptions={logAnalyticsSubscriptions}
|
||||
onLoadSubscriptions={this.onLoadSubscriptions}
|
||||
onDatasourceUpdate={this.onConfigUpdate}
|
||||
onLoadWorkspaces={this.getWorkspaces}
|
||||
/>
|
||||
|
||||
<InsightsConfig datasourceConfig={config} onDatasourceUpdate={this.onConfigUpdate} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ConfigEditor;
|
||||
@@ -0,0 +1,147 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<Fragment>
|
||||
<MonitorConfig
|
||||
datasourceConfig={
|
||||
Object {
|
||||
"access": "proxy",
|
||||
"basicAuth": false,
|
||||
"basicAuthPassword": "",
|
||||
"basicAuthUser": "",
|
||||
"database": "",
|
||||
"editorJsonData": Object {
|
||||
"appInsightsAppId": "",
|
||||
"clientId": "",
|
||||
"logAnalyticsClientId": "",
|
||||
"logAnalyticsDefaultWorkspace": "",
|
||||
"logAnalyticsSubscriptionId": "",
|
||||
"logAnalyticsTenantId": "",
|
||||
"subscriptionId": "",
|
||||
"tenantId": "",
|
||||
},
|
||||
"editorSecureJsonData": Object {
|
||||
"appInsightsApiKey": "",
|
||||
"clientSecret": "",
|
||||
"logAnalyticsClientSecret": "",
|
||||
},
|
||||
"id": 21,
|
||||
"isDefault": false,
|
||||
"jsonData": Object {
|
||||
"azureLogAnalyticsSameAs": true,
|
||||
"cloudName": "azuremonitor",
|
||||
},
|
||||
"name": "Azure Monitor-10-10",
|
||||
"orgId": 1,
|
||||
"password": "",
|
||||
"readOnly": false,
|
||||
"secureJsonData": Object {},
|
||||
"secureJsonFields": Object {},
|
||||
"type": "grafana-azure-monitor-datasource",
|
||||
"typeLogoUrl": "",
|
||||
"url": "/api/datasources/proxy/21",
|
||||
"user": "",
|
||||
"version": 1,
|
||||
"withCredentials": false,
|
||||
}
|
||||
}
|
||||
onDatasourceUpdate={[Function]}
|
||||
onLoadSubscriptions={[Function]}
|
||||
subscriptions={Array []}
|
||||
/>
|
||||
<AnalyticsConfig
|
||||
datasourceConfig={
|
||||
Object {
|
||||
"access": "proxy",
|
||||
"basicAuth": false,
|
||||
"basicAuthPassword": "",
|
||||
"basicAuthUser": "",
|
||||
"database": "",
|
||||
"editorJsonData": Object {
|
||||
"appInsightsAppId": "",
|
||||
"clientId": "",
|
||||
"logAnalyticsClientId": "",
|
||||
"logAnalyticsDefaultWorkspace": "",
|
||||
"logAnalyticsSubscriptionId": "",
|
||||
"logAnalyticsTenantId": "",
|
||||
"subscriptionId": "",
|
||||
"tenantId": "",
|
||||
},
|
||||
"editorSecureJsonData": Object {
|
||||
"appInsightsApiKey": "",
|
||||
"clientSecret": "",
|
||||
"logAnalyticsClientSecret": "",
|
||||
},
|
||||
"id": 21,
|
||||
"isDefault": false,
|
||||
"jsonData": Object {
|
||||
"azureLogAnalyticsSameAs": true,
|
||||
"cloudName": "azuremonitor",
|
||||
},
|
||||
"name": "Azure Monitor-10-10",
|
||||
"orgId": 1,
|
||||
"password": "",
|
||||
"readOnly": false,
|
||||
"secureJsonData": Object {},
|
||||
"secureJsonFields": Object {},
|
||||
"type": "grafana-azure-monitor-datasource",
|
||||
"typeLogoUrl": "",
|
||||
"url": "/api/datasources/proxy/21",
|
||||
"user": "",
|
||||
"version": 1,
|
||||
"withCredentials": false,
|
||||
}
|
||||
}
|
||||
logAnalyticsSubscriptions={Array []}
|
||||
logAnalyticsWorkspaces={Array []}
|
||||
onDatasourceUpdate={[Function]}
|
||||
onLoadSubscriptions={[Function]}
|
||||
onLoadWorkspaces={[Function]}
|
||||
/>
|
||||
<InsightsConfig
|
||||
datasourceConfig={
|
||||
Object {
|
||||
"access": "proxy",
|
||||
"basicAuth": false,
|
||||
"basicAuthPassword": "",
|
||||
"basicAuthUser": "",
|
||||
"database": "",
|
||||
"editorJsonData": Object {
|
||||
"appInsightsAppId": "",
|
||||
"clientId": "",
|
||||
"logAnalyticsClientId": "",
|
||||
"logAnalyticsDefaultWorkspace": "",
|
||||
"logAnalyticsSubscriptionId": "",
|
||||
"logAnalyticsTenantId": "",
|
||||
"subscriptionId": "",
|
||||
"tenantId": "",
|
||||
},
|
||||
"editorSecureJsonData": Object {
|
||||
"appInsightsApiKey": "",
|
||||
"clientSecret": "",
|
||||
"logAnalyticsClientSecret": "",
|
||||
},
|
||||
"id": 21,
|
||||
"isDefault": false,
|
||||
"jsonData": Object {
|
||||
"azureLogAnalyticsSameAs": true,
|
||||
"cloudName": "azuremonitor",
|
||||
},
|
||||
"name": "Azure Monitor-10-10",
|
||||
"orgId": 1,
|
||||
"password": "",
|
||||
"readOnly": false,
|
||||
"secureJsonData": Object {},
|
||||
"secureJsonFields": Object {},
|
||||
"type": "grafana-azure-monitor-datasource",
|
||||
"typeLogoUrl": "",
|
||||
"url": "/api/datasources/proxy/21",
|
||||
"user": "",
|
||||
"version": 1,
|
||||
"withCredentials": false,
|
||||
}
|
||||
}
|
||||
onDatasourceUpdate={[Function]}
|
||||
/>
|
||||
</Fragment>
|
||||
`;
|
||||
@@ -5,7 +5,6 @@ import { AzureMonitorQuery, AzureDataSourceJsonData } from '../types';
|
||||
import { DataQueryRequest, DataSourceInstanceSettings } from '@grafana/ui';
|
||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { IQService } from 'angular';
|
||||
|
||||
export default class AzureLogAnalyticsDatasource {
|
||||
id: number;
|
||||
@@ -20,8 +19,7 @@ export default class AzureLogAnalyticsDatasource {
|
||||
constructor(
|
||||
private instanceSettings: DataSourceInstanceSettings<AzureDataSourceJsonData>,
|
||||
private backendSrv: BackendSrv,
|
||||
private templateSrv: TemplateSrv,
|
||||
private $q: IQService
|
||||
private templateSrv: TemplateSrv
|
||||
) {
|
||||
this.id = instanceSettings.id;
|
||||
this.baseUrl = this.instanceSettings.jsonData.azureLogAnalyticsSameAs
|
||||
@@ -113,7 +111,7 @@ export default class AzureLogAnalyticsDatasource {
|
||||
|
||||
const promises = this.doQueries(queries);
|
||||
|
||||
return this.$q.all(promises).then(results => {
|
||||
return Promise.all(promises).then(results => {
|
||||
return new ResponseParser(results).parseQueryResult();
|
||||
});
|
||||
}
|
||||
@@ -124,8 +122,7 @@ export default class AzureLogAnalyticsDatasource {
|
||||
|
||||
const promises = this.doQueries(queries);
|
||||
|
||||
return this.$q
|
||||
.all(promises)
|
||||
return Promise.all(promises)
|
||||
.then(results => {
|
||||
return new ResponseParser(results).parseToVariables();
|
||||
})
|
||||
@@ -198,7 +195,7 @@ export default class AzureLogAnalyticsDatasource {
|
||||
|
||||
annotationQuery(options: any) {
|
||||
if (!options.annotation.rawQuery) {
|
||||
return this.$q.reject({
|
||||
return Promise.reject({
|
||||
message: 'Query missing in annotation definition',
|
||||
});
|
||||
}
|
||||
@@ -207,7 +204,7 @@ export default class AzureLogAnalyticsDatasource {
|
||||
|
||||
const promises = this.doQueries(queries);
|
||||
|
||||
return this.$q.all(promises).then(results => {
|
||||
return Promise.all(promises).then(results => {
|
||||
const annotations = new ResponseParser(results).transformToAnnotations(options);
|
||||
return annotations;
|
||||
});
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import AnalyticsConfig, { Props } from './AnalyticsConfig';
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
const props: Props = {
|
||||
datasourceConfig: {
|
||||
id: 21,
|
||||
orgId: 1,
|
||||
name: 'Azure Monitor-10-10',
|
||||
type: 'grafana-azure-monitor-datasource',
|
||||
typeLogoUrl: '',
|
||||
access: 'proxy',
|
||||
url: '',
|
||||
password: '',
|
||||
user: '',
|
||||
database: '',
|
||||
basicAuth: false,
|
||||
basicAuthUser: '',
|
||||
basicAuthPassword: '',
|
||||
withCredentials: false,
|
||||
isDefault: false,
|
||||
jsonData: {
|
||||
azureLogAnalyticsSameAs: false,
|
||||
},
|
||||
secureJsonFields: {
|
||||
logAnalyticsClientSecret: false,
|
||||
},
|
||||
editorJsonData: {
|
||||
logAnalyticsDefaultWorkspace: '',
|
||||
logAnalyticsClientSecret: '',
|
||||
logAnalyticsTenantId: '',
|
||||
},
|
||||
editorSecureJsonData: {
|
||||
logAnalyticsClientSecret: '',
|
||||
},
|
||||
version: 1,
|
||||
readOnly: false,
|
||||
},
|
||||
logAnalyticsSubscriptions: [],
|
||||
logAnalyticsWorkspaces: [],
|
||||
onDatasourceUpdate: jest.fn(),
|
||||
onLoadSubscriptions: jest.fn(),
|
||||
onLoadWorkspaces: jest.fn(),
|
||||
};
|
||||
|
||||
Object.assign(props, propOverrides);
|
||||
|
||||
return shallow(<AnalyticsConfig {...props} />);
|
||||
};
|
||||
|
||||
describe('Render', () => {
|
||||
it('should render component', () => {
|
||||
const wrapper = setup();
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should disable log analytics credentials form', () => {
|
||||
const wrapper = setup({
|
||||
jsonData: {
|
||||
azureLogAnalyticsSameAs: true,
|
||||
},
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should enable azure log analytics load workspaces button', () => {
|
||||
const wrapper = setup({
|
||||
editorJsonData: {
|
||||
logAnalyticsDefaultWorkspace: '',
|
||||
logAnalyticsTenantId: 'e7f3f661-a933-4b3f-8176-51c4f982ec48',
|
||||
logAnalyticsClientId: '44693801-6ee6-49de-9b2d-9106972f9572',
|
||||
logAnalyticsSubscriptionId: 'e3fe4fde-ad5e-4d60-9974-e2f3562ffdf2',
|
||||
logAnalyticsClientSecret: 'cddcc020-2c94-460a-a3d0-df3147ffa792',
|
||||
},
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,212 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { AzureCredentialsForm } from './AzureCredentialsForm';
|
||||
import { Switch, FormLabel, Select, Button } from '@grafana/ui';
|
||||
|
||||
export interface Props {
|
||||
datasourceConfig: any;
|
||||
logAnalyticsSubscriptions: SelectableValue[];
|
||||
logAnalyticsWorkspaces: SelectableValue[];
|
||||
onDatasourceUpdate: (config: any) => void;
|
||||
onLoadSubscriptions: (type?: string) => void;
|
||||
onLoadWorkspaces: (type?: string) => void;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
config: any;
|
||||
logAnalyticsSubscriptions: SelectableValue[];
|
||||
logAnalyticsWorkspaces: SelectableValue[];
|
||||
}
|
||||
|
||||
export class AnalyticsConfig extends PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
const { datasourceConfig } = this.props;
|
||||
|
||||
this.state = {
|
||||
config: datasourceConfig,
|
||||
logAnalyticsSubscriptions: [],
|
||||
logAnalyticsWorkspaces: [],
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(props: Props, state: State) {
|
||||
return {
|
||||
...state,
|
||||
config: props.datasourceConfig,
|
||||
logAnalyticsSubscriptions: props.logAnalyticsSubscriptions,
|
||||
logAnalyticsWorkspaces: props.logAnalyticsWorkspaces,
|
||||
};
|
||||
}
|
||||
|
||||
onLogAnalyticsTenantIdChange = (logAnalyticsTenantId: string) => {
|
||||
this.props.onDatasourceUpdate({
|
||||
...this.state.config,
|
||||
editorJsonData: {
|
||||
...this.state.config.editorJsonData,
|
||||
logAnalyticsTenantId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onLogAnalyticsClientIdChange = (logAnalyticsClientId: string) => {
|
||||
this.props.onDatasourceUpdate({
|
||||
...this.state.config,
|
||||
editorJsonData: {
|
||||
...this.state.config.editorJsonData,
|
||||
logAnalyticsClientId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onLogAnalyticsClientSecretChange = (logAnalyticsClientSecret: string) => {
|
||||
this.props.onDatasourceUpdate({
|
||||
...this.state.config,
|
||||
editorSecureJsonData: {
|
||||
...this.state.config.editorSecureJsonData,
|
||||
logAnalyticsClientSecret,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onLogAnalyticsResetClientSecret = () => {
|
||||
this.props.onDatasourceUpdate({
|
||||
...this.state.config,
|
||||
version: this.state.config.version + 1,
|
||||
secureJsonFields: { ...this.state.config.secureJsonFields, logAnalyticsClientSecret: false },
|
||||
});
|
||||
};
|
||||
|
||||
onLogAnalyticsSubscriptionSelect = (logAnalyticsSubscription: SelectableValue<string>) => {
|
||||
this.props.onDatasourceUpdate({
|
||||
...this.state.config,
|
||||
editorJsonData: {
|
||||
...this.state.config.editorJsonData,
|
||||
logAnalyticsSubscriptionId: logAnalyticsSubscription.value,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onWorkspaceSelectChange = (logAnalyticsDefaultWorkspace: SelectableValue<string>) => {
|
||||
this.props.onDatasourceUpdate({
|
||||
...this.state.config,
|
||||
editorJsonData: {
|
||||
...this.state.config.editorJsonData,
|
||||
logAnalyticsDefaultWorkspace: logAnalyticsDefaultWorkspace.value,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onAzureLogAnalyticsSameAsChange = (azureLogAnalyticsSameAs: boolean) => {
|
||||
this.props.onDatasourceUpdate({
|
||||
...this.state.config,
|
||||
jsonData: {
|
||||
...this.state.config.jsonData,
|
||||
azureLogAnalyticsSameAs,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
hasWorkspaceRequiredFields = () => {
|
||||
const {
|
||||
config: { editorJsonData, editorSecureJsonData, jsonData, secureJsonFields },
|
||||
} = this.state;
|
||||
|
||||
if (jsonData.azureLogAnalyticsSameAs) {
|
||||
return (
|
||||
editorJsonData.tenantId &&
|
||||
editorJsonData.clientId &&
|
||||
editorJsonData.subscriptionId &&
|
||||
(editorSecureJsonData.clientSecret || secureJsonFields.clientSecret)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
editorJsonData.logAnalyticsTenantId.length &&
|
||||
editorJsonData.logAnalyticsClientId.length &&
|
||||
editorJsonData.logAnalyticsSubscriptionId &&
|
||||
(secureJsonFields.logAnalyticsClientSecret || editorSecureJsonData.logAnalyticsClientSecret)
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
config: { editorJsonData, editorSecureJsonData, jsonData, secureJsonFields },
|
||||
logAnalyticsSubscriptions,
|
||||
logAnalyticsWorkspaces,
|
||||
} = this.state;
|
||||
|
||||
const addtlAttrs = {
|
||||
...(jsonData.azureLogAnalyticsSameAs && {
|
||||
tooltip: 'Workspaces are pulled from default subscription selected above.',
|
||||
}),
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<h3 className="page-heading">Azure Log Analytics API Details</h3>
|
||||
<Switch
|
||||
label="Same details as Azure Monitor API"
|
||||
checked={jsonData.azureLogAnalyticsSameAs}
|
||||
onChange={event => this.onAzureLogAnalyticsSameAsChange(!jsonData.azureLogAnalyticsSameAs)}
|
||||
{...addtlAttrs}
|
||||
/>
|
||||
{!jsonData.azureLogAnalyticsSameAs && (
|
||||
<AzureCredentialsForm
|
||||
subscriptionOptions={logAnalyticsSubscriptions}
|
||||
selectedSubscription={editorJsonData.logAnalyticsSubscriptionId}
|
||||
tenantId={editorJsonData.logAnalyticsTenantId}
|
||||
clientId={editorJsonData.logAnalyticsClientId}
|
||||
clientSecret={editorSecureJsonData.logAnalyticsClientSecret}
|
||||
clientSecretConfigured={secureJsonFields.logAnalyticsClientSecret}
|
||||
onSubscriptionSelectChange={this.onLogAnalyticsSubscriptionSelect}
|
||||
onTenantIdChange={this.onLogAnalyticsTenantIdChange}
|
||||
onClientIdChange={this.onLogAnalyticsClientIdChange}
|
||||
onClientSecretChange={this.onLogAnalyticsClientSecretChange}
|
||||
onResetClientSecret={this.onLogAnalyticsResetClientSecret}
|
||||
onLoadSubscriptions={() => this.props.onLoadSubscriptions('workspacesloganalytics')}
|
||||
/>
|
||||
)}
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<FormLabel
|
||||
className="width-12"
|
||||
tooltip="Choose the default/preferred Workspace for Azure Log Analytics queries."
|
||||
>
|
||||
Default Workspace
|
||||
</FormLabel>
|
||||
<div className="width-25">
|
||||
<Select
|
||||
value={logAnalyticsWorkspaces.find(
|
||||
workspace => workspace.value === editorJsonData.logAnalyticsDefaultWorkspace
|
||||
)}
|
||||
options={logAnalyticsWorkspaces}
|
||||
defaultValue={editorJsonData.logAnalyticsDefaultWorkspace}
|
||||
onChange={this.onWorkspaceSelectChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<div className="max-width-30 gf-form-inline">
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
type="button"
|
||||
onClick={() => this.props.onLoadWorkspaces()}
|
||||
disabled={!this.hasWorkspaceRequiredFields()}
|
||||
>
|
||||
Load Workspaces
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default AnalyticsConfig;
|
||||
@@ -0,0 +1,53 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import AzureCredentialsForm, { Props } from './AzureCredentialsForm';
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
const props: Props = {
|
||||
selectedAzureCloud: 'azuremonitor',
|
||||
selectedSubscription: '44693801-6ee6-49de-9b2d-9106972f9572',
|
||||
azureCloudOptions: [
|
||||
{ value: 'azuremonitor', label: 'Azure' },
|
||||
{ value: 'govazuremonitor', label: 'Azure US Government' },
|
||||
{ value: 'germanyazuremonitor', label: 'Azure Germany' },
|
||||
{ value: 'chinaazuremonitor', label: 'Azure China' },
|
||||
],
|
||||
tenantId: 'e7f3f661-a933-4b3f-8176-51c4f982ec48',
|
||||
clientId: '77409fad-c0a9-45df-9e25-f1ff95af6554',
|
||||
clientSecret: '',
|
||||
clientSecretConfigured: false,
|
||||
subscriptionOptions: [],
|
||||
onAzureCloudChange: jest.fn(),
|
||||
onSubscriptionSelectChange: jest.fn(),
|
||||
onTenantIdChange: jest.fn(),
|
||||
onClientIdChange: jest.fn(),
|
||||
onClientSecretChange: jest.fn(),
|
||||
onResetClientSecret: jest.fn(),
|
||||
onLoadSubscriptions: jest.fn(),
|
||||
};
|
||||
|
||||
Object.assign(props, propOverrides);
|
||||
|
||||
return shallow(<AzureCredentialsForm {...props} />);
|
||||
};
|
||||
|
||||
describe('Render', () => {
|
||||
it('should render component', () => {
|
||||
const wrapper = setup();
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should disable azure monitor secret input', () => {
|
||||
const wrapper = setup({
|
||||
clientSecretConfigured: true,
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should enable azure monitor load subscriptions button', () => {
|
||||
const wrapper = setup({
|
||||
clientSecret: 'e7f3f661-a933-4b3f-8176-51c4f982ec48',
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,200 @@
|
||||
import React, { ChangeEvent, PureComponent } from 'react';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { Input, FormLabel, Select, Button } from '@grafana/ui';
|
||||
|
||||
export interface Props {
|
||||
selectedAzureCloud?: string;
|
||||
selectedSubscription?: string;
|
||||
azureCloudOptions?: SelectableValue[];
|
||||
tenantId: string;
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
clientSecretConfigured: boolean;
|
||||
subscriptionOptions?: SelectableValue[];
|
||||
onAzureCloudChange?: (value: SelectableValue<string>) => void;
|
||||
onSubscriptionSelectChange?: (value: SelectableValue<string>) => void;
|
||||
onTenantIdChange: (tenantId: string) => void;
|
||||
onClientIdChange: (clientId: string) => void;
|
||||
onClientSecretChange: (clientSecret: string) => void;
|
||||
onResetClientSecret: () => void;
|
||||
onLoadSubscriptions?: () => void;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
selectedAzureCloud?: string;
|
||||
selectedSubscription: string;
|
||||
tenantId: string;
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
clientSecretConfigured: boolean;
|
||||
}
|
||||
|
||||
export class AzureCredentialsForm extends PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
const {
|
||||
selectedAzureCloud,
|
||||
selectedSubscription,
|
||||
tenantId,
|
||||
clientId,
|
||||
clientSecret,
|
||||
clientSecretConfigured,
|
||||
} = this.props;
|
||||
|
||||
this.state = {
|
||||
selectedAzureCloud,
|
||||
selectedSubscription,
|
||||
tenantId,
|
||||
clientId,
|
||||
clientSecret,
|
||||
clientSecretConfigured,
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps: Props, prevState: Props) {
|
||||
const { selectedAzureCloud, tenantId, clientId, clientSecret, clientSecretConfigured } = nextProps;
|
||||
return {
|
||||
selectedAzureCloud,
|
||||
tenantId,
|
||||
clientId,
|
||||
clientSecret,
|
||||
clientSecretConfigured,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
azureCloudOptions,
|
||||
subscriptionOptions,
|
||||
onAzureCloudChange,
|
||||
onSubscriptionSelectChange,
|
||||
onTenantIdChange,
|
||||
onClientIdChange,
|
||||
onClientSecretChange,
|
||||
onResetClientSecret,
|
||||
onLoadSubscriptions,
|
||||
} = this.props;
|
||||
const {
|
||||
selectedAzureCloud,
|
||||
selectedSubscription,
|
||||
tenantId,
|
||||
clientId,
|
||||
clientSecret,
|
||||
clientSecretConfigured,
|
||||
} = this.state;
|
||||
const hasRequiredFields = tenantId && clientId && (clientSecret || clientSecretConfigured);
|
||||
const hasSubscriptions = onLoadSubscriptions && subscriptionOptions;
|
||||
return (
|
||||
<>
|
||||
<div className="gf-form-group">
|
||||
{azureCloudOptions && (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<FormLabel className="width-12" tooltip="Choose an Azure Cloud.">
|
||||
Azure Cloud
|
||||
</FormLabel>
|
||||
<Select
|
||||
className="width-15"
|
||||
value={azureCloudOptions.find(azureCloud => azureCloud.value === selectedAzureCloud)}
|
||||
options={azureCloudOptions}
|
||||
defaultValue={selectedAzureCloud}
|
||||
onChange={onAzureCloudChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<FormLabel className="width-12">Directory (tenant) ID</FormLabel>
|
||||
<div className="width-15">
|
||||
<Input
|
||||
className="width-30"
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value={tenantId}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => onTenantIdChange(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<FormLabel className="width-12">Application (client) ID</FormLabel>
|
||||
<div className="width-15">
|
||||
<Input
|
||||
className="width-30"
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value={clientId}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => onClientIdChange(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{clientSecretConfigured ? (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<FormLabel className="width-12">Client Secret</FormLabel>
|
||||
<Input className="width-25" placeholder="configured" disabled={true} />
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<div className="max-width-30 gf-form-inline">
|
||||
<Button variant="secondary" type="button" onClick={onResetClientSecret}>
|
||||
reset
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<FormLabel className="width-12">Client Secret</FormLabel>
|
||||
<div className="width-15">
|
||||
<Input
|
||||
className="width-30"
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value={clientSecret}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => onClientSecretChange(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{hasSubscriptions && (
|
||||
<>
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<FormLabel className="width-12">Default Subscription</FormLabel>
|
||||
<div className="width-25">
|
||||
<Select
|
||||
value={subscriptionOptions.find(subscription => subscription.value === selectedSubscription)}
|
||||
options={subscriptionOptions}
|
||||
defaultValue={selectedSubscription}
|
||||
onChange={onSubscriptionSelectChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<div className="max-width-30 gf-form-inline">
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
type="button"
|
||||
onClick={onLoadSubscriptions}
|
||||
disabled={!hasRequiredFields}
|
||||
>
|
||||
Load Subscriptions
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default AzureCredentialsForm;
|
||||
@@ -0,0 +1,84 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import InsightsConfig, { Props } from './InsightsConfig';
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
const props: Props = {
|
||||
datasourceConfig: {
|
||||
id: 21,
|
||||
orgId: 1,
|
||||
name: 'Azure Monitor-10-10',
|
||||
type: 'grafana-azure-monitor-datasource',
|
||||
typeLogoUrl: '',
|
||||
access: 'proxy',
|
||||
url: '',
|
||||
password: '',
|
||||
user: '',
|
||||
database: '',
|
||||
basicAuth: false,
|
||||
basicAuthUser: '',
|
||||
basicAuthPassword: '',
|
||||
withCredentials: false,
|
||||
isDefault: false,
|
||||
jsonData: {},
|
||||
secureJsonFields: {
|
||||
appInsightsApiKey: false,
|
||||
},
|
||||
editorJsonData: {
|
||||
appInsightsAppId: 'cddcc020-2c94-460a-a3d0-df3147ffa792',
|
||||
},
|
||||
editorSecureJsonData: {
|
||||
appInsightsApiKey: 'e7f3f661-a933-4b3f-8176-51c4f982ec48',
|
||||
},
|
||||
version: 1,
|
||||
readOnly: false,
|
||||
},
|
||||
onDatasourceUpdate: jest.fn(),
|
||||
};
|
||||
|
||||
Object.assign(props, propOverrides);
|
||||
|
||||
return shallow(<InsightsConfig {...props} />);
|
||||
};
|
||||
|
||||
describe('Render', () => {
|
||||
it('should render component', () => {
|
||||
const wrapper = setup();
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should disable insights api key input', () => {
|
||||
const wrapper = setup({
|
||||
datasourceConfig: {
|
||||
secureJsonFields: {
|
||||
appInsightsApiKey: true,
|
||||
},
|
||||
editorJsonData: {
|
||||
appInsightsAppId: 'cddcc020-2c94-460a-a3d0-df3147ffa792',
|
||||
},
|
||||
editorSecureJsonData: {
|
||||
appInsightsApiKey: 'e7f3f661-a933-4b3f-8176-51c4f982ec48',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should enable insights api key input', () => {
|
||||
const wrapper = setup({
|
||||
datasourceConfig: {
|
||||
secureJsonFields: {
|
||||
appInsightsApiKey: false,
|
||||
},
|
||||
editorJsonData: {
|
||||
appInsightsAppId: 'cddcc020-2c94-460a-a3d0-df3147ffa792',
|
||||
},
|
||||
editorSecureJsonData: {
|
||||
appInsightsApiKey: 'e7f3f661-a933-4b3f-8176-51c4f982ec48',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,115 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { FormLabel, Button, Input } from '@grafana/ui';
|
||||
|
||||
export interface Props {
|
||||
datasourceConfig: any;
|
||||
onDatasourceUpdate: (config: any) => void;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
config: any;
|
||||
}
|
||||
|
||||
export class InsightsConfig extends PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
const { datasourceConfig } = this.props;
|
||||
|
||||
this.state = {
|
||||
config: datasourceConfig,
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(props: Props, state: State) {
|
||||
return {
|
||||
...state,
|
||||
config: props.datasourceConfig,
|
||||
};
|
||||
}
|
||||
|
||||
onAppInsightsAppIdChange = (appInsightsAppId: string) => {
|
||||
this.props.onDatasourceUpdate({
|
||||
...this.state.config,
|
||||
editorJsonData: {
|
||||
...this.state.config.editorJsonData,
|
||||
appInsightsAppId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onAppInsightsApiKeyChange = (appInsightsApiKey: string) => {
|
||||
this.props.onDatasourceUpdate({
|
||||
...this.state.config,
|
||||
editorSecureJsonData: {
|
||||
...this.state.config.editorSecureJsonData,
|
||||
appInsightsApiKey,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onAppInsightsResetApiKey = () => {
|
||||
this.props.onDatasourceUpdate({
|
||||
...this.state.config,
|
||||
version: this.state.config.version + 1,
|
||||
secureJsonFields: {
|
||||
...this.state.config.secureJsonFields,
|
||||
appInsightsApiKey: false,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { config } = this.state;
|
||||
return (
|
||||
<>
|
||||
<h3 className="page-heading">Application Insights Details</h3>
|
||||
<div className="gf-form-group">
|
||||
{config.secureJsonFields.appInsightsApiKey ? (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<FormLabel className="width-12">API Key</FormLabel>
|
||||
<Input className="width-25" placeholder="configured" disabled={true} />
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<div className="max-width-30 gf-form-inline">
|
||||
<Button variant="secondary" type="button" onClick={this.onAppInsightsResetApiKey}>
|
||||
reset
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<FormLabel className="width-12">API Key</FormLabel>
|
||||
<div className="width-15">
|
||||
<Input
|
||||
className="width-30"
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value={config.editorSecureJsonData.appInsightsApiKey}
|
||||
onChange={event => this.onAppInsightsApiKeyChange(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<FormLabel className="width-12">Application ID</FormLabel>
|
||||
<div className="width-15">
|
||||
<Input
|
||||
className="width-30"
|
||||
value={config.editorJsonData.appInsightsAppId}
|
||||
onChange={event => this.onAppInsightsAppIdChange(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default InsightsConfig;
|
||||
@@ -0,0 +1,132 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { AzureCredentialsForm } from './AzureCredentialsForm';
|
||||
|
||||
export interface Props {
|
||||
datasourceConfig: any;
|
||||
subscriptions: SelectableValue[];
|
||||
onDatasourceUpdate: (config: any) => void;
|
||||
onLoadSubscriptions: () => void;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
config: any;
|
||||
azureClouds: SelectableValue[];
|
||||
subscriptions: SelectableValue[];
|
||||
}
|
||||
|
||||
export class MonitorConfig extends PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
const { datasourceConfig } = this.props;
|
||||
|
||||
this.state = {
|
||||
config: datasourceConfig,
|
||||
azureClouds: [
|
||||
{ value: 'azuremonitor', label: 'Azure' },
|
||||
{ value: 'govazuremonitor', label: 'Azure US Government' },
|
||||
{ value: 'germanyazuremonitor', label: 'Azure Germany' },
|
||||
{ value: 'chinaazuremonitor', label: 'Azure China' },
|
||||
],
|
||||
subscriptions: [],
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(props: Props, state: State) {
|
||||
return {
|
||||
...state,
|
||||
config: props.datasourceConfig,
|
||||
subscriptions: props.subscriptions,
|
||||
};
|
||||
}
|
||||
|
||||
onAzureCloudSelect = (cloudName: SelectableValue<string>) => {
|
||||
this.props.onDatasourceUpdate({
|
||||
...this.state.config,
|
||||
jsonData: {
|
||||
...this.state.config.jsonData,
|
||||
cloudName,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onTenantIdChange = (tenantId: string) => {
|
||||
this.props.onDatasourceUpdate({
|
||||
...this.state.config,
|
||||
editorJsonData: {
|
||||
...this.state.config.editorJsonData,
|
||||
tenantId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onClientIdChange = (clientId: string) => {
|
||||
this.props.onDatasourceUpdate({
|
||||
...this.state.config,
|
||||
editorJsonData: {
|
||||
...this.state.config.editorJsonData,
|
||||
clientId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onClientSecretChange = (clientSecret: string) => {
|
||||
this.props.onDatasourceUpdate({
|
||||
...this.state.config,
|
||||
editorSecureJsonData: {
|
||||
...this.state.config.editorSecureJsonData,
|
||||
clientSecret,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onResetClientSecret = () => {
|
||||
this.props.onDatasourceUpdate({
|
||||
...this.state.config,
|
||||
version: this.state.config.version + 1,
|
||||
secureJsonFields: {
|
||||
...this.state.config.secureJsonFields,
|
||||
clientSecret: false,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onSubscriptionSelect = (subscription: SelectableValue<string>) => {
|
||||
this.props.onDatasourceUpdate({
|
||||
...this.state.config,
|
||||
editorJsonData: {
|
||||
...this.state.config.editorJsonData,
|
||||
subscriptionId: subscription.value,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { azureClouds, config, subscriptions } = this.state;
|
||||
return (
|
||||
<>
|
||||
<h3 className="page-heading">Azure Monitor Details</h3>
|
||||
<AzureCredentialsForm
|
||||
selectedAzureCloud={config.jsonData.cloudName}
|
||||
azureCloudOptions={azureClouds}
|
||||
subscriptionOptions={subscriptions}
|
||||
selectedSubscription={config.editorJsonData.subscriptionId}
|
||||
tenantId={config.editorJsonData.tenantId}
|
||||
clientId={config.editorJsonData.clientId}
|
||||
clientSecret={config.editorSecureJsonData.clientSecret}
|
||||
clientSecretConfigured={config.secureJsonFields.clientSecret}
|
||||
onAzureCloudChange={this.onAzureCloudSelect}
|
||||
onSubscriptionSelectChange={this.onSubscriptionSelect}
|
||||
onTenantIdChange={this.onTenantIdChange}
|
||||
onClientIdChange={this.onClientIdChange}
|
||||
onClientSecretChange={this.onClientSecretChange}
|
||||
onResetClientSecret={this.onResetClientSecret}
|
||||
onLoadSubscriptions={this.props.onLoadSubscriptions}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MonitorConfig;
|
||||
@@ -0,0 +1,286 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Render should disable log analytics credentials form 1`] = `
|
||||
<Fragment>
|
||||
<h3
|
||||
className="page-heading"
|
||||
>
|
||||
Azure Log Analytics API Details
|
||||
</h3>
|
||||
<Switch
|
||||
checked={false}
|
||||
label="Same details as Azure Monitor API"
|
||||
onChange={[Function]}
|
||||
/>
|
||||
<AzureCredentialsForm
|
||||
clientSecret=""
|
||||
clientSecretConfigured={false}
|
||||
onClientIdChange={[Function]}
|
||||
onClientSecretChange={[Function]}
|
||||
onLoadSubscriptions={[Function]}
|
||||
onResetClientSecret={[Function]}
|
||||
onSubscriptionSelectChange={[Function]}
|
||||
onTenantIdChange={[Function]}
|
||||
subscriptionOptions={Array []}
|
||||
tenantId=""
|
||||
/>
|
||||
<div
|
||||
className="gf-form-group"
|
||||
>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
tooltip="Choose the default/preferred Workspace for Azure Log Analytics queries."
|
||||
>
|
||||
Default Workspace
|
||||
</Component>
|
||||
<div
|
||||
className="width-25"
|
||||
>
|
||||
<Select
|
||||
autoFocus={false}
|
||||
backspaceRemovesValue={true}
|
||||
className=""
|
||||
components={
|
||||
Object {
|
||||
"Group": [Function],
|
||||
"IndicatorsContainer": [Function],
|
||||
"MenuList": [Function],
|
||||
"Option": [Function],
|
||||
"SingleValue": [Function],
|
||||
}
|
||||
}
|
||||
defaultValue=""
|
||||
isClearable={false}
|
||||
isDisabled={false}
|
||||
isLoading={false}
|
||||
isMulti={false}
|
||||
isSearchable={true}
|
||||
maxMenuHeight={300}
|
||||
onChange={[Function]}
|
||||
openMenuOnFocus={false}
|
||||
options={Array []}
|
||||
tabSelectsValue={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<div
|
||||
className="max-width-30 gf-form-inline"
|
||||
>
|
||||
<Button
|
||||
disabled={true}
|
||||
onClick={[Function]}
|
||||
size="sm"
|
||||
type="button"
|
||||
variant="secondary"
|
||||
>
|
||||
Load Workspaces
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`Render should enable azure log analytics load workspaces button 1`] = `
|
||||
<Fragment>
|
||||
<h3
|
||||
className="page-heading"
|
||||
>
|
||||
Azure Log Analytics API Details
|
||||
</h3>
|
||||
<Switch
|
||||
checked={false}
|
||||
label="Same details as Azure Monitor API"
|
||||
onChange={[Function]}
|
||||
/>
|
||||
<AzureCredentialsForm
|
||||
clientSecret=""
|
||||
clientSecretConfigured={false}
|
||||
onClientIdChange={[Function]}
|
||||
onClientSecretChange={[Function]}
|
||||
onLoadSubscriptions={[Function]}
|
||||
onResetClientSecret={[Function]}
|
||||
onSubscriptionSelectChange={[Function]}
|
||||
onTenantIdChange={[Function]}
|
||||
subscriptionOptions={Array []}
|
||||
tenantId=""
|
||||
/>
|
||||
<div
|
||||
className="gf-form-group"
|
||||
>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
tooltip="Choose the default/preferred Workspace for Azure Log Analytics queries."
|
||||
>
|
||||
Default Workspace
|
||||
</Component>
|
||||
<div
|
||||
className="width-25"
|
||||
>
|
||||
<Select
|
||||
autoFocus={false}
|
||||
backspaceRemovesValue={true}
|
||||
className=""
|
||||
components={
|
||||
Object {
|
||||
"Group": [Function],
|
||||
"IndicatorsContainer": [Function],
|
||||
"MenuList": [Function],
|
||||
"Option": [Function],
|
||||
"SingleValue": [Function],
|
||||
}
|
||||
}
|
||||
defaultValue=""
|
||||
isClearable={false}
|
||||
isDisabled={false}
|
||||
isLoading={false}
|
||||
isMulti={false}
|
||||
isSearchable={true}
|
||||
maxMenuHeight={300}
|
||||
onChange={[Function]}
|
||||
openMenuOnFocus={false}
|
||||
options={Array []}
|
||||
tabSelectsValue={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<div
|
||||
className="max-width-30 gf-form-inline"
|
||||
>
|
||||
<Button
|
||||
disabled={true}
|
||||
onClick={[Function]}
|
||||
size="sm"
|
||||
type="button"
|
||||
variant="secondary"
|
||||
>
|
||||
Load Workspaces
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<Fragment>
|
||||
<h3
|
||||
className="page-heading"
|
||||
>
|
||||
Azure Log Analytics API Details
|
||||
</h3>
|
||||
<Switch
|
||||
checked={false}
|
||||
label="Same details as Azure Monitor API"
|
||||
onChange={[Function]}
|
||||
/>
|
||||
<AzureCredentialsForm
|
||||
clientSecret=""
|
||||
clientSecretConfigured={false}
|
||||
onClientIdChange={[Function]}
|
||||
onClientSecretChange={[Function]}
|
||||
onLoadSubscriptions={[Function]}
|
||||
onResetClientSecret={[Function]}
|
||||
onSubscriptionSelectChange={[Function]}
|
||||
onTenantIdChange={[Function]}
|
||||
subscriptionOptions={Array []}
|
||||
tenantId=""
|
||||
/>
|
||||
<div
|
||||
className="gf-form-group"
|
||||
>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
tooltip="Choose the default/preferred Workspace for Azure Log Analytics queries."
|
||||
>
|
||||
Default Workspace
|
||||
</Component>
|
||||
<div
|
||||
className="width-25"
|
||||
>
|
||||
<Select
|
||||
autoFocus={false}
|
||||
backspaceRemovesValue={true}
|
||||
className=""
|
||||
components={
|
||||
Object {
|
||||
"Group": [Function],
|
||||
"IndicatorsContainer": [Function],
|
||||
"MenuList": [Function],
|
||||
"Option": [Function],
|
||||
"SingleValue": [Function],
|
||||
}
|
||||
}
|
||||
defaultValue=""
|
||||
isClearable={false}
|
||||
isDisabled={false}
|
||||
isLoading={false}
|
||||
isMulti={false}
|
||||
isSearchable={true}
|
||||
maxMenuHeight={300}
|
||||
onChange={[Function]}
|
||||
openMenuOnFocus={false}
|
||||
options={Array []}
|
||||
tabSelectsValue={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<div
|
||||
className="max-width-30 gf-form-inline"
|
||||
>
|
||||
<Button
|
||||
disabled={true}
|
||||
onClick={[Function]}
|
||||
size="sm"
|
||||
type="button"
|
||||
variant="secondary"
|
||||
>
|
||||
Load Workspaces
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
`;
|
||||
@@ -0,0 +1,626 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Render should disable azure monitor secret input 1`] = `
|
||||
<Fragment>
|
||||
<div
|
||||
className="gf-form-group"
|
||||
>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
tooltip="Choose an Azure Cloud."
|
||||
>
|
||||
Azure Cloud
|
||||
</Component>
|
||||
<Select
|
||||
autoFocus={false}
|
||||
backspaceRemovesValue={true}
|
||||
className="width-15"
|
||||
components={
|
||||
Object {
|
||||
"Group": [Function],
|
||||
"IndicatorsContainer": [Function],
|
||||
"MenuList": [Function],
|
||||
"Option": [Function],
|
||||
"SingleValue": [Function],
|
||||
}
|
||||
}
|
||||
defaultValue="azuremonitor"
|
||||
isClearable={false}
|
||||
isDisabled={false}
|
||||
isLoading={false}
|
||||
isMulti={false}
|
||||
isSearchable={true}
|
||||
maxMenuHeight={300}
|
||||
onChange={[MockFunction]}
|
||||
openMenuOnFocus={false}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"label": "Azure",
|
||||
"value": "azuremonitor",
|
||||
},
|
||||
Object {
|
||||
"label": "Azure US Government",
|
||||
"value": "govazuremonitor",
|
||||
},
|
||||
Object {
|
||||
"label": "Azure Germany",
|
||||
"value": "germanyazuremonitor",
|
||||
},
|
||||
Object {
|
||||
"label": "Azure China",
|
||||
"value": "chinaazuremonitor",
|
||||
},
|
||||
]
|
||||
}
|
||||
tabSelectsValue={true}
|
||||
value={
|
||||
Object {
|
||||
"label": "Azure",
|
||||
"value": "azuremonitor",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
Directory (tenant) ID
|
||||
</Component>
|
||||
<div
|
||||
className="width-15"
|
||||
>
|
||||
<Input
|
||||
className="width-30"
|
||||
onChange={[Function]}
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value="e7f3f661-a933-4b3f-8176-51c4f982ec48"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
Application (client) ID
|
||||
</Component>
|
||||
<div
|
||||
className="width-15"
|
||||
>
|
||||
<Input
|
||||
className="width-30"
|
||||
onChange={[Function]}
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value="77409fad-c0a9-45df-9e25-f1ff95af6554"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
Client Secret
|
||||
</Component>
|
||||
<Input
|
||||
className="width-25"
|
||||
disabled={true}
|
||||
placeholder="configured"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<div
|
||||
className="max-width-30 gf-form-inline"
|
||||
>
|
||||
<Button
|
||||
onClick={[MockFunction]}
|
||||
type="button"
|
||||
variant="secondary"
|
||||
>
|
||||
reset
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
Default Subscription
|
||||
</Component>
|
||||
<div
|
||||
className="width-25"
|
||||
>
|
||||
<Select
|
||||
autoFocus={false}
|
||||
backspaceRemovesValue={true}
|
||||
className=""
|
||||
components={
|
||||
Object {
|
||||
"Group": [Function],
|
||||
"IndicatorsContainer": [Function],
|
||||
"MenuList": [Function],
|
||||
"Option": [Function],
|
||||
"SingleValue": [Function],
|
||||
}
|
||||
}
|
||||
defaultValue="44693801-6ee6-49de-9b2d-9106972f9572"
|
||||
isClearable={false}
|
||||
isDisabled={false}
|
||||
isLoading={false}
|
||||
isMulti={false}
|
||||
isSearchable={true}
|
||||
maxMenuHeight={300}
|
||||
onChange={[MockFunction]}
|
||||
openMenuOnFocus={false}
|
||||
options={Array []}
|
||||
tabSelectsValue={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<div
|
||||
className="max-width-30 gf-form-inline"
|
||||
>
|
||||
<Button
|
||||
disabled={false}
|
||||
onClick={[MockFunction]}
|
||||
size="sm"
|
||||
type="button"
|
||||
variant="secondary"
|
||||
>
|
||||
Load Subscriptions
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`Render should enable azure monitor load subscriptions button 1`] = `
|
||||
<Fragment>
|
||||
<div
|
||||
className="gf-form-group"
|
||||
>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
tooltip="Choose an Azure Cloud."
|
||||
>
|
||||
Azure Cloud
|
||||
</Component>
|
||||
<Select
|
||||
autoFocus={false}
|
||||
backspaceRemovesValue={true}
|
||||
className="width-15"
|
||||
components={
|
||||
Object {
|
||||
"Group": [Function],
|
||||
"IndicatorsContainer": [Function],
|
||||
"MenuList": [Function],
|
||||
"Option": [Function],
|
||||
"SingleValue": [Function],
|
||||
}
|
||||
}
|
||||
defaultValue="azuremonitor"
|
||||
isClearable={false}
|
||||
isDisabled={false}
|
||||
isLoading={false}
|
||||
isMulti={false}
|
||||
isSearchable={true}
|
||||
maxMenuHeight={300}
|
||||
onChange={[MockFunction]}
|
||||
openMenuOnFocus={false}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"label": "Azure",
|
||||
"value": "azuremonitor",
|
||||
},
|
||||
Object {
|
||||
"label": "Azure US Government",
|
||||
"value": "govazuremonitor",
|
||||
},
|
||||
Object {
|
||||
"label": "Azure Germany",
|
||||
"value": "germanyazuremonitor",
|
||||
},
|
||||
Object {
|
||||
"label": "Azure China",
|
||||
"value": "chinaazuremonitor",
|
||||
},
|
||||
]
|
||||
}
|
||||
tabSelectsValue={true}
|
||||
value={
|
||||
Object {
|
||||
"label": "Azure",
|
||||
"value": "azuremonitor",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
Directory (tenant) ID
|
||||
</Component>
|
||||
<div
|
||||
className="width-15"
|
||||
>
|
||||
<Input
|
||||
className="width-30"
|
||||
onChange={[Function]}
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value="e7f3f661-a933-4b3f-8176-51c4f982ec48"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
Application (client) ID
|
||||
</Component>
|
||||
<div
|
||||
className="width-15"
|
||||
>
|
||||
<Input
|
||||
className="width-30"
|
||||
onChange={[Function]}
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value="77409fad-c0a9-45df-9e25-f1ff95af6554"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
Client Secret
|
||||
</Component>
|
||||
<div
|
||||
className="width-15"
|
||||
>
|
||||
<Input
|
||||
className="width-30"
|
||||
onChange={[Function]}
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value="e7f3f661-a933-4b3f-8176-51c4f982ec48"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
Default Subscription
|
||||
</Component>
|
||||
<div
|
||||
className="width-25"
|
||||
>
|
||||
<Select
|
||||
autoFocus={false}
|
||||
backspaceRemovesValue={true}
|
||||
className=""
|
||||
components={
|
||||
Object {
|
||||
"Group": [Function],
|
||||
"IndicatorsContainer": [Function],
|
||||
"MenuList": [Function],
|
||||
"Option": [Function],
|
||||
"SingleValue": [Function],
|
||||
}
|
||||
}
|
||||
defaultValue="44693801-6ee6-49de-9b2d-9106972f9572"
|
||||
isClearable={false}
|
||||
isDisabled={false}
|
||||
isLoading={false}
|
||||
isMulti={false}
|
||||
isSearchable={true}
|
||||
maxMenuHeight={300}
|
||||
onChange={[MockFunction]}
|
||||
openMenuOnFocus={false}
|
||||
options={Array []}
|
||||
tabSelectsValue={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<div
|
||||
className="max-width-30 gf-form-inline"
|
||||
>
|
||||
<Button
|
||||
disabled={false}
|
||||
onClick={[MockFunction]}
|
||||
size="sm"
|
||||
type="button"
|
||||
variant="secondary"
|
||||
>
|
||||
Load Subscriptions
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<Fragment>
|
||||
<div
|
||||
className="gf-form-group"
|
||||
>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
tooltip="Choose an Azure Cloud."
|
||||
>
|
||||
Azure Cloud
|
||||
</Component>
|
||||
<Select
|
||||
autoFocus={false}
|
||||
backspaceRemovesValue={true}
|
||||
className="width-15"
|
||||
components={
|
||||
Object {
|
||||
"Group": [Function],
|
||||
"IndicatorsContainer": [Function],
|
||||
"MenuList": [Function],
|
||||
"Option": [Function],
|
||||
"SingleValue": [Function],
|
||||
}
|
||||
}
|
||||
defaultValue="azuremonitor"
|
||||
isClearable={false}
|
||||
isDisabled={false}
|
||||
isLoading={false}
|
||||
isMulti={false}
|
||||
isSearchable={true}
|
||||
maxMenuHeight={300}
|
||||
onChange={[MockFunction]}
|
||||
openMenuOnFocus={false}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"label": "Azure",
|
||||
"value": "azuremonitor",
|
||||
},
|
||||
Object {
|
||||
"label": "Azure US Government",
|
||||
"value": "govazuremonitor",
|
||||
},
|
||||
Object {
|
||||
"label": "Azure Germany",
|
||||
"value": "germanyazuremonitor",
|
||||
},
|
||||
Object {
|
||||
"label": "Azure China",
|
||||
"value": "chinaazuremonitor",
|
||||
},
|
||||
]
|
||||
}
|
||||
tabSelectsValue={true}
|
||||
value={
|
||||
Object {
|
||||
"label": "Azure",
|
||||
"value": "azuremonitor",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
Directory (tenant) ID
|
||||
</Component>
|
||||
<div
|
||||
className="width-15"
|
||||
>
|
||||
<Input
|
||||
className="width-30"
|
||||
onChange={[Function]}
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value="e7f3f661-a933-4b3f-8176-51c4f982ec48"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
Application (client) ID
|
||||
</Component>
|
||||
<div
|
||||
className="width-15"
|
||||
>
|
||||
<Input
|
||||
className="width-30"
|
||||
onChange={[Function]}
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value="77409fad-c0a9-45df-9e25-f1ff95af6554"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
Client Secret
|
||||
</Component>
|
||||
<div
|
||||
className="width-15"
|
||||
>
|
||||
<Input
|
||||
className="width-30"
|
||||
onChange={[Function]}
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
Default Subscription
|
||||
</Component>
|
||||
<div
|
||||
className="width-25"
|
||||
>
|
||||
<Select
|
||||
autoFocus={false}
|
||||
backspaceRemovesValue={true}
|
||||
className=""
|
||||
components={
|
||||
Object {
|
||||
"Group": [Function],
|
||||
"IndicatorsContainer": [Function],
|
||||
"MenuList": [Function],
|
||||
"Option": [Function],
|
||||
"SingleValue": [Function],
|
||||
}
|
||||
}
|
||||
defaultValue="44693801-6ee6-49de-9b2d-9106972f9572"
|
||||
isClearable={false}
|
||||
isDisabled={false}
|
||||
isLoading={false}
|
||||
isMulti={false}
|
||||
isSearchable={true}
|
||||
maxMenuHeight={300}
|
||||
onChange={[MockFunction]}
|
||||
openMenuOnFocus={false}
|
||||
options={Array []}
|
||||
tabSelectsValue={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<div
|
||||
className="max-width-30 gf-form-inline"
|
||||
>
|
||||
<Button
|
||||
disabled={true}
|
||||
onClick={[MockFunction]}
|
||||
size="sm"
|
||||
type="button"
|
||||
variant="secondary"
|
||||
>
|
||||
Load Subscriptions
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
`;
|
||||
@@ -0,0 +1,188 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Render should disable insights api key input 1`] = `
|
||||
<Fragment>
|
||||
<h3
|
||||
className="page-heading"
|
||||
>
|
||||
Application Insights Details
|
||||
</h3>
|
||||
<div
|
||||
className="gf-form-group"
|
||||
>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
API Key
|
||||
</Component>
|
||||
<Input
|
||||
className="width-25"
|
||||
disabled={true}
|
||||
placeholder="configured"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<div
|
||||
className="max-width-30 gf-form-inline"
|
||||
>
|
||||
<Button
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
variant="secondary"
|
||||
>
|
||||
reset
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
Application ID
|
||||
</Component>
|
||||
<div
|
||||
className="width-15"
|
||||
>
|
||||
<Input
|
||||
className="width-30"
|
||||
onChange={[Function]}
|
||||
value="cddcc020-2c94-460a-a3d0-df3147ffa792"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`Render should enable insights api key input 1`] = `
|
||||
<Fragment>
|
||||
<h3
|
||||
className="page-heading"
|
||||
>
|
||||
Application Insights Details
|
||||
</h3>
|
||||
<div
|
||||
className="gf-form-group"
|
||||
>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
API Key
|
||||
</Component>
|
||||
<div
|
||||
className="width-15"
|
||||
>
|
||||
<Input
|
||||
className="width-30"
|
||||
onChange={[Function]}
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value="e7f3f661-a933-4b3f-8176-51c4f982ec48"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
Application ID
|
||||
</Component>
|
||||
<div
|
||||
className="width-15"
|
||||
>
|
||||
<Input
|
||||
className="width-30"
|
||||
onChange={[Function]}
|
||||
value="cddcc020-2c94-460a-a3d0-df3147ffa792"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<Fragment>
|
||||
<h3
|
||||
className="page-heading"
|
||||
>
|
||||
Application Insights Details
|
||||
</h3>
|
||||
<div
|
||||
className="gf-form-group"
|
||||
>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
API Key
|
||||
</Component>
|
||||
<div
|
||||
className="width-15"
|
||||
>
|
||||
<Input
|
||||
className="width-30"
|
||||
onChange={[Function]}
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value="e7f3f661-a933-4b3f-8176-51c4f982ec48"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
className="width-12"
|
||||
>
|
||||
Application ID
|
||||
</Component>
|
||||
<div
|
||||
className="width-15"
|
||||
>
|
||||
<Input
|
||||
className="width-30"
|
||||
onChange={[Function]}
|
||||
value="cddcc020-2c94-460a-a3d0-df3147ffa792"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
`;
|
||||
@@ -1,127 +0,0 @@
|
||||
import AzureLogAnalyticsDatasource from './azure_log_analytics/azure_log_analytics_datasource';
|
||||
import config from 'app/core/config';
|
||||
import { isVersionGtOrEq } from 'app/core/utils/version';
|
||||
import AzureMonitorDatasource from './azure_monitor/azure_monitor_datasource';
|
||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||
import { IQService } from 'angular';
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
|
||||
interface AzureCloud {
|
||||
key: string;
|
||||
url: string;
|
||||
loginUrl: string;
|
||||
}
|
||||
|
||||
export class AzureMonitorConfigCtrl {
|
||||
static templateUrl = 'public/app/plugins/datasource/grafana-azure-monitor-datasource/partials/config.html';
|
||||
current: any;
|
||||
azureLogAnalyticsDatasource: any;
|
||||
azureMonitorDatasource: any;
|
||||
workspaces: any[];
|
||||
subscriptions: Array<{ text: string; value: string }>;
|
||||
subscriptionsForLogAnalytics: Array<{ text: string; value: string }>;
|
||||
hasRequiredGrafanaVersion: boolean;
|
||||
azureClouds: AzureCloud[];
|
||||
token: string;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private backendSrv: BackendSrv, private $q: IQService, private templateSrv: TemplateSrv) {
|
||||
this.hasRequiredGrafanaVersion = this.hasMinVersion();
|
||||
this.current.jsonData.cloudName = this.current.jsonData.cloudName || 'azuremonitor';
|
||||
this.current.jsonData.azureLogAnalyticsSameAs = this.current.jsonData.azureLogAnalyticsSameAs || false;
|
||||
this.current.secureJsonData = this.current.secureJsonData || {};
|
||||
this.current.secureJsonFields = this.current.secureJsonFields || {};
|
||||
this.subscriptions = [];
|
||||
this.subscriptionsForLogAnalytics = [];
|
||||
this.azureClouds = [
|
||||
{
|
||||
key: 'azuremonitor',
|
||||
url: 'https://management.azure.com/',
|
||||
loginUrl: 'https://login.microsoftonline.com/',
|
||||
},
|
||||
{
|
||||
key: 'govazuremonitor',
|
||||
url: 'https://management.usgovcloudapi.net/',
|
||||
loginUrl: 'https://login.microsoftonline.us/',
|
||||
},
|
||||
{
|
||||
key: 'germanyazuremonitor',
|
||||
url: 'https://management.microsoftazure.de',
|
||||
loginUrl: 'https://management.microsoftazure.de/',
|
||||
},
|
||||
{
|
||||
key: 'chinaazuremonitor',
|
||||
url: 'https://management.chinacloudapi.cn',
|
||||
loginUrl: 'https://login.chinacloudapi.cn',
|
||||
},
|
||||
];
|
||||
|
||||
if (this.current.id) {
|
||||
this.current.url = '/api/datasources/proxy/' + this.current.id;
|
||||
this.init();
|
||||
}
|
||||
}
|
||||
|
||||
async init() {
|
||||
this.azureMonitorDatasource = new AzureMonitorDatasource(this.current, this.backendSrv, this.templateSrv);
|
||||
await this.getSubscriptions();
|
||||
await this.getSubscriptionsForLogsAnalytics();
|
||||
|
||||
this.azureLogAnalyticsDatasource = new AzureLogAnalyticsDatasource(
|
||||
this.current,
|
||||
this.backendSrv,
|
||||
this.templateSrv,
|
||||
this.$q
|
||||
);
|
||||
await this.getWorkspaces();
|
||||
}
|
||||
|
||||
hasMinVersion(): boolean {
|
||||
return isVersionGtOrEq(config.buildInfo.version, '5.2');
|
||||
}
|
||||
|
||||
showMinVersionWarning() {
|
||||
return !this.hasRequiredGrafanaVersion && this.current.secureJsonFields.logAnalyticsClientSecret;
|
||||
}
|
||||
|
||||
async getWorkspaces() {
|
||||
const sameAs = this.current.jsonData.azureLogAnalyticsSameAs && this.subscriptions.length > 0;
|
||||
if (!sameAs && this.subscriptionsForLogAnalytics.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.workspaces = await this.azureLogAnalyticsDatasource.getWorkspaces();
|
||||
if (this.workspaces.length > 0) {
|
||||
this.current.jsonData.logAnalyticsDefaultWorkspace =
|
||||
this.current.jsonData.logAnalyticsDefaultWorkspace || this.workspaces[0].value;
|
||||
}
|
||||
}
|
||||
|
||||
async getSubscriptions() {
|
||||
if (!this.current.secureJsonFields.clientSecret && !this.current.secureJsonData.clientSecret) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.subscriptions = (await this.azureMonitorDatasource.getSubscriptions()) || [];
|
||||
if (this.subscriptions && this.subscriptions.length > 0) {
|
||||
this.current.jsonData.subscriptionId = this.current.jsonData.subscriptionId || this.subscriptions[0].value;
|
||||
}
|
||||
}
|
||||
|
||||
async getSubscriptionsForLogsAnalytics() {
|
||||
if (
|
||||
!this.current.secureJsonFields.logAnalyticsClientSecret &&
|
||||
!this.current.secureJsonData.logAnalyticsClientSecret
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.subscriptionsForLogAnalytics =
|
||||
(await this.azureMonitorDatasource.getSubscriptions('workspacesloganalytics')) || [];
|
||||
|
||||
if (this.subscriptionsForLogAnalytics && this.subscriptionsForLogAnalytics.length > 0) {
|
||||
this.current.jsonData.logAnalyticsSubscriptionId =
|
||||
this.current.jsonData.logAnalyticsSubscriptionId || this.subscriptionsForLogAnalytics[0].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,8 +32,7 @@ export default class Datasource extends DataSourceApi<AzureMonitorQuery, AzureDa
|
||||
this.azureLogAnalyticsDatasource = new AzureLogAnalyticsDatasource(
|
||||
instanceSettings,
|
||||
this.backendSrv,
|
||||
this.templateSrv,
|
||||
this.$q
|
||||
this.templateSrv
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import Datasource from './datasource';
|
||||
import { AzureMonitorQueryCtrl } from './query_ctrl';
|
||||
import { AzureMonitorAnnotationsQueryCtrl } from './annotations_query_ctrl';
|
||||
import { AzureMonitorConfigCtrl } from './config_ctrl';
|
||||
|
||||
export {
|
||||
Datasource,
|
||||
AzureMonitorQueryCtrl as QueryCtrl,
|
||||
AzureMonitorConfigCtrl as ConfigCtrl,
|
||||
AzureMonitorAnnotationsQueryCtrl as AnnotationsQueryCtrl,
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
import { DataSourcePlugin } from '@grafana/ui';
|
||||
import { AzureMonitorQueryCtrl } from './query_ctrl';
|
||||
import Datasource from './datasource';
|
||||
import { ConfigEditor } from './ConfigEditor';
|
||||
import { AzureMonitorAnnotationsQueryCtrl } from './annotations_query_ctrl';
|
||||
|
||||
export const plugin = new DataSourcePlugin(Datasource)
|
||||
.setConfigEditor(ConfigEditor)
|
||||
.setQueryCtrl(AzureMonitorQueryCtrl)
|
||||
.setAnnotationQueryCtrl(AzureMonitorAnnotationsQueryCtrl);
|
||||
@@ -1,203 +0,0 @@
|
||||
<h3 class="page-heading">Azure Monitor Details</h3>
|
||||
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Azure Cloud</span>
|
||||
<div class="gf-form-select-wrapper width-15 gf-form-select-wrapper--has-help-icon">
|
||||
<select class="gf-form-input" ng-model="ctrl.current.jsonData.cloudName" ng-options="f.value as f.text for f in [{value: 'azuremonitor', text: 'Azure'}, {value: 'govazuremonitor', text: 'Azure US Government'}, {value: 'germanyazuremonitor', text: 'Azure Germany'}, {value: 'chinaazuremonitor', text: 'Azure China'}]"
|
||||
ng-change="ctrl.refresh()"></select>
|
||||
</div>
|
||||
<info-popover mode="right-absolute">
|
||||
<p>Choose an Azure Cloud.</p>
|
||||
</info-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Tenant Id</span>
|
||||
<input class="gf-form-input width-30 gf-form-input--has-help-icon" type="text" ng-model="ctrl.current.jsonData.tenantId" placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"></input>
|
||||
<info-popover mode="right-absolute">
|
||||
<p>In the Azure Portal, navigate to Azure Active Directory -> Properties -> Directory ID.</p>
|
||||
<a target="_blank" href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal">**Click
|
||||
here for detailed instructions on setting up an Azure Active Directory (AD) application.**</a>
|
||||
</info-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Client Id</span>
|
||||
<input class="gf-form-input width-30 gf-form-input--has-help-icon" type="text" ng-model="ctrl.current.jsonData.clientId" placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"></input>
|
||||
<info-popover mode="right-absolute">
|
||||
<p>In the Azure Portal, navigate to Azure Active Directory -> App Registrations -> Choose your app ->
|
||||
Application ID.</p>
|
||||
<a target="_blank" href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal">**Click
|
||||
here for detailed instructions on setting up an Azure Active Directory (AD) application.**</a>
|
||||
</info-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form-inline" ng-if="!ctrl.current.secureJsonFields.clientSecret">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Client Secret</span>
|
||||
<input class="gf-form-input width-30 gf-form-input--has-help-icon" type="text" ng-model="ctrl.current.secureJsonData.clientSecret" placeholder=""></input>
|
||||
<info-popover mode="right-absolute">
|
||||
<p>To create a new key, log in to Azure Portal, navigate to Azure Active Directory -> App Registrations ->
|
||||
Choose your
|
||||
app -> Keys.</p>
|
||||
<a target="_blank" href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal">**Click
|
||||
here for detailed instructions on setting up an Azure Active Directory (AD) application.**</a>
|
||||
</info-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form" ng-if="ctrl.current.secureJsonFields.clientSecret">
|
||||
<span class="gf-form-label width-10">Client Secret</span>
|
||||
<input type="text" class="gf-form-input max-width-12" disabled="disabled" value="configured">
|
||||
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.current.secureJsonFields.clientSecret = false">reset</a>
|
||||
</div>
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Default Subscription</span>
|
||||
<gf-form-dropdown model="ctrl.current.jsonData.subscriptionId" allow-custom="true" lookup-text="false"
|
||||
get-options="ctrl.subscriptions" css-class="width-30 gf-form-input">
|
||||
</gf-form-dropdown>
|
||||
<info-popover mode="right-absolute">
|
||||
<p>Choose the default/preferred Subscription for Azure Metrics.</p>
|
||||
<p>In the Azure Portal, navigate to Subscriptions -> Choose subscription -> Overview -> Subscription ID.</p>
|
||||
<a target="_blank" href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal">**Click
|
||||
here for detailed instructions on setting up an Azure Active Directory (AD) application.**</a>
|
||||
</info-popover>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="page-heading">Azure Log Analytics API Details</h3>
|
||||
|
||||
<div class="grafana-info-box ng-scope">
|
||||
The Azure Log Analytics support is marked as being in a preview development state. This means it is in currently in active development and major changes might be made - depending on feedback from users.
|
||||
</div>
|
||||
|
||||
<div class="gf-form-group">
|
||||
<gf-form-switch class="gf-form" label="Same details as Azure Monitor API" label-class="width-19" switch-class="max-width-6"
|
||||
checked="ctrl.current.jsonData.azureLogAnalyticsSameAs" on-change="ctrl.onSameAsToggle()">
|
||||
</gf-form-switch>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-group" ng-show="!ctrl.current.jsonData.azureLogAnalyticsSameAs">
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Tenant Id</span>
|
||||
<input class="gf-form-input width-30 gf-form-input--has-help-icon" type="text" ng-model="ctrl.current.jsonData.logAnalyticsTenantId"
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" />
|
||||
<info-popover mode="right-absolute">
|
||||
<p>In the Azure Portal, navigate to Azure Active Directory -> Properties -> Directory ID.</p>
|
||||
<a target="_blank" href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal">**Click
|
||||
here for detailed instructions on setting up an Azure Active Directory (AD) application.**</a>
|
||||
</info-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Client Id</span>
|
||||
<input class="gf-form-input width-30 gf-form-input--has-help-icon" type="text" ng-model="ctrl.current.jsonData.logAnalyticsClientId"
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"></input>
|
||||
<info-popover mode="right-absolute">
|
||||
<p>In the Azure Portal, navigate to Azure Active Directory -> App Registrations -> Choose your app ->
|
||||
Application ID.
|
||||
</p>
|
||||
<a target="_blank" href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal">**Click
|
||||
here for detailed instructions on setting up an Azure Active Directory (AD) application.**</a>
|
||||
</info-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form-inline" ng-if="!ctrl.current.secureJsonFields.logAnalyticsClientSecret">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Client Secret</span>
|
||||
<input class="gf-form-input width-30 gf-form-input--has-help-icon" type="text" ng-model="ctrl.current.secureJsonData.logAnalyticsClientSecret"
|
||||
placeholder="" />
|
||||
<info-popover mode="right-absolute">
|
||||
<p>To create a new key, log in to Azure Portal, navigate to Azure Active Directory -> App Registrations ->
|
||||
Choose your
|
||||
app -> Keys.</p>
|
||||
<a target="_blank" href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal">**Click
|
||||
here for detailed instructions on setting up an Azure Active Directory (AD) application.**</a>
|
||||
</info-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form" ng-if="ctrl.current.secureJsonFields.logAnalyticsClientSecret">
|
||||
<span class="gf-form-label width-10">Client Secret</span>
|
||||
<input type="text" class="gf-form-input max-width-12" disabled="disabled" value="configured">
|
||||
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.current.secureJsonFields.logAnalyticsClientSecret = false">reset</a>
|
||||
</div>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Default Subscription</span>
|
||||
<gf-form-dropdown model="ctrl.current.jsonData.logAnalyticsSubscriptionId" allow-custom="true" lookup-text="true"
|
||||
get-options="ctrl.subscriptionsForLogAnalytics" css-class="min-width-30">
|
||||
</gf-form-dropdown>
|
||||
<info-popover mode="right-absolute">
|
||||
<p>Choose the default/preferred Subscription for Azure Metrics.</p>
|
||||
<p>In the Azure Portal, navigate to Subscriptions -> Choose subscription -> Overview -> Subscription ID.</p>
|
||||
<a target="_blank" href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal">**Click
|
||||
here for detailed instructions on setting up an Azure Active Directory (AD) application.**</a>
|
||||
</info-popover>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Default Workspace</span>
|
||||
<div class="gf-form-select-wrapper min-width-30 gf-form-select-wrapper--has-help-icon">
|
||||
<select class="gf-form-input" ng-model="ctrl.current.jsonData.logAnalyticsDefaultWorkspace" ng-options="f.value as f.text for f in ctrl.workspaces"
|
||||
ng-disabled="!ctrl.workspaces"></select>
|
||||
</div>
|
||||
<info-popover mode="right-absolute">
|
||||
<p>Choose the default/preferred Workspace for Azure Log Analytics queries.</p>
|
||||
</info-popover>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form-group" ng-if="ctrl.showMinVersionWarning()">
|
||||
<div class=" alert alert-error">
|
||||
<p>
|
||||
The Azure Log Analytics feature requires Grafana 5.2.0 or greater. Download a new version of
|
||||
Grafana
|
||||
<a class="external-link" target="_blank" href="https://grafana.com/get">here</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="page-heading">Application Insights Details</h3>
|
||||
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form-inline" ng-if="!ctrl.current.secureJsonFields.appInsightsApiKey">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-9">API Key</span>
|
||||
<input class="gf-form-input width-30 gf-form-input--has-help-icon" type="text" ng-model="ctrl.current.secureJsonData.appInsightsApiKey"
|
||||
placeholder="" />
|
||||
<info-popover mode="right-absolute">
|
||||
<p>Section 2 of the Quickstart guide shows where to find/create the API Key:</p>
|
||||
<a target="_blank" href="https://dev.applicationinsights.io/quickstart/">**Click here to open the Application
|
||||
Insights Quickstart.**</a>
|
||||
</info-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form" ng-if="ctrl.current.secureJsonFields.appInsightsApiKey">
|
||||
<span class="gf-form-label width-9">API Key</span>
|
||||
<input type="text" class="gf-form-input max-width-12" disabled="disabled" value="configured">
|
||||
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.current.secureJsonFields.appInsightsApiKey = false">reset</a>
|
||||
</div>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-9">Application Id</span>
|
||||
<input class="gf-form-input width-30 gf-form-input--has-help-icon" type="text" ng-model="ctrl.current.jsonData.appInsightsAppId" placeholder="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"></input>
|
||||
<info-popover mode="right-absolute">
|
||||
<p>Section 2 of the Quickstart guide shows where to find the Application ID:</p>
|
||||
<a target="_blank" href="https://dev.applicationinsights.io/quickstart/">**Click here to open the Application
|
||||
Insights Quickstart.**</a>
|
||||
</info-popover>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user