Skip to content
This repository was archived by the owner on Apr 27, 2023. It is now read-only.

Commit d0f24f2

Browse files
committed
fix diff bug and lint errors
1 parent 2e34c7a commit d0f24f2

File tree

5 files changed

+87
-83
lines changed

5 files changed

+87
-83
lines changed

jest.config.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// This file is needed because it is used by vscode and other tools that
2+
// call `jest` directly. However, unless you are doing anything special
3+
// do not edit this file
4+
5+
const standard = require('@grafana/toolkit/src/config/jest.plugin.config');
6+
7+
// This process will use the same config that `yarn test` is using
8+
module.exports = standard.jestConfig();

src/ConfigEditor.tsx

Lines changed: 2 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { ChangeEvent, PureComponent } from 'react';
22
import { LegacyForms } from '@grafana/ui';
33
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
4-
import { MyDataSourceOptions, /* MySecureJsonData */ } from './types';
4+
import { MyDataSourceOptions } from './types';
55

66
const { /* SecretFormField, */ FormField } = LegacyForms;
77

@@ -19,36 +19,9 @@ export class ConfigEditor extends PureComponent<Props, State> {
1919
onOptionsChange({ ...options, jsonData });
2020
};
2121

22-
// Secure field (only sent to the backend)
23-
// onAPIKeyChange = (event: ChangeEvent<HTMLInputElement>) => {
24-
// const { onOptionsChange, options } = this.props;
25-
// onOptionsChange({
26-
// ...options,
27-
// secureJsonData: {
28-
// apiKey: event.target.value,
29-
// },
30-
// });
31-
// };
32-
33-
// onResetAPIKey = () => {
34-
// const { onOptionsChange, options } = this.props;
35-
// onOptionsChange({
36-
// ...options,
37-
// secureJsonFields: {
38-
// ...options.secureJsonFields,
39-
// apiKey: false,
40-
// },
41-
// secureJsonData: {
42-
// ...options.secureJsonData,
43-
// apiKey: '',
44-
// },
45-
// });
46-
// };
47-
4822
render() {
4923
const { options } = this.props;
50-
const { jsonData, /* secureJsonFields */ } = options;
51-
// const secureJsonData = (options.secureJsonData || {}) as MySecureJsonData;
24+
const { jsonData } = options;
5225

5326
return (
5427
<div className="gf-form-group">
@@ -62,21 +35,6 @@ export class ConfigEditor extends PureComponent<Props, State> {
6235
placeholder="url to your pyroscope instance"
6336
/>
6437
</div>
65-
66-
{/* <div className="gf-form-inline">
67-
<div className="gf-form">
68-
<SecretFormField
69-
isConfigured={(secureJsonFields && secureJsonFields.apiKey) as boolean}
70-
value={secureJsonData.apiKey || ''}
71-
label="API Key"
72-
placeholder="API Key of your pyroscope instance"
73-
labelWidth={6}
74-
inputWidth={20}
75-
onReset={this.onResetAPIKey}
76-
onChange={this.onAPIKeyChange}
77-
/>
78-
</div>
79-
</div> */}
8038
</div>
8139
);
8240
}

src/QueryEditor.tsx

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,53 +6,54 @@ import { QueryEditorProps, SelectableValue } from '@grafana/data';
66
import { DataSource } from './datasource';
77
import { defaultQuery, MyDataSourceOptions, FlamegraphQuery } from './types';
88

9-
109
type Props = QueryEditorProps<DataSource, FlamegraphQuery, MyDataSourceOptions>;
1110

1211
export const QueryEditor = (props: Props) => {
1312
const query = defaults(props.query, defaultQuery);
1413
const [appName, setAppName] = useState<SelectableValue<string>>({ label: query.name, value: query.name });
15-
const [names, setNames] = useState<SelectableValue<string>[]>([]);
14+
const [names, setNames] = useState<Array<SelectableValue<string>>>([]);
1615
const loadAppNames = (query: string) => {
1716
return props.datasource.loadAppNames().then(
1817
result => setNames(result.data.map((value: string) => ({ label: value, value }))),
1918
response => {
2019
throw new Error(response.statusText);
2120
}
2221
);
23-
}
22+
};
2423

2524
useEffect(() => {
2625
loadAppNames('');
27-
}, [])
26+
// eslint-disable-next-line
27+
}, []);
2828

2929
useEffect(() => {
3030
const { onChange, query, onRunQuery } = props;
31-
if(appName.value) {
31+
if (appName.value) {
3232
onChange({ ...query, name: appName.value });
3333
onRunQuery();
3434
}
35+
// eslint-disable-next-line
3536
}, [appName]);
3637

37-
return (
38-
<div className="gf-form">
39-
{/* <FormField
38+
return (
39+
<div className="gf-form">
40+
{/* <FormField
4041
labelWidth={8}
4142
value={name}
4243
onChange={this.onNameChange}
4344
label="Application name"
4445
/> */}
45-
<div style={{display: 'flex', flexDirection: 'row', marginTop: '10px'}}>
46-
<Label style={{marginTop: '8px', marginRight: '10px'}}>Application</Label>
46+
<div style={{ display: 'flex', flexDirection: 'row', marginTop: '10px' }}>
47+
<Label style={{ marginTop: '8px', marginRight: '10px' }}>Application</Label>
4748
<Select
48-
onChange={(v) => v ? setAppName(v) : setAppName({label:'', value: ''})}
49+
onChange={v => (v ? setAppName(v) : setAppName({ label: '', value: '' }))}
4950
value={appName}
5051
options={names}
5152
backspaceRemovesValue
5253
isClearable
5354
allowCustomValue
5455
/>
55-
</div>
5656
</div>
57-
);
58-
}
57+
</div>
58+
);
59+
};

