From d0ecf863df9894dd227a1173b08a82644e7d1391 Mon Sep 17 00:00:00 2001 From: Andre Pereira Date: Thu, 1 Feb 2024 13:01:24 +0000 Subject: [PATCH] Datatrails: Metric as breadcrumb and style improvements (#81661) * Fixed duplicate trails entry for first time users. Show header with description for first time users * Renamed trail to history in History component * Use metric name in breadcrumb * Style tweaks around search field in metric select * Address PR comments * prettier --- public/app/features/trails/DataTrail.tsx | 11 +++-- public/app/features/trails/DataTrailCard.tsx | 18 ++------ public/app/features/trails/DataTrailsApp.tsx | 8 +++- .../app/features/trails/DataTrailsHistory.tsx | 2 +- public/app/features/trails/DataTrailsHome.tsx | 9 ++-- .../app/features/trails/MetricSelectScene.tsx | 43 +++++++++++-------- public/app/features/trails/MetricsHeader.tsx | 10 +++++ public/app/features/trails/utils.ts | 14 +++++- 8 files changed, 67 insertions(+), 48 deletions(-) create mode 100644 public/app/features/trails/MetricsHeader.tsx diff --git a/public/app/features/trails/DataTrail.tsx b/public/app/features/trails/DataTrail.tsx index a3cb526c2257..27f75ee6b01c 100644 --- a/public/app/features/trails/DataTrail.tsx +++ b/public/app/features/trails/DataTrail.tsx @@ -27,8 +27,9 @@ import { DataTrailSettings } from './DataTrailSettings'; import { DataTrailHistory, DataTrailHistoryStep } from './DataTrailsHistory'; import { MetricScene } from './MetricScene'; import { MetricSelectScene } from './MetricSelectScene'; +import { MetricsHeader } from './MetricsHeader'; import { getTrailStore } from './TrailStore/TrailStore'; -import { MetricSelectedEvent, trailDS, LOGS_METRIC, VAR_DATASOURCE, VAR_FILTERS } from './shared'; +import { LOGS_METRIC, MetricSelectedEvent, trailDS, VAR_DATASOURCE, VAR_FILTERS } from './shared'; import { getUrlForTrail } from './utils'; export interface DataTrailState extends SceneObjectState { @@ -162,7 +163,7 @@ export class DataTrail extends SceneObjectBase { } } else if (values.metric === null) { stateUpdate.metric = undefined; - stateUpdate.topScene = new MetricSelectScene({ showHeading: true }); + stateUpdate.topScene = new MetricSelectScene({}); } this.setState(stateUpdate); @@ -171,9 +172,11 @@ export class DataTrail extends SceneObjectBase { static Component = ({ model }: SceneComponentProps) => { const { controls, topScene, history } = model.useState(); const styles = useStyles2(getStyles); + const showHeaderForFirstTimeUsers = getTrailStore().recent.length < 2; return (
+ {showHeaderForFirstTimeUsers && } {controls && (
@@ -192,7 +195,7 @@ function getTopSceneFor(metric?: string) { if (metric) { return new MetricScene({ metric: metric }); } else { - return new MetricSelectScene({ showHeading: true }); + return new MetricSelectScene({}); } } @@ -221,7 +224,7 @@ function getStyles(theme: GrafanaTheme2) { container: css({ flexGrow: 1, display: 'flex', - gap: theme.spacing(2), + gap: theme.spacing(1), minHeight: '100%', flexDirection: 'column', }), diff --git a/public/app/features/trails/DataTrailCard.tsx b/public/app/features/trails/DataTrailCard.tsx index 757e18696fa5..7e526c9640dc 100644 --- a/public/app/features/trails/DataTrailCard.tsx +++ b/public/app/features/trails/DataTrailCard.tsx @@ -3,11 +3,11 @@ import React from 'react'; import { dateTimeFormat, GrafanaTheme2 } from '@grafana/data'; import { AdHocFiltersVariable, sceneGraph } from '@grafana/scenes'; -import { useStyles2, Stack, Card, IconButton, Badge } from '@grafana/ui'; +import { Badge, Card, IconButton, Stack, useStyles2 } from '@grafana/ui'; import { DataTrail } from './DataTrail'; -import { LOGS_METRIC, VAR_FILTERS } from './shared'; -import { getDataSource, getDataSourceName } from './utils'; +import { VAR_FILTERS } from './shared'; +import { getDataSource, getDataSourceName, getMetricName } from './utils'; export interface Props { trail: DataTrail; @@ -63,18 +63,6 @@ export function DataTrailCard({ trail, onSelect, onDelete }: Props) { ); } -function getMetricName(metric?: string) { - if (!metric) { - return 'Select metric'; - } - - if (metric === LOGS_METRIC) { - return 'Logs'; - } - - return metric; -} - function getStyles(theme: GrafanaTheme2) { return { tag: css({ diff --git a/public/app/features/trails/DataTrailsApp.tsx b/public/app/features/trails/DataTrailsApp.tsx index c56c8adc17ea..f8fe2d33b5bd 100644 --- a/public/app/features/trails/DataTrailsApp.tsx +++ b/public/app/features/trails/DataTrailsApp.tsx @@ -11,7 +11,7 @@ import { Page } from 'app/core/components/Page/Page'; import { DataTrail } from './DataTrail'; import { DataTrailsHome } from './DataTrailsHome'; import { getTrailStore } from './TrailStore/TrailStore'; -import { getUrlForTrail, newMetricsTrail } from './utils'; +import { getMetricName, getUrlForTrail, newMetricsTrail } from './utils'; export interface DataTrailsAppState extends SceneObjectState { trail: DataTrail; @@ -49,7 +49,11 @@ export class DataTrailsApp extends SceneObjectBase { exact={true} path="/explore/metrics/trail" render={() => ( - +
diff --git a/public/app/features/trails/DataTrailsHistory.tsx b/public/app/features/trails/DataTrailsHistory.tsx index b5bdbb6eeae3..34490bd2fb13 100644 --- a/public/app/features/trails/DataTrailsHistory.tsx +++ b/public/app/features/trails/DataTrailsHistory.tsx @@ -139,7 +139,7 @@ export class DataTrailHistory extends SceneObjectBase { return (
-
Trail
+
History
{steps.map((step, index) => ( model.renderStepTooltip(step)} key={index}> diff --git a/public/app/features/trails/MetricSelectScene.tsx b/public/app/features/trails/MetricSelectScene.tsx index 13fd520cbfd3..eb8ce11c199b 100644 --- a/public/app/features/trails/MetricSelectScene.tsx +++ b/public/app/features/trails/MetricSelectScene.tsx @@ -4,22 +4,22 @@ import React from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { - SceneObjectState, - SceneObjectBase, - SceneComponentProps, PanelBuilders, - SceneFlexItem, - SceneVariableSet, QueryVariable, - sceneGraph, - VariableDependencyConfig, - SceneCSSGridLayout, + SceneComponentProps, SceneCSSGridItem, + SceneCSSGridLayout, + SceneFlexItem, + sceneGraph, + SceneObjectBase, SceneObjectRef, + SceneObjectState, SceneQueryRunner, + SceneVariableSet, + VariableDependencyConfig, } from '@grafana/scenes'; import { VariableHide } from '@grafana/schema'; -import { Input, Text, useStyles2, InlineSwitch, Field, LoadingPlaceholder } from '@grafana/ui'; +import { Field, Icon, InlineSwitch, Input, LoadingPlaceholder, useStyles2 } from '@grafana/ui'; import { getAutoQueriesForMetric } from './AutomaticMetricQueries/AutoQueryEngine'; import { MetricCategoryCascader } from './MetricCategory/MetricCategoryCascader'; @@ -40,7 +40,6 @@ interface MetricPanel { export interface MetricSelectSceneState extends SceneObjectState { body: SceneCSSGridLayout; - showHeading?: boolean; searchQuery?: string; showPreviews?: boolean; prefixFilter?: string; @@ -274,8 +273,7 @@ export class MetricSelectScene extends SceneObjectBase { }; public static Component = ({ model }: SceneComponentProps) => { - const { showHeading, searchQuery, showPreviews, body, metricsAfterSearch, metricsAfterFilter, prefixFilter } = - model.useState(); + const { searchQuery, showPreviews, body, metricsAfterSearch, metricsAfterFilter, prefixFilter } = model.useState(); const { children } = body.useState(); const styles = useStyles2(getStyles); @@ -296,13 +294,15 @@ export class MetricSelectScene extends SceneObjectBase { return (
- {showHeading && ( -
- Select a metric -
- )}
- + + } + value={searchQuery} + onChange={model.onSearchChange} + /> +
@@ -393,19 +393,24 @@ function getStyles(theme: GrafanaTheme2) { flexGrow: 1, }), headingWrapper: css({ - marginTop: theme.spacing(1), + marginBottom: theme.spacing(0.5), }), header: css({ flexGrow: 0, display: 'flex', gap: theme.spacing(2), marginBottom: theme.spacing(1), + alignItems: 'flex-end', }), statusMessage: css({ fontStyle: 'italic', marginTop: theme.spacing(7), textAlign: 'center', }), + searchField: css({ + flexGrow: 1, + marginBottom: 0, + }), }; } diff --git a/public/app/features/trails/MetricsHeader.tsx b/public/app/features/trails/MetricsHeader.tsx new file mode 100644 index 000000000000..f40edb4be898 --- /dev/null +++ b/public/app/features/trails/MetricsHeader.tsx @@ -0,0 +1,10 @@ +import React from 'react'; + +import { Stack, Text } from '@grafana/ui'; + +export const MetricsHeader = () => ( + + Metrics + Explore your Prometheus-compatible metrics without writing a query + +); diff --git a/public/app/features/trails/utils.ts b/public/app/features/trails/utils.ts index df5f62c0b775..b80a42b9eb57 100644 --- a/public/app/features/trails/utils.ts +++ b/public/app/features/trails/utils.ts @@ -8,7 +8,7 @@ import { DataTrail } from './DataTrail'; import { DataTrailSettings } from './DataTrailSettings'; import { MetricScene } from './MetricScene'; import { getTrailStore } from './TrailStore/TrailStore'; -import { TRAILS_ROUTE, VAR_DATASOURCE_EXPR } from './shared'; +import { LOGS_METRIC, TRAILS_ROUTE, VAR_DATASOURCE_EXPR } from './shared'; export function getTrailFor(model: SceneObject): DataTrail { return sceneGraph.getAncestor(model, DataTrail); @@ -58,6 +58,18 @@ export function getDataSourceName(dataSourceUid: string) { return getDataSourceSrv().getInstanceSettings(dataSourceUid)?.name || dataSourceUid; } +export function getMetricName(metric?: string) { + if (!metric) { + return 'Select metric'; + } + + if (metric === LOGS_METRIC) { + return 'Logs'; + } + + return metric; +} + export function getDatasourceForNewTrail(): string | undefined { const prevTrail = getTrailStore().recent[0]; if (prevTrail) {