Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/v5.1.0 #163

Merged
merged 6 commits into from
Sep 23, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Version 5.1.0 initial commit
coderReview committed Sep 6, 2024
commit 67de00ecc789302af6756d9ce3e0200c3905d8e4
2 changes: 1 addition & 1 deletion dist/module.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/module.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/plugin.json
Original file line number Diff line number Diff line change
@@ -40,7 +40,7 @@
{"name": "Annotations Editor", "path": "img/annotations.png"}
],
"version": "5.1.0",
"updated": "2024-08-13"
"updated": "2024-09-06"
},
"dependencies": {
"grafanaDependency": ">=10.1.0",
3 changes: 2 additions & 1 deletion pkg/plugin/annotation_query.go
Original file line number Diff line number Diff line change
@@ -80,7 +80,8 @@ func (d *Datasource) processAnnotationQuery(ctx context.Context, query backend.D
}

func (q PiProcessedAnnotationQuery) getTimeRangeURIComponent() string {
return "&startTime=" + q.TimeRange.From.UTC().Format(time.RFC3339) + "&endTime=" + q.TimeRange.To.UTC().Format(time.RFC3339)
return "&startTime=" + q.TimeRange.From.UTC().Truncate(time.Second).Format(time.RFC3339) +
"&endTime=" + q.TimeRange.To.UTC().Truncate(time.Second).Format(time.RFC3339)
}

// getEventFrameQueryURL returns the URI for the event frame query
4 changes: 2 additions & 2 deletions pkg/plugin/datasource.go
Original file line number Diff line number Diff line change
@@ -183,8 +183,8 @@ func (d *Datasource) QueryAnnotations(ctx context.Context, req *backend.QueryDat
trace.WithAttributes(
attribute.String("query.ref_id", q.RefID),
attribute.String("query.type", q.QueryType),
attribute.Int64("query.time_range.from", q.TimeRange.From.Unix()),
attribute.Int64("query.time_range.to", q.TimeRange.To.Unix()),
attribute.Int64("query.time_range.from", q.TimeRange.From.Truncate(time.Second).Unix()),
attribute.Int64("query.time_range.to", q.TimeRange.To.Truncate(time.Second).Unix()),
),
)

5 changes: 3 additions & 2 deletions pkg/plugin/helpers.go
Original file line number Diff line number Diff line change
@@ -373,6 +373,7 @@ func getDataLabels(useNewFormat bool, q *PiProcessedQuery, pointType string, sum
} else {
label = targetParts[len(targetParts)-1]
}
label += summaryLabel
}

