From 1708f78ff6d97f37578fd1cff9a51ae8d9172412 Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Fri, 13 Jan 2023 21:31:20 +0100 Subject: [PATCH 1/2] Add default editor option in Prometheus configuration --- .betterer.results | 3 +- .../prometheus/configuration/PromSettings.tsx | 26 +++++++- .../datasource/prometheus/datasource.tsx | 3 + .../PromQueryEditorSelector.test.tsx | 63 +++++++++++++++++-- .../components/PromQueryEditorSelector.tsx | 10 ++- .../prometheus/querybuilder/state.test.ts | 10 +++ .../prometheus/querybuilder/state.ts | 12 ++-- .../plugins/datasource/prometheus/types.ts | 2 + 8 files changed, 114 insertions(+), 15 deletions(-) diff --git a/.betterer.results b/.betterer.results index c16b06a4d699..386655fb6726 100644 --- a/.betterer.results +++ b/.betterer.results @@ -6356,8 +6356,7 @@ exports[`better eslint`] = { ], "public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.test.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], - [0, 0, 0, "Unexpected any. Specify a different type.", "1"], - [0, 0, 0, "Unexpected any. Specify a different type.", "2"] + [0, 0, 0, "Unexpected any. Specify a different type.", "1"] ], "public/app/plugins/datasource/prometheus/querybuilder/shared/LabelFilterItem.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], diff --git a/public/app/plugins/datasource/prometheus/configuration/PromSettings.tsx b/public/app/plugins/datasource/prometheus/configuration/PromSettings.tsx index 386639bab093..a5b9d4eee68f 100644 --- a/public/app/plugins/datasource/prometheus/configuration/PromSettings.tsx +++ b/public/app/plugins/datasource/prometheus/configuration/PromSettings.tsx @@ -21,6 +21,7 @@ import { import { useUpdateDatasource } from '../../../../features/datasources/state'; import { PromApplication, PromBuildInfoResponse } from '../../../../types/unified-alerting-dto'; +import { QueryEditorMode } from '../querybuilder/shared/types'; import { PromOptions } from '../types'; import { ExemplarsSettings } from './ExemplarsSettings'; @@ -33,6 +34,11 @@ const httpOptions = [ { value: 'GET', label: 'GET' }, ]; +const editorOptions = [ + { value: QueryEditorMode.Builder, label: 'Builder' }, + { value: QueryEditorMode.Code, label: 'Code' }, +]; + type PrometheusSelectItemsType = Array<{ value: PromApplication; label: PromApplication }>; const prometheusFlavorSelectItems: PrometheusSelectItemsType = [ @@ -136,7 +142,8 @@ export const PromSettings = (props: Props) => { // This update call is typed as void, but it returns a response which we need const onUpdate = useUpdateDatasource(); - // We are explicitly adding httpMethod so it is correctly displayed in dropdown. This way, it is more predictable for users. + // We are explicitly adding httpMethod so, it is correctly displayed in dropdown. This way, it is more predictable + // for users. if (!options.jsonData.httpMethod) { options.jsonData.httpMethod = 'POST'; } @@ -292,6 +299,23 @@ export const PromSettings = (props: Props) => { /> +
+ o.value === options.jsonData.defaultEditor)} + onChange={onChangeHandler('defaultEditor', options, onOptionsChange)} + width={20} + disabled={options.readOnly} + /> + } + tooltip={`Set default editor option (builder/code) for all users of this datasource. If no option was selected, the default editor will be the "builder". If they switch to other option rather than the specified with this setting on the panel we always show the selected editor for that user.`} + /> +
+ new PrometheusDatasource( { id: 1, uid: '', @@ -57,14 +79,17 @@ const defaultProps = { name: 'prom-test', access: 'proxy', url: '', - jsonData: {}, - meta: {} as any, + jsonData: jsonDataOverrides, + meta: defaultMeta, readOnly: false, }, undefined, undefined, new EmptyLanguageProviderMock() as unknown as PromQlLanguageProvider - ), + ); + +const defaultProps = { + datasource: getDefaultDatasource(), query: defaultQuery, onRunQuery: () => {}, onChange: () => {}, @@ -77,6 +102,16 @@ describe('PromQueryEditorSelector', () => { expectCodeEditor(); }); + it('shows code editor if no expr and nothing else since defaultEditor is code', async () => { + renderWithDatasourceDefaultEditorMode(QueryEditorMode.Code); + expectCodeEditor(); + }); + + it('shows builder if no expr and nothing else since defaultEditor is builder', async () => { + renderWithDatasourceDefaultEditorMode(QueryEditorMode.Builder); + expectBuilder(); + }); + it('shows code editor when code mode is set', async () => { renderWithMode(QueryEditorMode.Code); expectCodeEditor(); @@ -168,6 +203,22 @@ function renderWithMode(mode: QueryEditorMode) { return renderWithProps({ editorMode: mode } as any); } +function renderWithDatasourceDefaultEditorMode(mode: QueryEditorMode) { + const props = { + ...defaultProps, + datasource: getDefaultDatasource({ + defaultEditor: mode, + }), + query: { + refId: 'B', + expr: '', + }, + onRunQuery: () => {}, + onChange: () => {}, + }; + render(); +} + function renderWithProps(overrides?: Partial, componentProps: Partial = {}) { const query = defaultsDeep(overrides ?? {}, cloneDeep(defaultQuery)); const onChange = jest.fn(); diff --git a/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.tsx b/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.tsx index e943754df7a8..768621924c0c 100644 --- a/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.tsx +++ b/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.tsx @@ -34,12 +34,18 @@ export const INTERVAL_FACTOR_OPTIONS: Array> = map([1, 2 type Props = PromQueryEditorProps; export const PromQueryEditorSelector = React.memo((props) => { - const { onChange, onRunQuery, data, app } = props; + const { + onChange, + onRunQuery, + data, + app, + datasource: { defaultEditor }, + } = props; const [parseModalOpen, setParseModalOpen] = useState(false); const [dataIsStale, setDataIsStale] = useState(false); const { flag: explain, setFlag: setExplain } = useFlag(promQueryEditorExplainKey); - const query = getQueryWithDefaults(props.query, app); + const query = getQueryWithDefaults(props.query, app, defaultEditor); // This should be filled in from the defaults by now. const editorMode = query.editorMode!; diff --git a/public/app/plugins/datasource/prometheus/querybuilder/state.test.ts b/public/app/plugins/datasource/prometheus/querybuilder/state.test.ts index fb8ded74555f..952c55929e76 100644 --- a/public/app/plugins/datasource/prometheus/querybuilder/state.test.ts +++ b/public/app/plugins/datasource/prometheus/querybuilder/state.test.ts @@ -49,4 +49,14 @@ describe('getQueryWithDefaults(', () => { QueryEditorMode.Code ); }); + + it('should return default editor mode when it is provided', () => { + expect(getQueryWithDefaults({ refId: 'A' } as PromQuery, CoreApp.Dashboard, QueryEditorMode.Code)).toEqual({ + editorMode: 'code', + expr: '', + legendFormat: '__auto', + range: true, + refId: 'A', + }); + }); }); diff --git a/public/app/plugins/datasource/prometheus/querybuilder/state.ts b/public/app/plugins/datasource/prometheus/querybuilder/state.ts index 748b8fb814fb..0ffbc346b853 100644 --- a/public/app/plugins/datasource/prometheus/querybuilder/state.ts +++ b/public/app/plugins/datasource/prometheus/querybuilder/state.ts @@ -16,7 +16,7 @@ export function changeEditorMode(query: PromQuery, editorMode: QueryEditorMode, onChange({ ...query, editorMode }); } -function getDefaultEditorMode(expr: string) { +function getDefaultEditorMode(expr: string, defaultEditor: QueryEditorMode = QueryEditorMode.Builder): QueryEditorMode { // If we already have an expression default to code view if (expr != null && expr !== '') { return QueryEditorMode.Code; @@ -28,18 +28,22 @@ function getDefaultEditorMode(expr: string) { case QueryEditorMode.Code: return value; default: - return QueryEditorMode.Builder; + return defaultEditor; } } /** * Returns query with defaults, and boolean true/false depending on change was required */ -export function getQueryWithDefaults(query: PromQuery, app: CoreApp | undefined): PromQuery { +export function getQueryWithDefaults( + query: PromQuery, + app: CoreApp | undefined, + defaultEditor?: QueryEditorMode +): PromQuery { let result = query; if (!query.editorMode) { - result = { ...query, editorMode: getDefaultEditorMode(query.expr) }; + result = { ...query, editorMode: getDefaultEditorMode(query.expr, defaultEditor) }; } if (query.expr == null) { diff --git a/public/app/plugins/datasource/prometheus/types.ts b/public/app/plugins/datasource/prometheus/types.ts index 5181a8fe6ebe..3fbede5a34cb 100644 --- a/public/app/plugins/datasource/prometheus/types.ts +++ b/public/app/plugins/datasource/prometheus/types.ts @@ -35,6 +35,7 @@ export interface PromOptions extends DataSourceJsonData { prometheusType?: PromApplication; prometheusVersion?: string; enableSecureSocksProxy?: boolean; + defaultEditor?: QueryEditorMode; } export type ExemplarTraceIdDestination = { @@ -116,6 +117,7 @@ export type PromValue = [number, any]; export interface PromMetric { __name__?: string; + [index: string]: any; } From 389bdc0eae5f9f3776c50e39b4d7fabab8e7e64e Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Fri, 13 Jan 2023 22:00:37 +0100 Subject: [PATCH 2/2] Small readability improvement --- .../datasource/prometheus/configuration/PromSettings.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/app/plugins/datasource/prometheus/configuration/PromSettings.tsx b/public/app/plugins/datasource/prometheus/configuration/PromSettings.tsx index a5b9d4eee68f..59ba93d3a433 100644 --- a/public/app/plugins/datasource/prometheus/configuration/PromSettings.tsx +++ b/public/app/plugins/datasource/prometheus/configuration/PromSettings.tsx @@ -142,8 +142,8 @@ export const PromSettings = (props: Props) => { // This update call is typed as void, but it returns a response which we need const onUpdate = useUpdateDatasource(); - // We are explicitly adding httpMethod so, it is correctly displayed in dropdown. This way, it is more predictable - // for users. + // We are explicitly adding httpMethod so, it is correctly displayed in dropdown. + // This way, it is more predictable for users. if (!options.jsonData.httpMethod) { options.jsonData.httpMethod = 'POST'; }