diff --git a/bolt/internal/internal.proto b/bolt/internal/internal.proto index 27dec2513c..f11b3bc833 100644 --- a/bolt/internal/internal.proto +++ b/bolt/internal/internal.proto @@ -97,7 +97,7 @@ message Template { } message TemplateValue { - string type = 1; // Type can be tagKey, tagValue, fieldKey, csv, measurement, database, constant + string type = 1; // Type can be tagKey, tagValue, fieldKey, csv, map, measurement, database, constant string value = 2; // Value is the specific value used to replace a template in an InfluxQL query bool selected = 3; // Selected states that this variable has been picked to use for replacement string key = 4; // Key is the key for a specific Value if the Template Type is map (optional) diff --git a/chronograf.go b/chronograf.go index 8a1c54f47d..3f83f8f950 100644 --- a/chronograf.go +++ b/chronograf.go @@ -159,7 +159,7 @@ type Range struct { // TemplateValue is a value use to replace a template in an InfluxQL query type TemplateValue struct { Value string `json:"value"` // Value is the specific value used to replace a template in an InfluxQL query - Type string `json:"type"` // Type can be tagKey, tagValue, fieldKey, csv, measurement, database, constant, influxql + Type string `json:"type"` // Type can be tagKey, tagValue, fieldKey, csv, map, measurement, database, constant, influxql Selected bool `json:"selected"` // Selected states that this variable has been picked to use for replacement Key string `json:"key,omitempty"` // Key is the key for the Value if the Template Type is 'map' } @@ -177,7 +177,7 @@ type TemplateID string type Template struct { TemplateVar ID TemplateID `json:"id"` // ID is the unique ID associated with this template - Type string `json:"type"` // Type can be fieldKeys, tagKeys, tagValues, CSV, constant, measurements, databases, map, influxql + Type string `json:"type"` // Type can be fieldKeys, tagKeys, tagValues, csv, constant, measurements, databases, map, influxql Label string `json:"label"` // Label is a user-facing description of the Template Query *TemplateQuery `json:"query,omitempty"` // Query is used to generate the choices for a template } diff --git a/server/swagger.json b/server/swagger.json index 3225d598aa..9896b5171a 100644 --- a/server/swagger.json +++ b/server/swagger.json @@ -4179,7 +4179,7 @@ }, "type": { "type": "string", - "enum": ["csv", "tagKey", "tagValue", "fieldKey", "timeStamp"], + "enum": ["csv", "tagKey", "tagValue", "fieldKey", "timeStamp", "map"], "description": "The type will change the format of the output value. tagKey/fieldKey are double quoted; tagValue are single quoted; csv and timeStamp are not quoted." }, diff --git a/server/templates.go b/server/templates.go index 6f158ac3c3..fcb7a365e1 100644 --- a/server/templates.go +++ b/server/templates.go @@ -22,7 +22,7 @@ func ValidTemplateRequest(template *chronograf.Template) error { switch v.Type { default: return fmt.Errorf("Unknown template variable type %s", v.Type) - case "csv", "fieldKey", "tagKey", "tagValue", "measurement", "database", "constant", "influxql": + case "csv", "map", "fieldKey", "tagKey", "tagValue", "measurement", "database", "constant", "influxql": } if template.Type == "map" && v.Key == "" { diff --git a/server/templates_test.go b/server/templates_test.go index cd775acea9..4a23fefefd 100644 --- a/server/templates_test.go +++ b/server/templates_test.go @@ -69,7 +69,7 @@ func TestValidTemplateRequest(t *testing.T) { { Key: "key", Value: "value", - Type: "constant", + Type: "map", }, }, }, @@ -84,7 +84,7 @@ func TestValidTemplateRequest(t *testing.T) { Values: []chronograf.TemplateValue{ { Value: "value", - Type: "constant", + Type: "map", }, }, }, diff --git a/ui/src/dashboards/actions/index.ts b/ui/src/dashboards/actions/index.ts index 86db269b03..071a4ae4b4 100644 --- a/ui/src/dashboards/actions/index.ts +++ b/ui/src/dashboards/actions/index.ts @@ -312,7 +312,10 @@ const removeUnselectedTemplateValues = ( 'templates', [] ).map(template => { - if (template.type === TempVarsModels.TemplateType.CSV) { + if ( + template.type === TempVarsModels.TemplateType.CSV || + template.type === TempVarsModels.TemplateType.Map + ) { return template } diff --git a/ui/src/shared/copy/notifications.ts b/ui/src/shared/copy/notifications.ts index 879ed8e090..6ed110f0b1 100644 --- a/ui/src/shared/copy/notifications.ts +++ b/ui/src/shared/copy/notifications.ts @@ -541,6 +541,12 @@ export const notifyInvalidTimeRangeValueInURLQuery = (): Notification => ({ message: `Invalid URL query value supplied for lower or upper time range.`, }) +export const notifyInvalidMapType = (): Notification => ({ + ...defaultErrorNotification, + icon: 'cube', + message: `Template Variables of map type accept two comma separated values per line`, +}) + export const notifyInvalidZoomedTimeRangeValueInURLQuery = (): Notification => ({ ...defaultErrorNotification, icon: 'cube', diff --git a/ui/src/tempVars/components/MapTemplateBuilder.tsx b/ui/src/tempVars/components/MapTemplateBuilder.tsx new file mode 100644 index 0000000000..cb4b1fa425 --- /dev/null +++ b/ui/src/tempVars/components/MapTemplateBuilder.tsx @@ -0,0 +1,154 @@ +import React, {PureComponent, ChangeEvent} from 'react' +import {getDeep} from 'src/utils/wrappers' +import Papa from 'papaparse' +import _ from 'lodash' + +import {ErrorHandling} from 'src/shared/decorators/errors' + +import TemplatePreviewList from 'src/tempVars/components/TemplatePreviewList' +import DragAndDrop from 'src/shared/components/DragAndDrop' +import { + notifyCSVUploadFailed, + notifyInvalidMapType, +} from 'src/shared/copy/notifications' + +import {TemplateBuilderProps, TemplateValueType} from 'src/types' +import {trimAndRemoveQuotes} from 'src/tempVars/utils/parsing' + +interface State { + templateValuesString: string +} + +@ErrorHandling +class MapTemplateBuilder extends PureComponent { + public constructor(props: TemplateBuilderProps) { + super(props) + const templateValues = props.template.values.map(v => v.value) + const templateKeys = props.template.values.map(v => v.key) + const templateValuesString = templateKeys + .map((v, i) => `${v}, ${templateValues[i]}`) + .join('\n') + + this.state = { + templateValuesString, + } + } + + public render() { + const {onUpdateDefaultTemplateValue, template} = this.props + const {templateValuesString} = this.state + const pluralizer = template.values.length === 1 ? '' : 's' + + return ( + <> +
+ + +
+
+ +
+