Skip to content

Commit 3adb660

Browse files
Added field config for label option to mark requiredness and config default value
1 parent 25b090d commit 3adb660

File tree

4 files changed

+126
-49
lines changed

4 files changed

+126
-49
lines changed

pkg/plugin/parsing/parsing.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,20 @@ func getLabelsFromFlatData(flatData *jsonnode.Object, parsingOption querymodel.P
150150
case querymodel.FIELD:
151151
fieldValue := flatData.Get(labelOption.Value)
152152
if fieldValue == nil {
153-
return nil, errors.New(fmt.Sprintf("Label option: %s could not be satisfied as key %s does not exist", labelOption.Name, labelOption.Value))
154-
}
155-
switch typedFieldValue := fieldValue.(type) {
156-
case jsonnode.String:
157-
labels[labelOption.Name] = typedFieldValue.String()
158-
default:
159-
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)))
153+
fieldConfig := labelOption.FieldConfig
154+
if fieldConfig != nil && fieldConfig.Required {
155+
return nil, errors.New(fmt.Sprintf("Label option: %s could not be satisfied as key %s does not exist", labelOption.Name, labelOption.Value))
156+
} else if fieldConfig != nil && fieldConfig.DefaultValue != nil {
157+
labels[labelOption.Name] = *fieldConfig.DefaultValue
158+
}
159+
// else omit
160+
} else {
161+
switch typedFieldValue := fieldValue.(type) {
162+
case jsonnode.String:
163+
labels[labelOption.Name] = typedFieldValue.String()
164+
default:
165+
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)))
166+
}
160167
}
161168
}
162169
}

pkg/plugin/querymodel/querymodel.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,14 @@ const (
3232
)
3333

3434
type LabelOption struct {
35-
Name string `json:"name"`
36-
Type LabelOptionType `json:"type"`
37-
Value string `json:"value"`
35+
Name string `json:"name"`
36+
Type LabelOptionType `json:"type"`
37+
Value string `json:"value"`
38+
FieldConfig *LabelOptionFieldConfig `json:"fieldConfig"`
39+
}
40+
type LabelOptionFieldConfig struct {
41+
Required bool `json:"required"`
42+
DefaultValue *string `json:"defaultValue"`
3843
}
3944

