Skip to content

Commit 4348a51

Browse files
authored
Merge pull request #125 from GridProtectionAlliance/feature/v4.1.0
Added calulation when last value is selected. Modified the links to b…
2 parents cde71b2 + 72c6b4d commit 4348a51

File tree

7 files changed

+73
-45
lines changed

7 files changed

+73
-45
lines changed

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,10 @@
2626
- Updated to Grafana plugin SDK v9.4.7
2727
- Fixed PI AF calculation
2828
- Added plugin screenshots
29+
30+
## 4.1.0
31+
32+
- Modified the PI Webapi controller endpoints used when calculation is selected
33+
- Allow calculation when last value option is selected
34+
- When calculation is selected, change label from Interpolated to Interval
35+
- Fixed issue with variable in Element Path

dist/module.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/module.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/plugin.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@
3636
{"name": "Datasource Configuration", "path": "img/configuration.png"},
3737
{"name": "Annotations Editor", "path": "img/annotations.png"}
3838
],
39-
"version": "4.0.0",
40-
"updated": "2023-05-02"
39+
"version": "4.1.0",
40+
"updated": "2023-05-29"
4141
},
4242
"dependencies": {
4343
"grafanaDependency": ">=8.4.0",

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "grid-protection-alliance-osisoftpi-grafana",
3-
"version": "4.0.0",
3+
"version": "4.1.0",
44
"description": "OSISoft PI Grafana Plugin",
55
"scripts": {
66
"build": "grafana-toolkit plugin:build",

src/datasource.ts

+23-8
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ export class PiWebAPIDatasource extends DataSourceApi<PIWebAPIQuery, PIWebAPIDat
203203
.then((result: PiwebapiRsp) => [result])
204204
.then(metricQueryTransform)
205205
: ds.getAssetServers().then(metricQueryTransform);
206+
} else if (query.type === 'databases' && !!query.afServerWebId) {
207+
return ds.getDatabases(query.afServerWebId, {}).then(metricQueryTransform);
206208
} else if (query.type === 'databases') {
207209
return ds
208210
.getAssetServer(query.path)
@@ -718,19 +720,32 @@ export class PiWebAPIDatasource extends DataSourceApi<PIWebAPIQuery, PIWebAPIDat
718720
let url = '';
719721
const isSummary = target.summary && target.summary.types && target.summary.types.length > 0;
720722
const isInterpolated = target.interpolate && target.interpolate.enable;
723+
const isRecorded = target.recordedValues && target.recordedValues.enable;
721724
// perhaps add a check to see if interpolate override time < query.interval
722725
const intervalTime = target.interpolate.interval ? target.interpolate.interval : query.interval;
723726
const timeRange = '?startTime=' + query.range.from.toJSON() + '&endTime=' + query.range.to.toJSON();
724727
const targetName = target.expression || target.elementPath;
725728
const displayName = target.display ? this.templateSrv.replace(target.display, query.scopedVars) : null;
726729
if (target.expression) {
727730
url += '/calculation';
728-
if (isSummary) {
731+
if (target.useLastValue?.enable) {
732+
url += '/times?&time=' + query.range.to.toJSON();
733+
} else if (isSummary) {
729734
url += '/summary' + timeRange + (isInterpolated ? '&sampleType=Interval&sampleInterval=' + intervalTime : '');
730735
} else if (isInterpolated) {
731736
url += '/intervals' + timeRange + '&sampleInterval=' + intervalTime;
732-
} else {
737+
} else if (isRecorded) {
733738
url += '/recorded' + timeRange;
739+
} else {
740+
const windowWidth = 40;
741+
const diff = Math.floor((query.range.to.valueOf() - query.range.from.valueOf()) / windowWidth);
742+
let timeQuery = 'time=' + query.range.from.toJSON();
743+
for (let i = 1; i < windowWidth; i ++) {
744+
const newTime = query.range.from.valueOf() + i * diff;
745+
timeQuery += '&time=' + new Date(newTime).toISOString();
746+
}
747+
timeQuery += '&time=' + query.range.to.toJSON();
748+
url += '/times?' + timeQuery;
734749
}
735750
url += '&expression=' + encodeURIComponent(target.expression.replace(/\${intervalTime}/g, intervalTime));
736751
if (target.attributes.length > 0) {
@@ -749,18 +764,18 @@ export class PiWebAPIDatasource extends DataSourceApi<PIWebAPIQuery, PIWebAPIDat
749764
}
750765
} else {
751766
url += '/streamsets';
752-
if (isSummary) {
767+
if (target.useLastValue?.enable) {
768+
url += '/value?time=' + query.range.to.toJSON();
769+
} else if (isSummary) {
753770
url += '/summary' + timeRange + '&intervals=' + query.maxDataPoints + this.getSummaryUrl(target.summary);
754771
} else if (isInterpolated) {
755772
url += '/interpolated' + timeRange + '&interval=' + intervalTime;
756-
} else if (target.recordedValues && target.recordedValues.enable) {
773+
} else if (isRecorded) {
757774
const maxNumber =
758775
target.recordedValues.maxNumber && !isNaN(target.recordedValues.maxNumber)
759776
? target.recordedValues.maxNumber
760777
: query.maxDataPoints;
761778
url += '/recorded' + timeRange + '&maxCount=' + maxNumber;
762-
} else if (target.useLastValue?.enable) {
763-
url += '/value?time=' + query.range.to.toJSON();
764779
} else {
765780
url += '/plot' + timeRange + '&intervals=' + query.maxDataPoints;
766781
}
@@ -782,9 +797,9 @@ export class PiWebAPIDatasource extends DataSourceApi<PIWebAPIQuery, PIWebAPIDat
782797
private handleBatchResponse(response: any, target: any, displayName: string | null): Promise<PiwebapTargetRsp[]> {
783798
const targetName = target.expression || target.elementPath;
784799
const noTemplate = target.elementPathArray.length === 1 && target.elementPath === target.elementPathArray[0].path;
785-
let index = 1;
800+
const totalSize = noTemplate ? target.attributes.length : target.elementPathArray.length;
786801
const targetResults: PiwebapTargetRsp[] = [];
787-
for (const _ of target.attributes) {
802+
for (let index = 1; index <= totalSize; index++) {
788803
const dataKey = `Req${index + 1000}`;
789804
const path = response.config.data[dataKey].Headers ? response.config.data[dataKey].Headers['Asset-Path'] : null;
790805
const data = response.data[dataKey];

src/query/QueryEditor.tsx

+38-32
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,10 @@ export class PIWebAPIQueryEditor extends PureComponent<Props, State> {
349349
const ctrl = this;
350350
const findQuery = query.isPiPoint
351351
? { type: 'dataserver' }
352-
: { path: this.getSegmentPathUpTo(currentSegment ?? this.state.segments.slice(0), index) };
352+
: {
353+
path: this.getSegmentPathUpTo(currentSegment ?? this.state.segments.slice(0), index),
354+
afServerWebId: this.state.segments[0].value ? this.state.segments[0].value.webId : undefined,
355+
};
353356

354357
if (!query.isPiPoint) {
355358
if (datasource.afserver?.name && index === 0) {
@@ -374,10 +377,6 @@ export class PIWebAPIQueryEditor extends PureComponent<Props, State> {
374377
},
375378
]);
376379
}
377-
378-
// if (!findQuery.path?.length) {
379-
// return Promise.resolve([]);
380-
// }
381380
}
382381
return datasource
383382
.metricFindQuery(findQuery, Object.assign(data?.request?.scopedVars ?? {}, { isPiPoint: query.isPiPoint }))
@@ -1060,7 +1059,11 @@ export class PIWebAPIQueryEditor extends PureComponent<Props, State> {
10601059
)}
10611060

10621061
<InlineFieldRow>
1063-
<InlineField label="Use Last Value" labelWidth={LABEL_WIDTH}>
1062+
<InlineField
1063+
label="Use Last Value"
1064+
tooltip={"Fetch only last value from time range"}
1065+
labelWidth={LABEL_WIDTH}
1066+
>
10641067
<InlineSwitch
10651068
value={useLastValue.enable}
10661069
onChange={() =>
@@ -1071,11 +1074,12 @@ export class PIWebAPIQueryEditor extends PureComponent<Props, State> {
10711074
}
10721075
/>
10731076
</InlineField>
1074-
</InlineFieldRow>
1075-
1076-
{this.props.datasource.useUnitConfig && (
1077-
<InlineFieldRow>
1078-
<InlineField label="Use unit from datapoints" labelWidth={LABEL_WIDTH}>
1077+
{this.props.datasource.useUnitConfig && (
1078+
<InlineField
1079+
label="Use unit from datapoints"
1080+
tooltip={"Use unit in label from PI tag or PI AF attribute"}
1081+
labelWidth={LABEL_WIDTH}
1082+
>
10791083
<InlineSwitch
10801084
value={useUnit.enable}
10811085
onChange={() =>
@@ -1086,28 +1090,30 @@ export class PIWebAPIQueryEditor extends PureComponent<Props, State> {
10861090
}
10871091
/>
10881092
</InlineField>
1089-
</InlineFieldRow>
1090-
)}
1093+
)}
1094+
</InlineFieldRow>
10911095

1092-
{!useLastValue.enable && (
1093-
<>
1094-
<InlineField
1095-
label="Calculation"
1096-
labelWidth={LABEL_WIDTH}
1097-
tooltip={
1098-
"Modify all attributes by an equation. Use '.' for current item. Leave Attributes empty if you wish to perform element based calculations."
1096+
<InlineFieldRow>
1097+
<InlineField
1098+
label="Calculation"
1099+
labelWidth={LABEL_WIDTH}
1100+
tooltip={
1101+
"Modify all attributes by an equation. Use '.' for current item. Leave Attributes empty if you wish to perform element based calculations."
1102+
}
1103+
>
1104+
<Input
1105+
onBlur={onRunQuery}
1106+
value={expression}
1107+
onChange={(event: ChangeEvent<HTMLInputElement>) =>
1108+
onChange({ ...metricsQuery, expression: event.target.value })
10991109
}
1100-
>
1101-
<Input
1102-
onBlur={onRunQuery}
1103-
value={expression}
1104-
onChange={(event: ChangeEvent<HTMLInputElement>) =>
1105-
onChange({ ...metricsQuery, expression: event.target.value })
1106-
}
1107-
placeholder="'.'*2"
1108-
/>
1109-
</InlineField>
1110+
placeholder="'.'*2"
1111+
/>
1112+
</InlineField>
1113+
</InlineFieldRow>
11101114

1115+
{!useLastValue.enable && (
1116+
<>
11111117
<InlineFieldRow>
11121118
<InlineField
11131119
label="Max Recorded Values"
@@ -1155,7 +1161,7 @@ export class PIWebAPIQueryEditor extends PureComponent<Props, State> {
11551161

11561162
<InlineFieldRow>
11571163
<InlineField
1158-
label="Interpolate Period"
1164+
label={!!expression ? "Interval Period" : "Interpolate Period"}
11591165
labelWidth={LABEL_WIDTH}
11601166
tooltip={"Override time between sampling, e.g. '30s'. Defaults to timespan/chart width."}
11611167
>
@@ -1168,7 +1174,7 @@ export class PIWebAPIQueryEditor extends PureComponent<Props, State> {
11681174
placeholder="30s"
11691175
/>
11701176
</InlineField>
1171-
<InlineField label="Interpolate" labelWidth={LABEL_WIDTH}>
1177+
<InlineField label={!!expression ? "Interval Values" : "Interpolate"} labelWidth={LABEL_WIDTH}>
11721178
<InlineSwitch
11731179
value={interpolate.enable}
11741180
onChange={() =>

0 commit comments

Comments
 (0)