Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/ConfigEditor/ResourceSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import { selectors } from '../selectors';
import { isEqual } from 'lodash';
import { defaultKey } from 'types';

export type QueryResourceType = 'ManagedSecret';
export type QueryResourceType = 'ManagedSecret' | 'schema' | 'table' | 'column';

type Props = {
resource: QueryResourceType;
value: string | null;
fetch: () => Promise<Array<string | SelectableValue<string>>>;
onChange: (e: SelectableValue<string> | null) => void;
dependencies?: Array<string | null>;
dependencies?: Array<string | null | undefined>;
tooltip?: string;
// Options only needed for QueryEditor
default?: string;
Expand Down
71 changes: 0 additions & 71 deletions src/QueryCodeEditor.test.tsx

This file was deleted.

74 changes: 10 additions & 64 deletions src/QueryCodeEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,13 @@ import React from 'react';
import { QueryEditorProps } from '@grafana/data';
import { DataSource } from './datasource';
import { defaultQuery, RedshiftDataSourceOptions, RedshiftQuery } from './types';
import { CodeEditor, InlineFormLabel } from '@grafana/ui';
import { CodeEditor } from '@grafana/ui';
import { getTemplateSrv } from '@grafana/runtime';
import ResourceMacro from 'ResourceMacro';
import { getSuggestions } from 'Suggestions';

type Props = QueryEditorProps<DataSource, RedshiftQuery, RedshiftDataSourceOptions>;

export function QueryCodeEditor(props: Props) {
const onChange = (value: RedshiftQuery) => {
props.onChange(value);
props.onRunQuery();
};

const onRawSqlChange = (rawSQL: string) => {
props.onChange({
...props.query,
Expand All @@ -27,63 +21,15 @@ export function QueryCodeEditor(props: Props) {

const { rawSQL } = defaults(props.query, defaultQuery);

const loadSchemas = async () => {
const schemas: string[] = await props.datasource.getResource('schemas');
return schemas.map((schema) => ({ label: schema, value: schema })).concat({ label: '-- remove --', value: '' });
};

const loadTables = async () => {
const tables: string[] = await props.datasource.postResource('tables', {
schema: props.query.schema || '',
});
return tables.map((table) => ({ label: table, value: table })).concat({ label: '-- remove --', value: '' });
};

const loadColumns = async () => {
const columns: string[] = await props.datasource.postResource('columns', {
table: props.query.table,
});
return columns.map((column) => ({ label: column, value: column })).concat({ label: '-- remove --', value: '' });
};

return (
<>
<div className={'gf-form-inline'}>
<InlineFormLabel width={8} className="query-keyword">
Macros
</InlineFormLabel>
{ResourceMacro({
resource: 'schema',
query: props.query,
loadOptions: loadSchemas,
updateQuery: onChange,
})}
{ResourceMacro({
resource: 'table',
query: props.query,
loadOptions: loadTables,
updateQuery: onChange,
})}
{ResourceMacro({
resource: 'column',
query: props.query,
loadOptions: loadColumns,
updateQuery: onChange,
})}
<div className="gf-form gf-form--grow">
<div className="gf-form-label gf-form-label--grow" />
</div>
</div>
<CodeEditor
height={'250px'}
language={'redshift'}
value={rawSQL}
onBlur={onRawSqlChange}
// removed onSave due to bug: https://github.com/grafana/grafana/issues/39264
showMiniMap={false}
showLineNumbers={true}
getSuggestions={() => getSuggestions({ query: props.query, templateSrv: getTemplateSrv() })}
/>
</>
<CodeEditor
height={'231px'}
language={'redshift'}
value={rawSQL}
onBlur={onRawSqlChange}
showMiniMap={false}
showLineNumbers={true}
getSuggestions={() => getSuggestions({ query: props.query, templateSrv: getTemplateSrv() })}
/>
);
}
75 changes: 68 additions & 7 deletions src/QueryEditor.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ import { FillValueOptions } from 'types';

const ds = mockDatasource;
const q = mockQuery;
ds.getResource = jest.fn().mockResolvedValue([]);
ds.postResource = jest.fn().mockResolvedValue([]);

beforeEach(() => {
ds.getResource = jest.fn().mockResolvedValue([]);
ds.postResource = jest.fn().mockResolvedValue([]);
});

const props = {
datasource: ds,
Expand All @@ -19,11 +22,69 @@ const props = {
};

describe('QueryEditor', () => {
it('should render Macros input', async () => {
render(<QueryEditor {...props} />);
await waitFor(() => screen.getByText('$__schema = public'));
expect(screen.getByText('$__table = ?')).toBeInTheDocument();
expect(screen.getByText('$__column = ?')).toBeInTheDocument();
it('should request select schemas and execute the query', async () => {
const onChange = jest.fn();
const onRunQuery = jest.fn();
ds.getResource = jest.fn().mockResolvedValue(['foo']);
render(
<QueryEditor {...props} onChange={onChange} onRunQuery={onRunQuery} query={{ ...props.query, schema: 'bar' }} />
);

const selectEl = screen.getByLabelText('Schema');
expect(selectEl).toBeInTheDocument();

await select(selectEl, 'foo', { container: document.body });

expect(ds.getResource).toHaveBeenCalledWith('schemas');
expect(onChange).toHaveBeenCalledWith({
...q,
schema: 'foo',
});
expect(onRunQuery).toHaveBeenCalled();
});

it('should request select tables and execute the query', async () => {
const onChange = jest.fn();
const onRunQuery = jest.fn();
ds.postResource = jest.fn().mockResolvedValue(['foo']);
render(
<QueryEditor {...props} onChange={onChange} onRunQuery={onRunQuery} query={{ ...props.query, schema: 'bar' }} />
);

const selectEl = screen.getByLabelText('Table');
expect(selectEl).toBeInTheDocument();

await select(selectEl, 'foo', { container: document.body });

expect(ds.postResource).toHaveBeenCalledWith('tables', { schema: 'bar' });
expect(onChange).toHaveBeenCalledWith({
...q,
schema: 'bar',
table: 'foo',
});
expect(onRunQuery).toHaveBeenCalled();
});

it('should request select column and execute the query', async () => {
const onChange = jest.fn();
const onRunQuery = jest.fn();
ds.postResource = jest.fn().mockResolvedValue(['foo']);
render(
<QueryEditor {...props} onChange={onChange} onRunQuery={onRunQuery} query={{ ...props.query, table: 'bar' }} />
);

const selectEl = screen.getByLabelText('Column');
expect(selectEl).toBeInTheDocument();

await select(selectEl, 'foo', { container: document.body });

expect(ds.postResource).toHaveBeenCalledWith('columns', { table: 'bar' });
expect(onChange).toHaveBeenCalledWith({
...q,
table: 'bar',
column: 'foo',
});
expect(onRunQuery).toHaveBeenCalled();
});

it('should include the Format As input', async () => {
Expand Down
Loading