4045
func (parsingOption *ParsingOption) GetTimeField(key string) *TimeField {

src/components/QueryEditor.tsx

Lines changed: 95 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import {Button, IconButton, InlineField, Input, Select} from '@grafana/ui';
33
import {CoreApp, QueryEditorProps} from '@grafana/data';
44
import {DataSource} from '../datasource';
55
import {
6+
DEFAULT_LABEL_OPTION_FIELD_CONFIG,
67
getQueryVariablesAsJsonString,
78
LabelOption,
89
LabelOptionType,
9-
ParsingOption, TimeField,
10+
ParsingOption,
11+
TimeField,
1012
WildGraphQLAnyQuery,
1113
WildGraphQLDataSourceOptions
1214
} from '../types';
@@ -444,47 +446,101 @@ function InnerQueryEditor({ query, onChange, onRunQuery, datasource }: Props) {
444446
}
445447
</div>
446448
</>)}
447-
{parsingOption.labelOptions?.map((labelOption, labelOptionIndex) => <>
448-
<div className="gf-form-inline">
449-
<InlineField
450-
label={`Label: "${labelOption.name}"`}
451-
tooltip={`Specify how the custom label "${labelOption.name}" should be populated. A type of "Constant" means that you may put whatever text you would like as the label. A type of "Field" means that the given field will be used as the label's value.`}
452-
labelWidth={LABEL_WIDTH}
453-
>
454-
<Select
455-
width={16}
456-
options={[
457-
{label: "Constant", value: LabelOptionType.CONSTANT},
458-
{label: "Field", value: LabelOptionType.FIELD},
459-
]}
460-
value={labelOption.type}
461-
onChange={(value) => {
462-
const newType = value.value;
463-
if (newType !== undefined) {
449+
{parsingOption.labelOptions?.map((labelOption, labelOptionIndex) => {
450+
// fieldConfig and fieldConfigSelection are undefined ONLY when labelOption.type is CONSTANT
451+
const fieldConfig = labelOption.type === LabelOptionType.CONSTANT
452+
? undefined
453+
: (labelOption.fieldConfig ?? DEFAULT_LABEL_OPTION_FIELD_CONFIG);
454+
const fieldConfigSelection = fieldConfig === undefined
455+
? undefined
456+
: fieldConfig.required
457+
? "required"
458+
: fieldConfig.defaultValue === undefined ? "omit" : "default";
459+
return <>
460+
<div className="gf-form-inline">
461+
<InlineField
462+
label={`Label: "${labelOption.name}"`}
463+
tooltip={`Specify how the custom label "${labelOption.name}" should be populated. A type of "Constant" means that you may put whatever text you would like as the label. A type of "Field" means that the given field will be used as the label's value.`}
464+
labelWidth={LABEL_WIDTH}
465+
>
466+
<Select
467+
width={16}
468+
options={[
469+
{label: "Constant", value: LabelOptionType.CONSTANT},
470+
{label: "Field", value: LabelOptionType.FIELD},
471+
]}
472+
value={labelOption.type}
473+
onChange={(value) => {
474+
const newType = value.value;
475+
if (newType !== undefined) {
476+
setLabelOption(parsingOptionIndex, labelOptionIndex, {
477+
...labelOption,
478+
type: newType,
479+
});
480+
}
481+
}}
482+
/>
483+
484+
</InlineField>
485+
<InlineField label="Value" labelWidth={8}>
486+
<Input
487+
width={INPUT_WIDTH}
488+
value={labelOption.value}
489+
onChange={(event) => {
464490
setLabelOption(parsingOptionIndex, labelOptionIndex, {
465491
...labelOption,
466-
type: newType,
467-
});
468-
}
469-
}}
470-
/>
492+
value: event.currentTarget.value,
493+
})
494+
}}
495+
/>
496+
</InlineField>
471497

472-
</InlineField>
473-
<InlineField label="Value" labelWidth={8}>
474-
<Input
475-
width={INPUT_WIDTH}
476-
value={labelOption.value}
477-
onChange={(event) => {
478-
setLabelOption(parsingOptionIndex, labelOptionIndex, {
479-
...labelOption,
480-
value: event.currentTarget.value,
481-
})
482-
}}
483-
/>
484-
</InlineField>
485-
<IconButton name={"minus"} onClick={() => deleteLabelOption(parsingOptionIndex, labelOptionIndex)}/>
486-
</div>
487-
</>)}
498+
{fieldConfig &&
499+
<InlineField label="If absent" labelWidth={10}>
500+
<Select
501+
width={16}
502+
options={[
503+
{label: "Error", value: "required"},
504+
{label: "Omit", value: "omit"},
505+
{label: "Use default", value: "default"},
506+
]}
507+
value={fieldConfigSelection!}
508+
onChange={(value) => {
509+
const newValue = value.value;
510+
if (newValue !== undefined) {
511+
setLabelOption(parsingOptionIndex, labelOptionIndex, {
512+
...labelOption,
513+
fieldConfig: {
514+
required: newValue === "required",
515+
defaultValue: newValue === "omit" ? undefined : (fieldConfig!.defaultValue ?? "")
516+
}
517+
});
518+
}
519+
}}
520+
/>
521+
</InlineField>
522+
}
523+
{fieldConfigSelection === "default" &&
524+
<InlineField label="Default" labelWidth={10}>
525+
<Input
526+
width={INPUT_WIDTH}
527+
value={fieldConfig!.defaultValue!}
528+
onChange={(event) => {
529+
setLabelOption(parsingOptionIndex, labelOptionIndex, {
530+
...labelOption,
531+
fieldConfig: {
532+
required: false,
533+
defaultValue: event.currentTarget.value
534+
}
535+
})
536+
}}
537+
/>
538+
</InlineField>
539+
}
540+
<IconButton name={"minus"} onClick={() => deleteLabelOption(parsingOptionIndex, labelOptionIndex)}/>
541+
</div>
542+
</>;
543+
})}
488544
</>;
489545
})}
490546

src/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,20 @@ export interface LabelOption {
1414
/** When {@link type} is {@link LabelOptionType.CONSTANT}, this represents a text value that is constant.
1515
* When {@link type} is {@link LabelOptionType.FIELD}, this represents the path to a field relative to the data path */
1616
value: string;
17+
/** May be defined when {@link type} is {@link LabelOptionType.Field}. */
18+
fieldConfig?: LabelOptionFieldConfig;
1719
}
1820
export enum LabelOptionType {
1921
CONSTANT = "constant",
2022
FIELD = "field",
2123
}
24+
export interface LabelOptionFieldConfig {
25+
required: boolean;
26+
defaultValue?: string;
27+
}
28+
export const DEFAULT_LABEL_OPTION_FIELD_CONFIG: LabelOptionFieldConfig = { // omit is default
29+
required: false
30+
}
2231

2332
export interface ParsingOption {
2433
// TODO make sure an empty string is valid in the backend like this says

0 commit comments

Comments
 (0)