Skip to content

Commit 40a347c

Browse files
committed
feat: add helper documentation and some bugfixes
1 parent 4e02aaa commit 40a347c

File tree

9 files changed

+184
-127
lines changed

9 files changed

+184
-127
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Changelog
22

3-
## 0.0.3 (Unreleased)
3+
## 0.0.5 (Unreleased)
44

55
Initial release.

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ require (
3131
github.com/hashicorp/go-hclog v0.14.1 // indirect
3232
github.com/hashicorp/go-plugin v1.4.3 // indirect
3333
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect
34+
github.com/jmoiron/sqlx v1.3.5 // indirect
3435
github.com/josharian/intern v1.0.0 // indirect
3536
github.com/json-iterator/go v1.1.12 // indirect
3637
github.com/klauspost/compress v1.13.1 // indirect
@@ -40,6 +41,7 @@ require (
4041
github.com/mattn/go-colorable v0.1.4 // indirect
4142
github.com/mattn/go-isatty v0.0.10 // indirect
4243
github.com/mattn/go-runewidth v0.0.9 // indirect
44+
github.com/mattn/go-sqlite3 v1.14.16 // indirect
4345
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
4446
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
4547
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect

go.sum

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34
112112
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
113113
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
114114
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
115+
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
115116
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
116117
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
117118
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -199,6 +200,8 @@ github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKe
199200
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
200201
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
201202
github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
203+
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
204+
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
202205
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
203206
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
204207
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
@@ -225,6 +228,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
225228
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
226229
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
227230
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
231+
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
228232
github.com/magefile/mage v1.13.0 h1:XtLJl8bcCM7EFoO8FyH8XK3t7G5hQAeK+i4tq+veT9M=
229233
github.com/magefile/mage v1.13.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
230234
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -241,6 +245,9 @@ github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW1
241245
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
242246
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
243247
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
248+
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
249+
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
250+
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
244251
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
245252
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
246253
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "climeworks-databricks",
3-
"version": "0.0.4",
3+
"version": "0.0.5",
44
"description": "Databricks SQL Connector",
55
"scripts": {
66
"build": "grafana-toolkit plugin:build",

pkg/plugin/plugin.go

Lines changed: 101 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import (
1111
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
1212
"github.com/grafana/grafana-plugin-sdk-go/data"
1313
"github.com/grafana/grafana-plugin-sdk-go/live"
14+
"math"
1415
"regexp"
16+
"strings"
1517
"time"
1618
)
1719

@@ -93,12 +95,107 @@ type queryModel struct {
9395
RawSqlSelected bool `json:"rawSqlSelected"`
9496
}
9597

98+
func getIntervalString(duration time.Duration) string {
99+
hours := int(math.Floor(duration.Hours()))
100+
minutes := int(math.Floor(duration.Minutes()))
101+
seconds := int(math.Floor(duration.Seconds()))
102+
103+
returnString := ""
104+
105+
deliminator := ""
106+
if hours > 0 {
107+
returnString = fmt.Sprintf("%s%s%d HOURS", returnString, deliminator, hours)
108+
deliminator = " "
109+
}
110+
111+
remainingMinutes := minutes - (hours * 60)
112+
if remainingMinutes > 0 {
113+
returnString = fmt.Sprintf("%s%s%d MINUTES", returnString, deliminator, remainingMinutes)
114+
deliminator = " "
115+
}
116+
117+
remainingSeconds := seconds - (minutes * 60)
118+
if remainingSeconds > 0 {
119+
returnString = fmt.Sprintf("%s%s%d SECONDS", returnString, deliminator, remainingSeconds)
120+
deliminator = " "
121+
}
122+
123+
return returnString
124+
}
125+
126+
func replaceMacros(sqlQuery string, query backend.DataQuery) string {
127+
128+
queryString := sqlQuery
129+
log.DefaultLogger.Info("Raw SQL Query selected", "query", queryString)
130+
131+
interval_string := getIntervalString(query.Interval)
132+
133+
var rgx = regexp.MustCompile(`\$__timeWindow\(([a-zA-Z0-9_-]+)\)`)
134+
if rgx.MatchString(queryString) {
135+
log.DefaultLogger.Info("__timeWindow placeholder found")
136+
rs := rgx.FindStringSubmatch(queryString)
137+
timeColumnName := rs[1]
138+
queryString = rgx.ReplaceAllString(queryString, fmt.Sprintf("window(%s, '%s')", timeColumnName, interval_string))
139+
140+
rgx = regexp.MustCompile(`\$__time\(([a-zA-Z0-9_-]+)\)`)
141+
if rgx.MatchString(queryString) {
142+
log.DefaultLogger.Info("__time placeholder found")
143+
queryString = rgx.ReplaceAllString(queryString, "window.start")
144+
}
145+
146+
rgx = regexp.MustCompile(`\$__value\(([a-zA-Z0-9_-]+)\)`)
147+
if rgx.MatchString(queryString) {
148+
log.DefaultLogger.Info("__value placeholder found")
149+
rs = rgx.FindStringSubmatch(queryString)
150+
valueColumnName := rs[1]
151+
queryString = rgx.ReplaceAllString(queryString, fmt.Sprintf("avg(%s) AS value", valueColumnName))
152+
}
153+
} else {
154+
rgx = regexp.MustCompile(`\$__time\(([a-zA-Z0-9_-]+)\)`)
155+
if rgx.MatchString(queryString) {
156+
log.DefaultLogger.Info("__time placeholder found")
157+
rs := rgx.FindStringSubmatch(queryString)
158+
timeColumnName := rs[1]
159+
queryString = rgx.ReplaceAllString(queryString, fmt.Sprintf("%s AS time", timeColumnName))
160+
}
161+
162+
rgx = regexp.MustCompile(`\$__value\(([a-zA-Z0-9_-]+)\)`)
163+
if rgx.MatchString(queryString) {
164+
log.DefaultLogger.Info("__value placeholder found")
165+
rs := rgx.FindStringSubmatch(queryString)
166+
valueColumnName := rs[1]
167+
queryString = rgx.ReplaceAllString(queryString, fmt.Sprintf("%s AS value", valueColumnName))
168+
}
169+
}
170+
171+
rgx = regexp.MustCompile(`\$__timeFilter\(([a-zA-Z0-9_-]+)\)`)
172+
if rgx.MatchString(queryString) {
173+
rs := rgx.FindStringSubmatch(queryString)
174+
timeColumnName := rs[1]
175+
timeRangeFilter := fmt.Sprintf("%s BETWEEN '%s' AND '%s'",
176+
timeColumnName,
177+
query.TimeRange.From.UTC().Format("2006-01-02 15:04:05"),
178+
query.TimeRange.To.UTC().Format("2006-01-02 15:04:05"),
179+
)
180+
queryString = rgx.ReplaceAllString(queryString, timeRangeFilter)
181+
}
182+
183+
queryString = strings.ReplaceAll(queryString, "$__timeFrom", query.TimeRange.From.UTC().Format("2006-01-02 15:04:05"))
184+
185+
queryString = strings.ReplaceAll(queryString, "$__timeTo", query.TimeRange.To.UTC().Format("2006-01-02 15:04:05"))
186+
187+
queryString = strings.ReplaceAll(queryString, "$__interval", interval_string)
188+
189+
return queryString
190+
}
191+
96192
func (d *SampleDatasource) query(_ context.Context, pCtx backend.PluginContext, query backend.DataQuery) backend.DataResponse {
97193
response := backend.DataResponse{}
98194

99195
// Unmarshal the JSON into our queryModel.
100196
var qm queryModel
101197

198+
log.DefaultLogger.Info("Query Ful", "query", query)
102199
err := json.Unmarshal(query.JSON, &qm)
103200
if err != nil {
104201
response.Error = err
@@ -111,75 +208,24 @@ func (d *SampleDatasource) query(_ context.Context, pCtx backend.PluginContext,
111208
if seconds_interval <= 0 {
112209
seconds_interval = 1
113210
}
211+
interval_string := getIntervalString(query.Interval)
114212
queryString := ""
115213
if qm.RawSqlSelected {
116-
queryString = qm.RawSqlQuery
117-
log.DefaultLogger.Info("Raw SQL Query selected", "query", queryString)
118-
119-
var rgx = regexp.MustCompile(`\$__timeWindow\(([a-zA-Z0-9_-]+)\)`)
120-
if rgx.MatchString(queryString) {
121-
log.DefaultLogger.Info("__timeWindow placeholder found")
122-
rs := rgx.FindStringSubmatch(queryString)
123-
timeColumnName := rs[1]
124-
queryString = rgx.ReplaceAllString(queryString, fmt.Sprintf("window(%s, '%d SECONDS')", timeColumnName, seconds_interval))
125-
126-
rgx = regexp.MustCompile(`\$__time\(([a-zA-Z0-9_-]+)\)`)
127-
if rgx.MatchString(queryString) {
128-
log.DefaultLogger.Info("__time placeholder found")
129-
queryString = rgx.ReplaceAllString(queryString, "window.start")
130-
}
131-
132-
rgx = regexp.MustCompile(`\$__value\(([a-zA-Z0-9_-]+)\)`)
133-
if rgx.MatchString(queryString) {
134-
log.DefaultLogger.Info("__value placeholder found")
135-
rs = rgx.FindStringSubmatch(queryString)
136-
valueColumnName := rs[1]
137-
queryString = rgx.ReplaceAllString(queryString, fmt.Sprintf("avg(%s) AS value", valueColumnName))
138-
}
139-
} else {
140-
rgx = regexp.MustCompile(`\$__time\(([a-zA-Z0-9_-]+)\)`)
141-
if rgx.MatchString(queryString) {
142-
log.DefaultLogger.Info("__time placeholder found")
143-
rs := rgx.FindStringSubmatch(queryString)
144-
timeColumnName := rs[1]
145-
queryString = rgx.ReplaceAllString(queryString, fmt.Sprintf("%s AS time", timeColumnName))
146-
}
147-
148-
rgx = regexp.MustCompile(`\$__value\(([a-zA-Z0-9_-]+)\)`)
149-
if rgx.MatchString(queryString) {
150-
log.DefaultLogger.Info("__value placeholder found")
151-
rs := rgx.FindStringSubmatch(queryString)
152-
valueColumnName := rs[1]
153-
queryString = rgx.ReplaceAllString(queryString, fmt.Sprintf("%s AS value", valueColumnName))
154-
}
155-
}
156-
157-
rgx = regexp.MustCompile(`\$__timeFilter\(([a-zA-Z0-9_-]+)\)`)
158-
if rgx.MatchString(queryString) {
159-
rs := rgx.FindStringSubmatch(queryString)
160-
timeColumnName := rs[1]
161-
timeRangeFilter := fmt.Sprintf("%s BETWEEN '%s' AND '%s'",
162-
timeColumnName,
163-
query.TimeRange.From.UTC().Format("2006-01-02 15:04:05"),
164-
query.TimeRange.To.UTC().Format("2006-01-02 15:04:05"),
165-
)
166-
queryString = rgx.ReplaceAllString(queryString, timeRangeFilter)
167-
}
168-
214+
queryString = replaceMacros(qm.RawSqlQuery, query)
169215
} else {
170216
whereQuery := ""
171217
if qm.WhereQuery != "" {
172218
whereQuery = fmt.Sprintf(" %s AND", qm.WhereQuery)
173219
}
174-
queryString = fmt.Sprintf("SELECT window.start, avg(%s) AS value FROM %s WHERE%s %s BETWEEN '%s' AND '%s' GROUP BY window(%s, '%d SECONDS')",
220+
queryString = fmt.Sprintf("SELECT window.start, avg(%s) AS value FROM %s WHERE%s %s BETWEEN '%s' AND '%s' GROUP BY window(%s, '%s')",
175221
qm.ValueColumnName,
176222
qm.TableName,
177223
whereQuery,
178224
qm.TimeColumnName,
179225
query.TimeRange.From.UTC().Format("2006-01-02 15:04:05"),
180226
query.TimeRange.To.UTC().Format("2006-01-02 15:04:05"),
181227
qm.TimeColumnName,
182-
seconds_interval)
228+
interval_string)
183229
}
184230
log.DefaultLogger.Info("Query", "query", queryString)
185231

src/QueryEditor.tsx

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
11
import { defaults } from 'lodash';
22

3-
import React, {FormEvent, useState} from 'react';
4-
import { AutoSizeInput, InlineFieldRow, InlineField, useTheme, InlineSwitch } from '@grafana/ui';
3+
import React, {FormEvent } from 'react';
4+
import { AutoSizeInput, InlineFieldRow, InlineField, InlineSwitch, CodeEditor } from '@grafana/ui';
55
import { QueryEditorProps } from '@grafana/data';
66
import { DataSource } from './datasource';
7-
import Editor from "@monaco-editor/react";
87
import { defaultQuery, MyDataSourceOptions, MyQuery } from './types';
9-
import * as monaco from "monaco-editor";
108

119
type Props = QueryEditorProps<DataSource, MyQuery, MyDataSourceOptions>;
1210

1311
export function QueryEditor(props: Props) {
1412

15-
const [, setQueryText] = useState("")
16-
const [sqlEditorSelected, setSqlEditorSelected] = useState(false)
17-
const onQuerryChange = (value: string | undefined, ev: monaco.editor.IModelContentChangedEvent) => {
18-
setQueryText(value || "")
13+
const query = defaults(props.query, defaultQuery);
14+
const { timeColumnName, valueColumnName, whereQuery, tableName, rawSqlQuery, rawSqlSelected } = query;
15+
16+
const onSQLQueryChange = (value: string) => {
1917
const { onChange, query } = props;
2018
onChange({ ...query, rawSqlQuery: value });
2119
};
2220

2321
const onSQLSwitchChange = (event: any) => {
2422
const { onChange, query } = props;
25-
onChange({ ...query, rawSqlSelected: !sqlEditorSelected });
26-
setSqlEditorSelected(!sqlEditorSelected);
23+
onChange({ ...query, rawSqlSelected: !rawSqlSelected });
2724
};
2825
const ontableNameChange = (event: FormEvent<HTMLInputElement>) => {
2926
console.log(event);
@@ -52,19 +49,22 @@ export function QueryEditor(props: Props) {
5249
onChange({ ...query, whereQuery: event.currentTarget.value });
5350
};
5451

55-
const query = defaults(props.query, defaultQuery);
56-
const { timeColumnName, valueColumnName, whereQuery, tableName } = query;
57-
const theme = useTheme()
52+
5853
return (
5954
<div className="gf-form" style={{ flexDirection: "column", rowGap: "8px"}}>
60-
{sqlEditorSelected ? (
61-
<Editor
55+
{rawSqlSelected ? (
56+
<div className="code-wrapper" style={{ width: "100%" }}>
57+
<CodeEditor
58+
value={rawSqlQuery || ""}
59+
language="sql"
6260
height="200px"
63-
theme={theme.isDark ? "vs-dark" : "vs-light"}
64-
defaultLanguage="sql"
65-
defaultValue="SELECT $__time(time_column), $__value(value_column) FROM catalog.default.table_name WHERE $__timeFilter(time_column) GROUP BY $__timeWindow(time_column)"
66-
onChange={onQuerryChange}
67-
/>
61+
width="100%"
62+
onBlur={onSQLQueryChange}
63+
onSave={onSQLQueryChange}
64+
showMiniMap={false}
65+
showLineNumbers={false}
66+
/>
67+
</div>
6868
) : (
6969
<>
7070
<InlineFieldRow>
@@ -115,7 +115,7 @@ export function QueryEditor(props: Props) {
115115
<InlineFieldRow>
116116
<InlineField label="SQL Editor" labelWidth={16}>
117117
<InlineSwitch
118-
value={sqlEditorSelected}
118+
value={rawSqlSelected}
119119
onChange={onSQLSwitchChange}
120120
/>
121121
</InlineField>

src/QueryEditorHelp.tsx

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react';
2+
import { QueryEditorHelpProps} from '@grafana/data';
3+
import { MyQuery } from './types';
4+
5+
const examples = [
6+
{
7+
title: 'Time Range & Windowing',
8+
expression: "SELECT $__time(time_column), avg(value_column) FROM catalog.default.table_name WHERE $__timeFilter(time_column) GROUP BY $__timeWindow(time_column)",
9+
label: 'Inserts Time range filters and window aggregation into the query. The resulting query with macros replaced would look like this:',
10+
resultingQuery: "SELECT window.start, avg(value_column) FROM catalog.default.table_name WHERE time_column BETWEEN '2021-12-31 23:00:00' AND '2022-01-01 22:59:59' GROUP BY window(time_column, '2 HOURS')",
11+
rawSqlQuery: "SELECT $__time(time_column), avg(value_column) FROM catalog.default.table_name WHERE $__timeFilter(time_column) GROUP BY $__timeWindow(time_column)",
12+
rawSqlSelected: true,
13+
},
14+
{
15+
title: 'Time From/To',
16+
expression: 'SELECT time_column, value_column FROM catalog.default.table_name WHERE time_column BETWEEN $__timeFrom AND $__timeTo',
17+
label: 'Insert Time range filters from and to time values.',
18+
rawSqlQuery: "SELECT time_column, value_column FROM catalog.default.table_name WHERE time_column BETWEEN $__timeFrom AND $__timeTo",
19+
resultingQuery: "SELECT time_column, value_column FROM catalog.default.table_name WHERE time_column BETWEEN '2021-12-31 23:00:00' AND '2022-01-01 22:59:59'",
20+
rawSqlSelected: true,
21+
},
22+
];
23+
24+
25+
type Props = QueryEditorHelpProps<MyQuery>;
26+
export function QueryEditorHelp(props: Props) {
27+
return (
28+
<div>
29+
<h2>SQL Query Documentation</h2>
30+
<h3>Macros</h3>
31+
{examples.map((item, index) => (
32+
<div className="cheat-sheet-item" key={index}>
33+
<div className="cheat-sheet-item__title">{item.title}</div>
34+
{item.expression ? (
35+
<div
36+
className="cheat-sheet-item__example"
37+
onClick={(e) => props.onClickExample({ rawSqlQuery: item.rawSqlQuery, rawSqlSelected: item.rawSqlSelected } as MyQuery)}
38+
>
39+
<code>{item.expression}</code>
40+
</div>
41+
) : null}
42+
<div className="cheat-sheet-item__label" style={{margin: "16px 0 8px 0"}}>{item.label}</div>
43+
{item.resultingQuery && (<code>{item.resultingQuery}</code>)}
44+
</div>
45+
))}
46+
</div>
47+
);
48+
};

0 commit comments

Comments
 (0)