diff --git a/pkg/plugin/parsing/parsing.go b/pkg/plugin/parsing/parsing.go index f9ae9f3..db24dc9 100644 --- a/pkg/plugin/parsing/parsing.go +++ b/pkg/plugin/parsing/parsing.go @@ -150,13 +150,20 @@ func getLabelsFromFlatData(flatData *jsonnode.Object, parsingOption querymodel.P case querymodel.FIELD: fieldValue := flatData.Get(labelOption.Value) if fieldValue == nil { - return nil, errors.New(fmt.Sprintf("Label option: %s could not be satisfied as key %s does not exist", labelOption.Name, labelOption.Value)) - } - switch typedFieldValue := fieldValue.(type) { - case jsonnode.String: - labels[labelOption.Name] = typedFieldValue.String() - default: - return nil, errors.New(fmt.Sprintf("Label option: %s could not be satisfied as key %s is not a string. It's type is %v", labelOption.Name, labelOption.Value, reflect.TypeOf(typedFieldValue))) + fieldConfig := labelOption.FieldConfig + if fieldConfig != nil && fieldConfig.Required { + return nil, errors.New(fmt.Sprintf("Label option: %s could not be satisfied as key %s does not exist", labelOption.Name, labelOption.Value)) + } else if fieldConfig != nil && fieldConfig.DefaultValue != nil { + labels[labelOption.Name] = *fieldConfig.DefaultValue + } + // else omit + } else { + switch typedFieldValue := fieldValue.(type) { + case jsonnode.String: + labels[labelOption.Name] = typedFieldValue.String() + default: + return nil, errors.New(fmt.Sprintf("Label option: %s could not be satisfied as key %s is not a string. It's type is %v", labelOption.Name, labelOption.Value, reflect.TypeOf(typedFieldValue))) + } } } } diff --git a/pkg/plugin/querymodel/querymodel.go b/pkg/plugin/querymodel/querymodel.go index 462da8a..1810555 100644 --- a/pkg/plugin/querymodel/querymodel.go +++ b/pkg/plugin/querymodel/querymodel.go @@ -32,9 +32,14 @@ const ( ) type LabelOption struct { - Name string `json:"name"` - Type LabelOptionType `json:"type"` - Value string `json:"value"` + Name string `json:"name"` + Type LabelOptionType `json:"type"` + Value string `json:"value"` + FieldConfig *LabelOptionFieldConfig `json:"fieldConfig"` +} +type LabelOptionFieldConfig struct { + Required bool `json:"required"` + DefaultValue *string `json:"defaultValue"` } func (parsingOption *ParsingOption) GetTimeField(key string) *TimeField { diff --git a/src/components/QueryEditor.tsx b/src/components/QueryEditor.tsx index b92ad8e..d40a275 100644 --- a/src/components/QueryEditor.tsx +++ b/src/components/QueryEditor.tsx @@ -3,10 +3,12 @@ import {Button, IconButton, InlineField, Input, Select} from '@grafana/ui'; import {CoreApp, QueryEditorProps} from '@grafana/data'; import {DataSource} from '../datasource'; import { + DEFAULT_LABEL_OPTION_FIELD_CONFIG, getQueryVariablesAsJsonString, LabelOption, LabelOptionType, - ParsingOption, TimeField, + ParsingOption, + TimeField, WildGraphQLAnyQuery, WildGraphQLDataSourceOptions } from '../types'; @@ -444,47 +446,101 @@ function InnerQueryEditor({ query, onChange, onRunQuery, datasource }: Props) { } )} - {parsingOption.labelOptions?.map((labelOption, labelOptionIndex) => <> -
- - { + const newType = value.value; + if (newType !== undefined) { + setLabelOption(parsingOptionIndex, labelOptionIndex, { + ...labelOption, + type: newType, + }); + } + }} + /> + + + + { setLabelOption(parsingOptionIndex, labelOptionIndex, { ...labelOption, - type: newType, - }); - } - }} - /> + value: event.currentTarget.value, + }) + }} + /> + - - - { - setLabelOption(parsingOptionIndex, labelOptionIndex, { - ...labelOption, - value: event.currentTarget.value, - }) - }} - /> - - deleteLabelOption(parsingOptionIndex, labelOptionIndex)}/> -
- )} + {fieldConfig && + + { + setLabelOption(parsingOptionIndex, labelOptionIndex, { + ...labelOption, + fieldConfig: { + required: false, + defaultValue: event.currentTarget.value + } + }) + }} + /> + + } + deleteLabelOption(parsingOptionIndex, labelOptionIndex)}/> + + ; + })} ; })} diff --git a/src/types.ts b/src/types.ts index fef91ea..f4cba76 100644 --- a/src/types.ts +++ b/src/types.ts @@ -14,11 +14,20 @@ export interface LabelOption { /** When {@link type} is {@link LabelOptionType.CONSTANT}, this represents a text value that is constant. * When {@link type} is {@link LabelOptionType.FIELD}, this represents the path to a field relative to the data path */ value: string; + /** May be defined when {@link type} is {@link LabelOptionType.Field}. */ + fieldConfig?: LabelOptionFieldConfig; } export enum LabelOptionType { CONSTANT = "constant", FIELD = "field", } +export interface LabelOptionFieldConfig { + required: boolean; + defaultValue?: string; +} +export const DEFAULT_LABEL_OPTION_FIELD_CONFIG: LabelOptionFieldConfig = { // omit is default + required: false +} export interface ParsingOption { // TODO make sure an empty string is valid in the backend like this says