Prometheus: Query builder UX tweaks and feedback link (#47655)

* Prometheus: Query builder UX tweaks and feedback link

* Remove .

* Fixed link

* added option to hide feedback links

* feedback link setting name change

* move config check

* fixed ts issue
This commit is contained in:
Torkel Ödegaard 2022-04-14 15:18:03 +02:00 committed by GitHub
parent 782ec05d8c
commit 057ff5bcf5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 87 additions and 26 deletions

View File

@ -230,6 +230,9 @@ application_insights_connection_string =
# Optional. Specifies an Application Insights endpoint URL where the endpoint string is wrapped in backticks ``.
application_insights_endpoint_url =
# Controls if the UI contains any links to user feedback forms
feedback_links_enabled = true
#################################### Security ############################
[security]
# disable creation of admin user on first start of grafana

View File

@ -230,6 +230,9 @@
# Rudderstack Config url, optional, used by Rudderstack SDK to fetch source config
;rudderstack_config_url =
# Controls if the UI contains any links to user feedback forms
;feedback_links_enabled = true
#################################### Security ####################################
[security]
# disable creation of admin user on first start of grafana

View File

@ -509,6 +509,10 @@ If you want to track Grafana usage via Azure Application Insights, then specify
<hr />
### enable_feedback_links
If set to false will remove all feedback links from the UI. Defaults to true.
## [security]
### disable_initial_admin_creation

View File

@ -180,4 +180,5 @@ export interface GrafanaConfig {
geomapDisableCustomBaseLayer?: boolean;
unifiedAlertingEnabled: boolean;
angularSupportEnabled: boolean;
feedbackLinksEnabled: boolean;
}

View File

@ -36,6 +36,7 @@ export class GrafanaBootConfig implements GrafanaConfig {
externalUserMngLinkName = '';
externalUserMngInfo = '';
allowOrgCreate = false;
feedbackLinksEnabled = true;
disableLoginForm = false;
defaultDatasource = ''; // UID
alertingEnabled = false;

View File

@ -113,6 +113,7 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *models.ReqContext) (map[string]i
"rudderstackDataPlaneUrl": setting.RudderstackDataPlaneUrl,
"rudderstackSdkUrl": setting.RudderstackSdkUrl,
"rudderstackConfigUrl": setting.RudderstackConfigUrl,
"feedbackLinksEnabled": hs.Cfg.FeedbackLinksEnabled,
"applicationInsightsConnectionString": hs.Cfg.ApplicationInsightsConnectionString,
"applicationInsightsEndpointUrl": hs.Cfg.ApplicationInsightsEndpointUrl,
"disableLoginForm": setting.DisableLoginForm,

View File

@ -393,6 +393,7 @@ type Cfg struct {
ReportingEnabled bool
ApplicationInsightsConnectionString string
ApplicationInsightsEndpointUrl string
FeedbackLinksEnabled bool
// LDAP
LDAPEnabled bool
@ -938,13 +939,17 @@ func (cfg *Cfg) Load(args CommandLineArgs) error {
RudderstackDataPlaneUrl = analytics.Key("rudderstack_data_plane_url").String()
RudderstackSdkUrl = analytics.Key("rudderstack_sdk_url").String()
RudderstackConfigUrl = analytics.Key("rudderstack_config_url").String()
cfg.ReportingEnabled = analytics.Key("reporting_enabled").MustBool(true)
cfg.ReportingDistributor = analytics.Key("reporting_distributor").MustString("grafana-labs")
if len(cfg.ReportingDistributor) >= 100 {
cfg.ReportingDistributor = cfg.ReportingDistributor[:100]
}
cfg.ApplicationInsightsConnectionString = analytics.Key("application_insights_connection_string").String()
cfg.ApplicationInsightsEndpointUrl = analytics.Key("application_insights_endpoint_url").String()
cfg.FeedbackLinksEnabled = analytics.Key("feedback_links_enabled").MustBool(true)
if err := readAlertingSettings(iniFile); err != nil {
return err

View File

@ -54,7 +54,7 @@ export function PromQueryBuilderContainer(props: Props) {
onRunQuery={onRunQuery}
data={data}
/>
{query.editorPreview && <QueryPreview query={query.expr} />}
{query.rawQuery && <QueryPreview query={query.expr} />}
</>
);
}

View File

@ -90,24 +90,24 @@ describe('PromQueryEditorSelector', () => {
});
});
it('Can enable preview', async () => {
it('Can enable raw query', async () => {
const { onChange } = renderWithMode(QueryEditorMode.Builder);
expect(screen.queryByLabelText('selector')).not.toBeInTheDocument();
screen.getByLabelText('Preview').click();
screen.getByLabelText('Raw query').click();
expect(onChange).toBeCalledWith({
refId: 'A',
expr: defaultQuery.expr,
range: true,
editorMode: QueryEditorMode.Builder,
editorPreview: true,
rawQuery: true,
});
});
it('Should show preview', async () => {
it('Should show raw query', async () => {
renderWithProps({
editorPreview: true,
rawQuery: true,
editorMode: QueryEditorMode.Builder,
expr: 'my_metric',
});

View File

@ -14,6 +14,7 @@ import { PromQueryBuilderContainer } from './PromQueryBuilderContainer';
import { PromQueryBuilderOptions } from './PromQueryBuilderOptions';
import { changeEditorMode, getQueryWithDefaults } from '../state';
import { PromQuery } from '../../types';
import { FeedbackLink } from '../shared/FeedbackLink';
export const PromQueryEditorSelector = React.memo<PromQueryEditorProps>((props) => {
const { onChange, onRunQuery, data } = props;
@ -44,7 +45,7 @@ export const PromQueryEditorSelector = React.memo<PromQueryEditorProps>((props)
const onQueryPreviewChange = (event: SyntheticEvent<HTMLInputElement>) => {
const isEnabled = event.currentTarget.checked;
onChange({ ...query, editorPreview: isEnabled });
onChange({ ...query, rawQuery: isEnabled });
onRunQuery();
};
@ -67,16 +68,6 @@ export const PromQueryEditorSelector = React.memo<PromQueryEditorProps>((props)
onDismiss={() => setParseModalOpen(false)}
/>
<EditorHeader>
<FlexItem grow={1} />
<Button
variant={dataIsStale ? 'primary' : 'secondary'}
size="sm"
onClick={onRunQuery}
icon={data?.state === LoadingState.Loading ? 'fa fa-spinner' : undefined}
disabled={data?.state === LoadingState.Loading}
>
Run query
</Button>
{editorMode === QueryEditorMode.Builder && (
<>
<InlineSelect
@ -95,14 +86,22 @@ export const PromQueryEditorSelector = React.memo<PromQueryEditorProps>((props)
}}
options={promQueryModeller.getQueryPatterns().map((x) => ({ label: x.name, value: x }))}
/>
<QueryHeaderSwitch label="Raw query" value={query.rawQuery} onChange={onQueryPreviewChange} />
</>
)}
<QueryHeaderSwitch
label="Preview"
value={query.editorPreview}
onChange={onQueryPreviewChange}
disabled={editorMode !== QueryEditorMode.Builder}
/>
{editorMode === QueryEditorMode.Builder && (
<FeedbackLink feedbackUrl="https://github.com/grafana/grafana/discussions/47693" />
)}
<FlexItem grow={1} />
<Button
variant={dataIsStale ? 'primary' : 'secondary'}
size="sm"
onClick={onRunQuery}
icon={data?.state === LoadingState.Loading ? 'fa fa-spinner' : undefined}
disabled={data?.state === LoadingState.Loading}
>
Run query
</Button>
<QueryEditorModeToggle mode={editorMode} onChange={onEditorModeChange} />
</EditorHeader>
<Space v={0.5} />

View File

@ -18,7 +18,7 @@ export function QueryPreview({ query }: Props) {
return (
<EditorRow>
<EditorFieldGroup>
<EditorField label="Preview">
<EditorField label="Raw query">
<div
className={cx(styles.editorField, 'prism-syntax-highlight')}
aria-label="selector"

View File

@ -0,0 +1,44 @@
import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { Stack } from '@grafana/experimental';
import { config } from '@grafana/runtime';
import { Icon, useStyles2 } from '@grafana/ui';
import React from 'react';
export interface Props {
feedbackUrl?: string;
}
export function FeedbackLink({ feedbackUrl }: Props) {
const styles = useStyles2(getStyles);
if (!config.feedbackLinksEnabled) {
return null;
}
return (
<Stack gap={1}>
<a
href={feedbackUrl}
className={styles.link}
title="This query builder is new, please let us know how we can improve it"
target="_blank"
rel="noreferrer noopener"
>
<Icon name="comment-alt-message" /> Give feedback
</a>
</Stack>
);
}
function getStyles(theme: GrafanaTheme2) {
return {
link: css({
color: theme.colors.text.secondary,
fontSize: theme.typography.bodySmall.fontSize,
':hover': {
color: theme.colors.text.link,
},
}),
};
}

View File

@ -19,8 +19,8 @@ export interface PromQuery extends DataQuery {
showingTable?: boolean;
/** Code, Builder or Explain */
editorMode?: QueryEditorMode;
/** Controls if the query preview is shown */
editorPreview?: boolean;
/** Controls if the raw query text is shown */
rawQuery?: boolean;
}
export interface PromOptions extends DataSourceJsonData {