if q.IsPIPoint {
@@ -413,7 +414,7 @@ func convertItemsToDataFrame(processedQuery *PiProcessedQuery, d *Datasource, Su
webID := processedQuery.WebID
includeMetaData := processedQuery.UseUnit
digitalStates := processedQuery.DigitalStates
noDataReplace := processedQuery.getSummaryNoDataReplace()
noDataReplace := processedQuery.getNoDataReplace()

digitalStateValues := make([]string, 0)
sliceType := d.getTypeForWebID(webID)
@@ -518,7 +519,7 @@ func convertItemsToDataFrame(processedQuery *PiProcessedQuery, d *Datasource, Su
// in the slice type, or values that are not "good"
valuepointers := convertSliceToPointers(fP.values, fP.badValues)

timeField := data.NewField("time", nil, fP.timestamps)
timeField := data.NewField("Time", nil, fP.timestamps)
if !digitalState || !digitalStates {
valueField := data.NewField(frameLabel["name"], labels, valuepointers)
frame.Fields = append(frame.Fields,
43 changes: 29 additions & 14 deletions pkg/plugin/timeseries_query.go
Original file line number Diff line number Diff line change
@@ -99,6 +99,7 @@ func (d *Datasource) processQuery(query backend.DataQuery, datasourceUID string)
DigitalStates: DigitalStates,
Display: PiQuery.Pi.Display,
Regex: PiQuery.Pi.Regex,
Nodata: PiQuery.Pi.Nodata,
Summary: PiQuery.Pi.Summary,
Variable: PiQuery.Pi.getVariable(i),
Index: (j + 1) + 100*(i+1),
@@ -321,10 +322,10 @@ func (q *PIWebAPIQuery) isSummary() bool {
if q.Summary == nil {
return false
}
if q.Summary.Types == nil {
if q.Summary.Enable == nil {
return false
}
return *q.Summary.Basis != "" && len(*q.Summary.Types) > 0
return *q.Summary.Enable && *q.Summary.Basis != "" && len(*q.Summary.Types) > 0
}

// PiProcessedQuery isRegex returns true if the query is a regex query and is enabled
@@ -364,17 +365,28 @@ func (q *PiProcessedQuery) isRegexQuery() bool {
// A default of 30s is returned if the summary duration is not provided by the frontend
// or if the format is invalid
func (q *PIWebAPIQuery) getSummaryDuration() string {
backend.Logger.Debug("Summary duration", "summary", q.Summary)
// Return the default value if the summary is not provided by the frontend
if q.Summary == nil || *q.Summary.Interval == "" {
if q.Summary == nil || q.Summary.Duration == nil || *q.Summary.Duration == "" {
return "30s"
}
return _getDurationBase(*q.Summary.Duration)
}

// If the summary duration is provided, then validate the format piwebapi expects
func (q *PIWebAPIQuery) getSampleInterval() string {
// Return the default value if the summary is not provided by the frontend
if q.Summary == nil || q.Summary.SampleInterval == nil || *q.Summary.SampleInterval == "" {
return "30s"
}
return _getDurationBase(*q.Summary.SampleInterval)
}

func _getDurationBase(duration string) string {
// If the summary duration is provided, then validate the format piwebapi expects
// Regular expression to match the format: <number><short_name>
pattern := `^(\d+(\.\d+)?)\s*(ms|s|m|h|d|mo|w|wd|yd)$`
re := regexp.MustCompile(pattern)
matches := re.FindStringSubmatch(*q.Summary.Interval)
matches := re.FindStringSubmatch(duration)

if len(matches) != 4 {
return "30s" // Return the default value if the format is invalid
@@ -394,11 +406,11 @@ func (q *PIWebAPIQuery) getSummaryDuration() string {
switch shortName {
case "ms", "s", "m", "h":
// Fractions allowed for millisecond, second, minute, and hour
return *q.Summary.Interval
return duration
case "d", "mo", "w", "wd", "yd":
// No fractions allowed for day, month, week, weekday, yearday
if numericPart == float64(int64(numericPart)) {
return *q.Summary.Interval
return duration
}
default:
return "30s" // Return the default value if the short name or fractions are not allowed
@@ -413,7 +425,13 @@ func (q *PIWebAPIQuery) getSummaryURIComponent() string {
uri += "&summaryType=" + t.Value.Value
}
uri += "&summaryBasis=" + *q.Summary.Basis
uri += "&summaryDuration=" + q.getSummaryDuration()
if q.Summary.Duration != nil && *q.Summary.Duration != "" {
uri += "&summaryDuration=" + q.getSummaryDuration()
}
if q.Summary.SampleTypeInterval != nil && *q.Summary.SampleTypeInterval &&
q.Summary.SampleInterval != nil && *q.Summary.SampleInterval != "" {
uri += "&sampleType=Interval&sampleInterval=" + q.getSampleInterval()
}
return uri
}

@@ -572,10 +590,7 @@ func (q Query) getQueryBaseURL() string {
uri += "/times?time=" + q.getTimeRangeURIToComponent()
} else {
if q.Pi.isSummary() {
uri += "/summary" + q.getTimeRangeURIComponent()
if q.Pi.isInterpolated() {
uri += fmt.Sprintf("&sampleType=Interval&sampleInterval=%s", q.getIntervalTime())
}
uri += "/summary" + q.getTimeRangeURIComponent() + q.Pi.getSummaryURIComponent()
} else if q.Pi.isInterpolated() {
uri += "/intervals" + q.getTimeRangeURIComponent()
uri += fmt.Sprintf("&sampleInterval=%s", q.getIntervalTime())
@@ -597,8 +612,7 @@ func (q Query) getQueryBaseURL() string {
}
} else {
if q.Pi.isSummary() {
uri += "/summary" + q.getTimeRangeURIComponent() + fmt.Sprintf("&intervals=%d", q.getMaxDataPoints())
uri += q.Pi.getSummaryURIComponent()
uri += "/summary" + q.getTimeRangeURIComponent() + q.Pi.getSummaryURIComponent()
} else if q.Pi.isInterpolated() {
uri += "/interpolated" + q.getTimeRangeURIComponent() + fmt.Sprintf("&interval=%s", q.getIntervalTime())
} else if q.Pi.isRecordedValues() {
@@ -609,5 +623,6 @@ func (q Query) getQueryBaseURL() string {
uri += "&webId="
}
}
backend.Logger.Debug("Base url", "uri", uri)
return uri
}
34 changes: 18 additions & 16 deletions pkg/plugin/timeseries_query_models.go
Original file line number Diff line number Diff line change
@@ -43,8 +43,8 @@ func (q *Query) getIntervalTime() string {
func (q *Query) getWindowedTimeStampURI() string {
// Potential Improvement: Make windowWidth a user input
windowWidth := q.getMaxDataPoints()
fromTime := q.TimeRange.From
toTime := q.TimeRange.To
fromTime := q.TimeRange.From.Truncate(time.Second)
toTime := q.TimeRange.To.Truncate(time.Second)

diff := toTime.Sub(fromTime).Nanoseconds() / int64(windowWidth)
timeQuery := "time=" + fromTime.Format(time.RFC3339)
@@ -60,11 +60,12 @@ func (q *Query) getWindowedTimeStampURI() string {
}

func (q *Query) getTimeRangeURIComponent() string {
return "?startTime=" + q.TimeRange.From.UTC().Format(time.RFC3339) + "&endTime=" + q.TimeRange.To.UTC().Format(time.RFC3339)
return "?startTime=" + q.TimeRange.From.UTC().Truncate(time.Second).Format(time.RFC3339) +
"&endTime=" + q.TimeRange.To.UTC().Truncate(time.Second).Format(time.RFC3339)
}

func (q *Query) getTimeRangeURIToComponent() string {
return q.TimeRange.To.UTC().Format(time.RFC3339)
return q.TimeRange.To.UTC().Truncate(time.Second).Format(time.RFC3339)
}

func (q *Query) isstreamingEnabled() bool {
@@ -89,14 +90,11 @@ func (q *Query) isStreamable() bool {
// return *q.Summary.Basis != "" && len(*q.Summary.Types) > 0
// }

func (q *PiProcessedQuery) getSummaryNoDataReplace() string {
if q.Summary == nil {
func (q *PiProcessedQuery) getNoDataReplace() string {
if q.Nodata == nil {
return ""
}
if q.Summary.Nodata == nil {
return ""
}
return *q.Summary.Nodata
return *q.Nodata
}

type PIWebAPIQuery struct {
@@ -130,8 +128,9 @@ type PIWebAPIQuery struct {
MaxNumber *int `json:"maxNumber"`
BoundaryType *string `json:"boundaryType"`
} `json:"recordedValues"`
RefID *string `json:"refId"`
Regex *Regex `json:"regex"`
RefID *string `json:"refId"`
Regex *Regex `json:"regex"`
Nodata *string `json:"nodata"`
// Segments *[]string `json:"segments"`
Summary *QuerySummary `json:"summary"`
Target *string `json:"target"`
@@ -142,10 +141,12 @@ type PIWebAPIQuery struct {
}

type QuerySummary struct {
Basis *string `json:"basis"`
Interval *string `json:"interval"`
Nodata *string `json:"nodata"`
Types *[]SummaryType `json:"types"`
Enable *bool `json:"enable"`
Basis *string `json:"basis"`
Duration *string `json:"duration"`
Types *[]SummaryType `json:"types"`
SampleTypeInterval *bool `json:"sampleTypeInterval"`
SampleInterval *string `json:"sampleInterval"`
}

type QueryPropertiesValue struct {
@@ -197,6 +198,7 @@ type PiProcessedQuery struct {
UseUnit bool `json:"UseUnit"`
DigitalStates bool `json:"DigitalStates"`
Display *string `json:"Display"`
Nodata *string `json:"Nodata"`
Error error
Index int
Resource string
15 changes: 10 additions & 5 deletions src/datasource.ts
Original file line number Diff line number Diff line change
@@ -251,7 +251,8 @@ export class PiWebAPIDatasource extends DataSourceWithBackend<PIWebAPIQuery, PIW
webid: target.webid ?? '',
regex: target.regex || { enable: false },
expression: target.expression || '',
summary: target.summary || { types: [] },
summary: target.summary || { enable: false, types: [] },
nodata: target.nodata,
startTime: options.range.from,
endTime: options.range.to,
isPiPoint: !!target.isPiPoint,
@@ -263,13 +264,17 @@ export class PiWebAPIDatasource extends DataSourceWithBackend<PIWebAPIQuery, PIW
tar.expression = this.templateSrv.replace(tar.expression, options.scopedVars);
}

if (tar.summary.types !== undefined) {
if (tar.summary.enable && tar.summary.types !== undefined) {
tar.summary.types = filter(tar.summary.types, (item) => {
return item !== undefined && item !== null && item !== '';
});
tar.summary.interval = !!tar.summary.interval
? this.templateSrv.replace(tar.summary.interval, options.scopedVars)
: tar.summary.interval;
tar.summary.duration = !!tar.summary.duration
? this.templateSrv.replace(tar.summary.duration, options.scopedVars)
: tar.summary.duration;
tar.summary.sampleTypeInterval = !!tar.summary.sampleTypeInterval;
tar.summary.sampleInterval = !!tar.summary.sampleInterval
? this.templateSrv.replace(tar.summary.sampleInterval, options.scopedVars)
: tar.summary.sampleInterval;
}

return tar;
Loading