src/datasource.ts

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@ import {
66
MutableDataFrame,
77
FieldType,
88
} from '@grafana/data';
9-
import { getBackendSrv, BackendSrv } from "@grafana/runtime";
9+
import { getBackendSrv, BackendSrv } from '@grafana/runtime';
1010

1111
import { FlamegraphQuery, MyDataSourceOptions } from './types';
1212
import { getTemplateSrv } from '@grafana/runtime';
13-
14-
13+
import { deltaDiff } from './flamebearer';
1514

1615
export class DataSource extends DataSourceApi<FlamegraphQuery, MyDataSourceOptions> {
1716
constructor(instanceSettings: DataSourceInstanceSettings<MyDataSourceOptions>) {
@@ -26,20 +25,24 @@ export class DataSource extends DataSourceApi<FlamegraphQuery, MyDataSourceOptio
2625
url: string;
2726

2827
async getFlamegraph(query: FlamegraphQuery) {
29-
const result = await this.backendSrv.fetch({
30-
method: 'GET',
31-
url: this.url +'/render/render',
32-
params: query,
33-
}).toPromise();
28+
const result = await this.backendSrv
29+
.fetch({
30+
method: 'GET',
31+
url: this.url + '/render/render',
32+
params: query,
33+
})
34+
.toPromise();
3435

3536
return result;
3637
}
3738

3839
async getNames() {
39-
const result = await this.backendSrv.fetch<Array<string>>({
40-
method: 'GET',
41-
url: this.url +'/render/label-values?label=__name__',
42-
}).toPromise();
40+
const result = await this.backendSrv
41+
.fetch<string[]>({
42+
method: 'GET',
43+
url: this.url + '/render/label-values?label=__name__',
44+
})
45+
.toPromise();
4346

4447
return result;
4548
}
@@ -49,32 +52,36 @@ export class DataSource extends DataSourceApi<FlamegraphQuery, MyDataSourceOptio
4952
const from = range.raw.from.valueOf();
5053
const until = range.raw.to.valueOf();
5154

52-
const promises = options.targets.map((query) => {
55+
const promises = options.targets.map(query => {
5356
let nameFromVar: string | undefined;
54-
if(query?.name?.startsWith('$')) {
55-
const appNameVar = getTemplateSrv().getVariables().find((vari => query?.name?.slice(1) === vari.name));
57+
if (query?.name?.startsWith('$')) {
58+
const appNameVar = getTemplateSrv()
59+
.getVariables()
60+
.find(vari => query?.name?.slice(1) === vari.name);
5661
// @ts-ignore
5762
nameFromVar = appNameVar?.query;
5863
}
5964
return this.getFlamegraph({ ...query, name: nameFromVar || query.name, from, until }).then((response: any) => {
6065
const frame = new MutableDataFrame({
6166
refId: query.refId,
6267
name: nameFromVar || query.name,
63-
fields: [
64-
{ name: "flamebearer", type: FieldType.other },
65-
],
68+
fields: [{ name: 'flamebearer', type: FieldType.other }],
6669
meta: {
67-
preferredVisualisationType: 'table',
70+
preferredVisualisationType: 'table',
6871
},
6972
});
7073

71-
frame.appendRow([response.data.flamebearer]);
74+
frame.appendRow([
75+
{
76+
...response.data.flamebearer,
77+
levels: deltaDiff(response.data.flamebearer.levels),
78+
},
79+
]);
7280

7381
return frame;
74-
})
75-
}
76-
);
77-
return Promise.all(promises).then((data) => ({ data }));
82+
});
83+
});
84+
return Promise.all(promises).then(data => ({ data }));
7885
}
7986

8087
loadAppNames(): Promise<any> {
@@ -83,7 +90,7 @@ export class DataSource extends DataSourceApi<FlamegraphQuery, MyDataSourceOptio
8390

8491
async testDatasource() {
8592
const names = await this.getNames();
86-
if(names.status === 200) {
93+
if (names.status === 200) {
8794
return {
8895
status: 'success',
8996
message: 'Success',

src/flamebearer.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// ISC License
2+
3+
// Copyright (c) 2018, Mapbox
4+
5+
// Permission to use, copy, modify, and/or distribute this software for any purpose
6+
// with or without fee is hereby granted, provided that the above copyright notice
7+
// and this permission notice appear in all copies.
8+
9+
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10+
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
11+
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12+
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
13+
// OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
14+
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
15+
// THIS SOFTWARE.
16+
17+
// This component is based on flamebearer project
18+
// https://github.com/mapbox/flamebearer
19+
20+
export function deltaDiff(levels: any[]) {
21+
const levelsCopy = new Array(...levels);
22+
for (const level of levelsCopy) {
23+
let prev = 0;
24+
for (let i = 0; i < level.length; i += 4) {
25+
level[i] += prev;
26+
prev = level[i] + level[i + 1];
27+
}
28+
}
29+
return levelsCopy;
30+
}

0 commit comments

Comments
 (0)