mirror of
https://github.com/grafana/grafana.git
synced 2026-01-15 05:35:41 +00:00
Compare commits
9 Commits
ash/react-
...
grafakus/q
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f584d143f | ||
|
|
e38240369b | ||
|
|
26ac64cf1a | ||
|
|
d8777012cb | ||
|
|
dfa07d8e10 | ||
|
|
dc63eb3314 | ||
|
|
1e3c6fed55 | ||
|
|
d02201f564 | ||
|
|
2a9377ac02 |
@@ -800,6 +800,8 @@ VariableOption: {
|
||||
text: string | [...string]
|
||||
// Value of the option
|
||||
value: string | [...string]
|
||||
// Additional properties for multi-props variables
|
||||
properties?: {[string]: string}
|
||||
}
|
||||
|
||||
// Query variable specification
|
||||
|
||||
@@ -804,6 +804,8 @@ VariableOption: {
|
||||
text: string | [...string]
|
||||
// Value of the option
|
||||
value: string | [...string]
|
||||
// Additional properties for multi-props variables
|
||||
properties?: {[string]: string}
|
||||
}
|
||||
|
||||
// Query variable specification
|
||||
|
||||
@@ -241,6 +241,8 @@ lineage: schemas: [{
|
||||
text: string | [...string]
|
||||
// Value of the option
|
||||
value: string | [...string]
|
||||
// Additional properties for multi-props variables
|
||||
properties?: {[string]: string}
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// Options to config when to refresh a variable
|
||||
|
||||
@@ -241,6 +241,8 @@ lineage: schemas: [{
|
||||
text: string | [...string]
|
||||
// Value of the option
|
||||
value: string | [...string]
|
||||
// Additional properties for multi-props variables
|
||||
properties?: {[string]: string}
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// Options to config when to refresh a variable
|
||||
|
||||
@@ -804,6 +804,8 @@ VariableOption: {
|
||||
text: string | [...string]
|
||||
// Value of the option
|
||||
value: string | [...string]
|
||||
// Additional properties for multi-props variables
|
||||
properties?: {[string]: string}
|
||||
}
|
||||
|
||||
// Query variable specification
|
||||
|
||||
@@ -1426,6 +1426,8 @@ type DashboardVariableOption struct {
|
||||
Text DashboardStringOrArrayOfString `json:"text"`
|
||||
// Value of the option
|
||||
Value DashboardStringOrArrayOfString `json:"value"`
|
||||
// Additional properties for multi-props variables
|
||||
Properties map[string]string `json:"properties,omitempty"`
|
||||
}
|
||||
|
||||
// NewDashboardVariableOption creates a new DashboardVariableOption object.
|
||||
|
||||
@@ -5133,6 +5133,22 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardVariableOption(ref common.Refer
|
||||
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardStringOrArrayOfString"),
|
||||
},
|
||||
},
|
||||
"properties": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Additional properties for multi-props variables",
|
||||
Type: []string{"object"},
|
||||
AdditionalProperties: &spec.SchemaOrBool{
|
||||
Allows: true,
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"text", "value"},
|
||||
},
|
||||
|
||||
@@ -808,6 +808,8 @@ VariableOption: {
|
||||
text: string | [...string]
|
||||
// Value of the option
|
||||
value: string | [...string]
|
||||
// Additional properties for multi-props variables
|
||||
properties?: {[string]: string}
|
||||
}
|
||||
|
||||
// Query variable specification
|
||||
|
||||
@@ -1429,6 +1429,8 @@ type DashboardVariableOption struct {
|
||||
Text DashboardStringOrArrayOfString `json:"text"`
|
||||
// Value of the option
|
||||
Value DashboardStringOrArrayOfString `json:"value"`
|
||||
// Additional properties for multi-props variables
|
||||
Properties map[string]string `json:"properties,omitempty"`
|
||||
}
|
||||
|
||||
// NewDashboardVariableOption creates a new DashboardVariableOption object.
|
||||
|
||||
@@ -5196,6 +5196,22 @@ func schema_pkg_apis_dashboard_v2beta1_DashboardVariableOption(ref common.Refere
|
||||
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1.DashboardStringOrArrayOfString"),
|
||||
},
|
||||
},
|
||||
"properties": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Additional properties for multi-props variables",
|
||||
Type: []string{"object"},
|
||||
AdditionalProperties: &spec.SchemaOrBool{
|
||||
Allows: true,
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"text", "value"},
|
||||
},
|
||||
|
||||
4
apps/dashboard/pkg/apis/dashboard_manifest.go
generated
4
apps/dashboard/pkg/apis/dashboard_manifest.go
generated
File diff suppressed because one or more lines are too long
@@ -237,6 +237,8 @@ lineage: schemas: [{
|
||||
text: string | [...string]
|
||||
// Value of the option
|
||||
value: string | [...string]
|
||||
// Additional properties for multi-props variables
|
||||
properties?: {[string]: string}
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// Options to config when to refresh a variable
|
||||
|
||||
@@ -91,6 +91,8 @@ export interface VariableOption {
|
||||
text: string | string[];
|
||||
value: string | string[];
|
||||
isNone?: boolean;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
properties?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface IntervalVariableModel extends VariableWithOptions {
|
||||
@@ -118,6 +120,7 @@ export interface QueryVariableModel extends VariableWithMultiSupport {
|
||||
definition: string;
|
||||
sort: VariableSort;
|
||||
queryValue?: string;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
query: any;
|
||||
regex: string;
|
||||
regexApplyTo?: VariableRegexApplyTo;
|
||||
@@ -193,6 +196,7 @@ export interface BaseVariableModel {
|
||||
skipUrlSync: boolean;
|
||||
index: number;
|
||||
state: LoadingState;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
error: any | null;
|
||||
description: string | null;
|
||||
usedInRepeat?: boolean;
|
||||
|
||||
@@ -231,6 +231,10 @@ export const defaultVariableModel: Partial<VariableModel> = {
|
||||
* Option to be selected in a variable.
|
||||
*/
|
||||
export interface VariableOption {
|
||||
/**
|
||||
* Additional properties for multi-props variables
|
||||
*/
|
||||
properties?: Record<string, string>;
|
||||
/**
|
||||
* Whether the option is selected or not
|
||||
*/
|
||||
|
||||
@@ -715,7 +715,9 @@ VariableOption: {
|
||||
// Text to be displayed for the option
|
||||
text: string | [...string]
|
||||
// Value of the option
|
||||
value: string | [...string]
|
||||
value: string | [...string]
|
||||
// Additional properties for multi-props variables
|
||||
properties?: {[string]: string}
|
||||
}
|
||||
|
||||
// Query variable specification
|
||||
|
||||
2
pkg/kinds/dashboard/dashboard_spec_gen.go
generated
2
pkg/kinds/dashboard/dashboard_spec_gen.go
generated
@@ -903,6 +903,8 @@ type VariableOption struct {
|
||||
Text StringOrArrayOfString `json:"text"`
|
||||
// Value of the option
|
||||
Value StringOrArrayOfString `json:"value"`
|
||||
// Additional properties for multi-props variables
|
||||
Properties map[string]string `json:"properties,omitempty"`
|
||||
}
|
||||
|
||||
// NewVariableOption creates a new VariableOption object.
|
||||
|
||||
@@ -3912,6 +3912,13 @@
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"properties": {
|
||||
"description": "Additional properties for multi-props variables",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"selected": {
|
||||
"description": "Whether the option is selected or not",
|
||||
"type": "boolean"
|
||||
|
||||
@@ -3939,6 +3939,13 @@
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"properties": {
|
||||
"description": "Additional properties for multi-props variables",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"selected": {
|
||||
"description": "Whether the option is selected or not",
|
||||
"type": "boolean"
|
||||
|
||||
@@ -284,6 +284,7 @@ function variableValueOptionsToVariableOptions(varState: MultiValueVariable['sta
|
||||
value: String(o.value),
|
||||
text: o.label,
|
||||
selected: Array.isArray(varState.value) ? varState.value.includes(o.value) : varState.value === o.value,
|
||||
...(o.properties && { properties: o.properties }),
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,6 @@ export function VariableEditorForm({ variable, onTypeChange, onGoBack, onDelete
|
||||
|
||||
const isHasVariableOptions = hasVariableOptions(variable);
|
||||
const optionsForSelect = isHasVariableOptions ? variable.getOptionsForSelect(false) : [];
|
||||
const hasMultiProps = 'valuesFormat' in variable.state && variable.state.valuesFormat === 'json';
|
||||
|
||||
const onDeleteVariable = (hideModal: () => void) => () => {
|
||||
reportInteraction('Delete variable');
|
||||
@@ -125,7 +124,7 @@ export function VariableEditorForm({ variable, onTypeChange, onGoBack, onDelete
|
||||
|
||||
{EditorToRender && <EditorToRender variable={variable} onRunQuery={onRunQuery} />}
|
||||
|
||||
{isHasVariableOptions && <VariableValuesPreview options={optionsForSelect} hasMultiProps={hasMultiProps} />}
|
||||
{isHasVariableOptions && <VariableValuesPreview options={optionsForSelect} />}
|
||||
|
||||
<div className={styles.buttonContainer}>
|
||||
<Stack gap={2}>
|
||||
|
||||
@@ -10,13 +10,16 @@ import { Button, InlineFieldRow, InlineLabel, InteractiveTable, Text, useStyles2
|
||||
|
||||
export interface Props {
|
||||
options: VariableValueOption[];
|
||||
hasMultiProps?: boolean;
|
||||
}
|
||||
|
||||
export const VariableValuesPreview = ({ options, hasMultiProps }: Props) => {
|
||||
const hasMultiProps = (options: Props['options']) => {
|
||||
return Object.keys(options[1]?.properties ?? options[0]?.properties ?? {}).length > 0;
|
||||
};
|
||||
|
||||
export const VariableValuesPreview = ({ options }: Props) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
const hasOptions = options.length > 0;
|
||||
const displayMultiPropsPreview = config.featureToggles.multiPropsVariables && hasMultiProps;
|
||||
const displayMultiPropsPreview = config.featureToggles.multiPropsVariables && hasOptions && hasMultiProps(options);
|
||||
|
||||
return (
|
||||
<div className={styles.previewContainer} style={{ gap: '8px' }}>
|
||||
@@ -43,7 +46,8 @@ function VariableValuesWithPropsPreview({ options }: { options: VariableValueOpt
|
||||
|
||||
return {
|
||||
data,
|
||||
columns: Object.keys(data[0] ?? {}).map((id) => ({
|
||||
// the option at index 0 can be "All" so we try to grab the column names from the 2nd option
|
||||
columns: Object.keys(data[1] ?? data[0] ?? {}).map((id) => ({
|
||||
id,
|
||||
// see https://github.com/TanStack/table/issues/1671
|
||||
header: unsanitizeKey(id),
|
||||
@@ -62,7 +66,6 @@ function VariableValuesWithPropsPreview({ options }: { options: VariableValueOpt
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const sanitizeKey = (key: string) => key.replace(/\./g, '__dot__');
|
||||
const unsanitizeKey = (key: string) => key.replace(/__dot__/g, '.');
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ function ModalEditorMultiProps(props: ModalEditorProps) {
|
||||
{queryValidationError && <FieldValidationMessage>{queryValidationError.message}</FieldValidationMessage>}
|
||||
</div>
|
||||
<div>
|
||||
<VariableValuesPreview options={options} hasMultiProps={valuesFormat === 'json'} />
|
||||
<VariableValuesPreview options={options} />
|
||||
</div>
|
||||
</Stack>
|
||||
<Modal.ButtonRow>
|
||||
|
||||
@@ -81,16 +81,17 @@ const buildLabelPath = (label: string) => {
|
||||
};
|
||||
|
||||
const getVariableValueProperties = (variable: TypedVariableModel): string[] => {
|
||||
if (!('valuesFormat' in variable) || variable.valuesFormat !== 'json') {
|
||||
if (!('options' in variable) || !variable.options[0].properties) {
|
||||
return [];
|
||||
}
|
||||
|
||||
function collectFieldPaths(option: Record<string, string>, currentPath: string) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function collectFieldPaths(properties: Record<string, any>, currentPath: string) {
|
||||
let paths: string[] = [];
|
||||
for (const field in option) {
|
||||
if (option.hasOwnProperty(field)) {
|
||||
for (const field in properties) {
|
||||
if (properties.hasOwnProperty(field)) {
|
||||
const newPath = `${currentPath}.${field}`;
|
||||
const value = option[field];
|
||||
const value = properties[field];
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
paths = [...paths, ...collectFieldPaths(value, newPath)];
|
||||
}
|
||||
@@ -100,11 +101,7 @@ const getVariableValueProperties = (variable: TypedVariableModel): string[] => {
|
||||
return paths;
|
||||
}
|
||||
|
||||
try {
|
||||
return collectFieldPaths(JSON.parse(variable.query)[0], variable.name);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
return collectFieldPaths(variable.options[0].properties, variable.name);
|
||||
};
|
||||
|
||||
export const getPanelLinksVariableSuggestions = (): VariableSuggestion[] => [
|
||||
|
||||
@@ -503,13 +503,16 @@ describe('linkSrv', () => {
|
||||
});
|
||||
|
||||
describe('getPanelLinksVariableSuggestions', () => {
|
||||
it('then it should return template variables, json properties and built-ins', () => {
|
||||
it('then it should return template variables, options properties and built-ins', () => {
|
||||
const templateSrvWithJsonValues = initTemplateSrv('key', [
|
||||
{
|
||||
type: 'custom',
|
||||
name: 'customServers',
|
||||
valuesFormat: 'json',
|
||||
query: '[{"name":"web","ip":"192.168.0.100"},{"name":"ads","ip":"192.168.0.142"}]',
|
||||
options: [
|
||||
{ text: 'web', value: 'web', properties: { name: 'web', ip: '192.168.0.100' } },
|
||||
{ text: 'ads', value: 'ads', properties: { name: 'ads', ip: '192.168.0.142' } },
|
||||
],
|
||||
},
|
||||
]);
|
||||
setTemplateSrv(templateSrvWithJsonValues);
|
||||
|
||||
Reference in New Issue
Block a user