+ {NativeHistogramBanner({ histogramsLoaded, nativeHistograms, trail: model })}
{showHeaderForFirstTimeUsers &&
}
{controls && (
@@ -546,9 +621,9 @@ export class DataTrail extends SceneObjectBase
implements SceneO
};
}
-export function getTopSceneFor(metric?: string) {
+export function getTopSceneFor(metric?: string, nativeHistogram?: boolean) {
if (metric) {
- return new MetricScene({ metric: metric });
+ return new MetricScene({ metric: metric, nativeHistogram: nativeHistogram ?? false });
} else {
return new MetricSelectScene({});
}
diff --git a/public/app/features/trails/MetricScene.tsx b/public/app/features/trails/MetricScene.tsx
index 0e3cb6b48f7..e2920e510d9 100644
--- a/public/app/features/trails/MetricScene.tsx
+++ b/public/app/features/trails/MetricScene.tsx
@@ -44,6 +44,7 @@ const relatedLogsFeatureEnabled = config.featureToggles.exploreMetricsRelatedLog
export interface MetricSceneState extends SceneObjectState {
body: MetricGraphScene;
metric: string;
+ nativeHistogram?: boolean;
actionView?: string;
autoQuery: AutoQueryInfo;
@@ -54,7 +55,7 @@ export class MetricScene extends SceneObjectBase {
protected _urlSync = new SceneObjectUrlSyncConfig(this, { keys: ['actionView'] });
public constructor(state: MakeOptional) {
- const autoQuery = state.autoQuery ?? getAutoQueriesForMetric(state.metric);
+ const autoQuery = state.autoQuery ?? getAutoQueriesForMetric(state.metric, state.nativeHistogram);
super({
$variables: state.$variables ?? getVariableSet(state.metric),
body: state.body ?? new MetricGraphScene({}),
diff --git a/public/app/features/trails/MetricSelect/MetricSelectScene.tsx b/public/app/features/trails/MetricSelect/MetricSelectScene.tsx
index 1eb1deacf45..ce3d0c86dd3 100644
--- a/public/app/features/trails/MetricSelect/MetricSelectScene.tsx
+++ b/public/app/features/trails/MetricSelect/MetricSelectScene.tsx
@@ -424,7 +424,9 @@ export class MetricSelectScene extends SceneObjectBase i
children.push(metric.itemRef.resolve());
continue;
}
- const panel = getPreviewPanelFor(metric.name, index, currentFilterCount, description);
+ // refactor this into the query generator in future
+ const isNative = trail.isNativeHistogram(metric.name);
+ const panel = getPreviewPanelFor(metric.name, index, currentFilterCount, description, isNative);
metric.itemRef = panel.getRef();
metric.isPanel = true;
diff --git a/public/app/features/trails/MetricSelect/NativeHistogramBadge.tsx b/public/app/features/trails/MetricSelect/NativeHistogramBadge.tsx
new file mode 100644
index 00000000000..f2c551f3d70
--- /dev/null
+++ b/public/app/features/trails/MetricSelect/NativeHistogramBadge.tsx
@@ -0,0 +1,32 @@
+import { css } from '@emotion/css';
+
+import { GrafanaTheme2 } from '@grafana/data';
+import { SceneObjectBase } from '@grafana/scenes';
+import { Badge, useStyles2 } from '@grafana/ui';
+import { Trans } from '@grafana/ui/src/utils/i18n';
+
+export class NativeHistogramBadge extends SceneObjectBase {
+ public static Component = () => {
+ const styles = useStyles2(getStyles);
+ return (
+ Native Histogram}
+ />
+ );
+ };
+}
+
+function getStyles(theme: GrafanaTheme2) {
+ return {
+ badge: css({
+ borderRadius: theme.shape.radius.pill,
+ border: `1px solid ${theme.colors.info.text}`,
+ background: theme.colors.info.transparent,
+ cursor: 'auto',
+ width: '112px',
+ padding: '0rem 0.25rem 0 0.35rem',
+ }),
+ };
+}
diff --git a/public/app/features/trails/MetricSelect/previewPanel.ts b/public/app/features/trails/MetricSelect/previewPanel.ts
index dd5feb9391b..92007959ac0 100644
--- a/public/app/features/trails/MetricSelect/previewPanel.ts
+++ b/public/app/features/trails/MetricSelect/previewPanel.ts
@@ -6,20 +6,32 @@ import { getVariablesWithMetricConstant, MDP_METRIC_PREVIEW, trailDS } from '../
import { getColorByIndex } from '../utils';
import { AddToExplorationButton } from './AddToExplorationsButton';
+import { NativeHistogramBadge } from './NativeHistogramBadge';
import { SelectMetricAction } from './SelectMetricAction';
import { hideEmptyPreviews } from './hideEmptyPreviews';
-export function getPreviewPanelFor(metric: string, index: number, currentFilterCount: number, description?: string) {
- const autoQuery = getAutoQueriesForMetric(metric);
+export function getPreviewPanelFor(
+ metric: string,
+ index: number,
+ currentFilterCount: number,
+ description?: string,
+ nativeHistogram?: boolean
+) {
+ const autoQuery = getAutoQueriesForMetric(metric, nativeHistogram);
+ let actions: Array = [
+ new SelectMetricAction({ metric, title: 'Select' }),
+ new AddToExplorationButton({ labelName: metric }),
+ ];
+
+ if (nativeHistogram) {
+ actions.unshift(new NativeHistogramBadge({}));
+ }
const vizPanel = autoQuery.preview
.vizBuilder()
.setColor({ mode: 'fixed', fixedColor: getColorByIndex(index) })
.setDescription(description)
- .setHeaderActions([
- new SelectMetricAction({ metric, title: 'Select' }),
- new AddToExplorationButton({ labelName: metric }),
- ])
+ .setHeaderActions(actions)
.build();
const queries = autoQuery.preview.queries.map((query) =>
diff --git a/public/app/features/trails/TrailStore/TrailStore.test.ts b/public/app/features/trails/TrailStore/TrailStore.test.ts
index ba41d6c6014..b92abceca20 100644
--- a/public/app/features/trails/TrailStore/TrailStore.test.ts
+++ b/public/app/features/trails/TrailStore/TrailStore.test.ts
@@ -66,6 +66,7 @@ describe('TrailStore', () => {
'var-ds': 'cb3a3391-700f-4cc6-81be-a122488e93e6',
'var-filters': [],
refresh: '',
+ nativeHistogramMetric: '',
},
type: 'start',
description: 'Test',
@@ -80,6 +81,7 @@ describe('TrailStore', () => {
'var-ds': 'cb3a3391-700f-4cc6-81be-a122488e93e6',
'var-filters': [],
refresh: '',
+ nativeHistogramMetric: '',
},
type: 'metric',
description: 'Test',
@@ -228,6 +230,7 @@ describe('TrailStore', () => {
'var-ds': 'ds',
'var-filters': [],
refresh: '',
+ nativeHistogramMetric: '',
},
type: 'start',
description: 'Test',
@@ -242,6 +245,7 @@ describe('TrailStore', () => {
'var-ds': 'ds',
'var-filters': [],
refresh: '',
+ nativeHistogramMetric: '',
},
type: 'metric',
description: 'Test',
@@ -256,6 +260,7 @@ describe('TrailStore', () => {
'var-ds': 'ds',
'var-filters': [],
refresh: '',
+ nativeHistogramMetric: '',
},
type: 'metric',
description: 'Test',
@@ -506,6 +511,7 @@ describe('TrailStore', () => {
{
urlValues: {
metric: 'bookmarked_metric',
+ nativeHistogramMetric: '',
from: 'now-1h',
to: 'now',
timezone,
@@ -603,6 +609,7 @@ describe('TrailStore', () => {
'var-ds': 'cb3a3391-700f-4cc6-81be-a122488e93e6',
'var-filters': [],
refresh: '',
+ nativeHistogramMetric: '',
},
type: 'start',
description: 'Test',
@@ -616,6 +623,7 @@ describe('TrailStore', () => {
'var-ds': 'cb3a3391-700f-4cc6-81be-a122488e93e6',
'var-filters': [],
refresh: '',
+ nativeHistogramMetric: '',
},
type: 'time',
description: 'Test',
@@ -655,6 +663,7 @@ describe('TrailStore', () => {
'var-ds': 'prom-mock',
'var-filters': [],
refresh: '',
+ nativeHistogramMetric: '',
},
type: 'start',
},
@@ -666,6 +675,7 @@ describe('TrailStore', () => {
'var-ds': 'prom-mock',
'var-filters': [],
refresh: '',
+ nativeHistogramMetric: '',
},
type: 'time',
},
@@ -677,6 +687,7 @@ describe('TrailStore', () => {
'var-ds': 'prom-mock',
'var-filters': [],
refresh: '',
+ nativeHistogramMetric: '',
},
type: 'metric',
},
@@ -713,6 +724,7 @@ describe('TrailStore', () => {
history: [
{
urlValues: {
+ nativeHistogramMetric: '',
from: 'now-1h',
to: 'now',
timezone,
@@ -728,6 +740,7 @@ describe('TrailStore', () => {
{
urlValues: {
metric: 'bookmarked_metric',
+ nativeHistogramMetric: '',
from: 'now-1h',
to: 'now',
timezone,
@@ -743,6 +756,7 @@ describe('TrailStore', () => {
{
urlValues: {
metric: 'some_other_metric',
+ nativeHistogramMetric: '',
from: 'now-1h',
to: 'now',
timezone,
@@ -766,6 +780,7 @@ describe('TrailStore', () => {
{
urlValues: {
metric: 'bookmarked_metric',
+ nativeHistogramMetric: '',
from: 'now-1h',
to: 'now',
timezone,
diff --git a/public/app/features/trails/autoQuery/getAutoQueriesForMetric.ts b/public/app/features/trails/autoQuery/getAutoQueriesForMetric.ts
index aa09aeb8486..732fd6ed4b3 100644
--- a/public/app/features/trails/autoQuery/getAutoQueriesForMetric.ts
+++ b/public/app/features/trails/autoQuery/getAutoQueriesForMetric.ts
@@ -4,7 +4,7 @@ import { createSummaryMetricQueryDefs } from './queryGenerators/summary';
import { AutoQueryContext, AutoQueryInfo } from './types';
import { getUnit } from './units';
-export function getAutoQueriesForMetric(metric: string): AutoQueryInfo {
+export function getAutoQueriesForMetric(metric: string, nativeHistogram?: boolean): AutoQueryInfo {
const isUtf8Metric = false;
const metricParts = metric.split('_');
const suffix = metricParts.at(-1);
@@ -28,7 +28,7 @@ export function getAutoQueriesForMetric(metric: string): AutoQueryInfo {
return createSummaryMetricQueryDefs(ctx);
}
- if (suffix === 'bucket') {
+ if (suffix === 'bucket' || nativeHistogram) {
return createHistogramMetricQueryDefs(ctx);
}
diff --git a/public/app/features/trails/banners/NativeHistogramBanner.test.tsx b/public/app/features/trails/banners/NativeHistogramBanner.test.tsx
new file mode 100644
index 00000000000..d5191037dae
--- /dev/null
+++ b/public/app/features/trails/banners/NativeHistogramBanner.test.tsx
@@ -0,0 +1,54 @@
+import { render, screen, fireEvent } from '@testing-library/react';
+
+import { DataTrail } from '../DataTrail';
+import { MetricSelectedEvent } from '../shared';
+
+import { NativeHistogramBanner } from './NativeHistogramBanner';
+
+const mockTrail = {
+ publishEvent: jest.fn(),
+} as unknown as DataTrail;
+
+const mockProps = {
+ histogramsLoaded: true,
+ nativeHistograms: ['histogram1', 'histogram2'],
+ trail: mockTrail,
+};
+
+describe('NativeHistogramBanner', () => {
+ test('renders correctly when histograms are loaded', () => {
+ render();
+ expect(screen.getByText('Native Histogram Support')).toBeInTheDocument();
+ expect(
+ screen.getByText(
+ 'Prometheus native histograms offer high resolution, high precision, simple usage in instrumentation and a way to combine and manipulate histograms in queries and in Grafana.'
+ )
+ ).toBeInTheDocument();
+ });
+
+ test('Has a learn more button works', () => {
+ render();
+ const learnMoreButton = screen.getByText('Learn more');
+ expect(learnMoreButton).toBeInTheDocument();
+ });
+
+ test('See examples button works', () => {
+ render();
+ const seeExamplesButton = screen.getByText('> See examples');
+ expect(seeExamplesButton).toBeInTheDocument();
+ fireEvent.click(seeExamplesButton);
+ expect(screen.getByText('Native Histogram displayed as heatmap:')).toBeInTheDocument();
+ expect(screen.getByText('Native Histogram displayed as histogram:')).toBeInTheDocument();
+ expect(screen.getByText('Classic Histogram displayed as heatmap:')).toBeInTheDocument();
+ expect(screen.getByText('Classic Histogram displayed as histogram:')).toBeInTheDocument();
+ });
+
+ test('Native histograms buttons work', () => {
+ render();
+ fireEvent.click(screen.getByText('> See examples'));
+ const histogramButton = screen.getByText('histogram1');
+ expect(histogramButton).toBeInTheDocument();
+ fireEvent.click(histogramButton);
+ expect(mockTrail.publishEvent).toHaveBeenCalledWith(new MetricSelectedEvent('histogram1'), true);
+ });
+});
diff --git a/public/app/features/trails/banners/NativeHistogramBanner.tsx b/public/app/features/trails/banners/NativeHistogramBanner.tsx
new file mode 100644
index 00000000000..62bcd7551f3
--- /dev/null
+++ b/public/app/features/trails/banners/NativeHistogramBanner.tsx
@@ -0,0 +1,273 @@
+import { css } from '@emotion/css';
+import { useState, type Dispatch, type SetStateAction } from 'react';
+
+import { GrafanaTheme2 } from '@grafana/data';
+import { useStyles2, useTheme2, Alert, Button } from '@grafana/ui';
+import { t, Trans } from '@grafana/ui/src/utils/i18n';
+
+import { DataTrail } from '../DataTrail';
+import { reportExploreMetrics } from '../interactions';
+import { MetricSelectedEvent } from '../shared';
+
+interface NativeHistogramInfoProps {
+ histogramsLoaded: boolean;
+ nativeHistograms: string[];
+ trail: DataTrail;
+}
+
+export function NativeHistogramBanner(props: NativeHistogramInfoProps) {
+ const { histogramsLoaded, nativeHistograms, trail } = props;
+ const [histogramMessage, setHistogramMessage] = useState(true);
+ const [showHistogramExamples, setShowHistogramExamples] = useState(false);
+ const styles = useStyles2(getStyles, 0);
+
+ if (!histogramsLoaded || nativeHistograms.length === 0 || !histogramMessage) {
+ return null;
+ }
+
+ return (
+ <>
+ {
+ {
+ setHistogramMessage(false);
+ }}
+ >
+
+
+
+ Prometheus native histograms offer high resolution, high precision, simple usage in instrumentation and
+ a way to combine and manipulate histograms in queries and in Grafana.
+
+
+
+
+
+
+
+
+
+ {showHistogramExamples && (
+
+ )}
+
+ }
+ >
+ );
+}
+
+interface NativeHistogramExamplesButtonProps {
+ showHistogramExamples: boolean;
+ setShowHistogramExamples: Dispatch>;
+}
+
+const NativeHistogramExamplesButton = ({
+ showHistogramExamples,
+ setShowHistogramExamples,
+}: NativeHistogramExamplesButtonProps) => {
+ const styles = useStyles2(getStyles, 0);
+
+ return (
+
+
+
+ );
+};
+
+type NativeHistogramExamplesProps = Pick & {
+ setHistogramMessage: Dispatch>;
+};
+
+const NativeHistogramExamples = ({ trail, nativeHistograms, setHistogramMessage }: NativeHistogramExamplesProps) => {
+ const styles = useStyles2(getStyles, 0);
+ const isDark = useTheme2().isDark;
+ const selectNativeHistogram = (metric: string) => {
+ reportExploreMetrics('native_histogram_example_clicked', {
+ metric,
+ });
+ trail.publishEvent(new MetricSelectedEvent(metric), true);
+ };
+ const images = {
+ nativeHeatmap: isDark
+ ? 'public/img/native-histograms/DarkModeHeatmapNativeHistogram.png'
+ : 'public/img/native-histograms/LightModeHeatmapNativeHistogram.png',
+ classicHeatmap: isDark
+ ? 'public/img/native-histograms/DarkModeHeatmapClassicHistogram.png'
+ : 'public/img/native-histograms/LightModeHeatmapClassicHistogram.png',
+ nativeHistogram: isDark
+ ? 'public/img/native-histograms/DarkModeHistogramNativehistogram.png'
+ : 'public/img/native-histograms/LightModeHistogramClassicHistogram.png',
+ classicHistogram: isDark
+ ? 'public/img/native-histograms/DarkModeHistogramClassicHistogram.png'
+ : 'public/img/native-histograms/LightModeHistogramClassicHistogram.png',
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+ Native Histogram displayed as heatmap:
+
+
+
+

+
+
+
+
+
+ Native Histogram displayed as histogram:
+
+
+
+

+
+
+
+
+
+
+
+
+
+ Classic Histogram displayed as heatmap:
+
+
+
+

+
+
+
+
+
+ Classic Histogram displayed as histogram:
+
+
+
+

+
+
+
+
+
+
+
+
+ Click any of the native histograms below to explore them:
+
+
+
+ {nativeHistograms.map((el) => {
+ return (
+
+
+
+ );
+ })}
+
+ >
+ );
+};
+
+function getStyles(theme: GrafanaTheme2, _chromeHeaderHeight: number) {
+ return {
+ histogramRow: css({
+ display: 'flex',
+ flexDirection: 'row',
+ gap: theme.spacing(2),
+ }),
+ histogramSentence: css({
+ width: '90%',
+ }),
+ histogramLearnMore: css({
+ width: '10%',
+ }),
+ button: css({
+ float: 'right',
+ }),
+ seeExamplesButton: css({
+ paddingLeft: '0px',
+ }),
+ seeExamplesRow: css({
+ paddingTop: '4px',
+ }),
+ histogramImageCol: css({
+ display: 'flex',
+ flexDirection: 'column',
+ flexBasis: '100%',
+ flex: '1',
+ }),
+ fontSmall: css({
+ fontSize: theme.typography.size.sm,
+ }),
+ imageText: css({
+ paddingBottom: '4px',
+ }),
+ rightImageCol: css({
+ borderLeft: `1px solid ${theme.colors.secondary.borderTransparent}`,
+ }),
+ rightCol: css({
+ paddingLeft: '16px',
+ }),
+ };
+}
diff --git a/public/app/features/trails/helpers/MetricDataSourceHelper.test.ts b/public/app/features/trails/helpers/MetricDataSourceHelper.test.ts
new file mode 100644
index 00000000000..48574cebe20
--- /dev/null
+++ b/public/app/features/trails/helpers/MetricDataSourceHelper.test.ts
@@ -0,0 +1,45 @@
+import { DataTrail } from '../DataTrail';
+
+import { MetricDatasourceHelper } from './MetricDatasourceHelper';
+
+jest.mock('@grafana/runtime', () => ({
+ ...jest.requireActual('@grafana/runtime'),
+ config: {
+ ...jest.requireActual('@grafana/runtime').config,
+ publicDashboardAccessToken: '123',
+ },
+}));
+
+const NATIVE_HISTOGRAM = 'test_metric';
+describe('MetricDatasourceHelper', () => {
+ let metricDatasourceHelper: MetricDatasourceHelper;
+
+ beforeEach(() => {
+ const trail = new DataTrail({});
+ metricDatasourceHelper = new MetricDatasourceHelper(trail);
+ metricDatasourceHelper['_classicHistograms'] = {
+ test_metric_bucket: 1,
+ };
+ });
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe('isNativeHistogram', () => {
+ it('should return false if metric is not provided', async () => {
+ const result = await metricDatasourceHelper.isNativeHistogram('');
+ expect(result).toBe(false);
+ });
+
+ it('should return true if metric is a native histogram', async () => {
+ const result = await metricDatasourceHelper.isNativeHistogram(NATIVE_HISTOGRAM);
+ expect(result).toBe(true);
+ });
+
+ it('should return false if metric is not a native histogram', async () => {
+ const result = await metricDatasourceHelper.isNativeHistogram('non_histogram_metric');
+ expect(result).toBe(false);
+ });
+ });
+});
diff --git a/public/app/features/trails/helpers/MetricDatasourceHelper.ts b/public/app/features/trails/helpers/MetricDatasourceHelper.ts
index d9b84d76b82..4ecfb09db53 100644
--- a/public/app/features/trails/helpers/MetricDatasourceHelper.ts
+++ b/public/app/features/trails/helpers/MetricDatasourceHelper.ts
@@ -19,6 +19,8 @@ export class MetricDatasourceHelper {
public reset() {
this._datasource = undefined;
this._metricsMetadata = undefined;
+ this._classicHistograms = {};
+ this._nativeHistograms = [];
}
private _trail: DataTrail;
@@ -61,6 +63,67 @@ export class MetricDatasourceHelper {
return metadata?.[metric];
}
+ private _classicHistograms: Record = {};
+ private _nativeHistograms: string[] = [];
+
+ public listNativeHistograms() {
+ return this._nativeHistograms;
+ }
+ /**
+ * Identify native histograms by querying classic histograms and all metrics,
+ * then comparing the results and build the collection of native histograms.
+ *
+ * classic histogram = test_metric_bucket
+ * native histogram = test_metric
+ */
+ public async initializeHistograms() {
+ const ds = await this.getDatasource();
+ if (Object.keys(this._classicHistograms).length === 0 && ds instanceof PrometheusDatasource) {
+ const classicHistogramsCall = ds.metricFindQuery('metrics(.*_bucket)');
+ const allMetricsCall = ds.metricFindQuery('metrics(.*)');
+
+ const [classicHistograms, allMetrics] = await Promise.all([classicHistogramsCall, allMetricsCall]);
+
+ classicHistograms.forEach((m) => {
+ this._classicHistograms[m.text] = 1;
+ });
+
+ allMetrics.forEach((m) => {
+ if (this.isNativeHistogram(m.text)) {
+ // Build the collection of native histograms.
+ this.addNativeHistogram(m.text);
+ }
+ });
+ }
+ }
+
+ /**
+ *
+ * If a metric name + _bucket exists in the classic histograms, then it is a native histogram
+ *
+ * classic histogram = test_metric_bucket
+ * native histogram = test_metric
+ * @param metric
+ * @returns
+ */
+ public isNativeHistogram(metric: string): boolean {
+ if (!metric) {
+ return false;
+ }
+
+ if (this._classicHistograms[`${metric}_bucket`]) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private addNativeHistogram(metric: string) {
+ if (!this._nativeHistograms.includes(metric)) {
+ this._nativeHistograms.push(metric);
+ }
+ }
+
/**
* Used for additional filtering for adhoc vars labels in Explore metrics.
* @param options
diff --git a/public/app/features/trails/interactions.ts b/public/app/features/trails/interactions.ts
index 968742feb35..c0306b01410 100644
--- a/public/app/features/trails/interactions.ts
+++ b/public/app/features/trails/interactions.ts
@@ -131,7 +131,11 @@ type Interactions = {
otel_experience_used: {},
otel_experience_toggled: {
value: ('on'| 'off')
- }
+ },
+ native_histogram_examples_closed: {},
+ native_histogram_example_clicked: {
+ metric: string;
+ },
};
const PREFIX = 'grafana_explore_metrics_';
diff --git a/public/img/native-histograms/DarkModeHeatmapClassicHistogram.png b/public/img/native-histograms/DarkModeHeatmapClassicHistogram.png
new file mode 100644
index 00000000000..df27290a806
Binary files /dev/null and b/public/img/native-histograms/DarkModeHeatmapClassicHistogram.png differ
diff --git a/public/img/native-histograms/DarkModeHeatmapNativeHistogram.png b/public/img/native-histograms/DarkModeHeatmapNativeHistogram.png
new file mode 100644
index 00000000000..cc2b7c4e73c
Binary files /dev/null and b/public/img/native-histograms/DarkModeHeatmapNativeHistogram.png differ
diff --git a/public/img/native-histograms/DarkModeHistogramClassicHistogram.png b/public/img/native-histograms/DarkModeHistogramClassicHistogram.png
new file mode 100644
index 00000000000..0d9bcc27f8c
Binary files /dev/null and b/public/img/native-histograms/DarkModeHistogramClassicHistogram.png differ
diff --git a/public/img/native-histograms/DarkModeHistogramNativehistogram.png b/public/img/native-histograms/DarkModeHistogramNativehistogram.png
new file mode 100644
index 00000000000..ec4512312fc
Binary files /dev/null and b/public/img/native-histograms/DarkModeHistogramNativehistogram.png differ
diff --git a/public/img/native-histograms/LightModeHeatmapClassicHistogram.png b/public/img/native-histograms/LightModeHeatmapClassicHistogram.png
new file mode 100644
index 00000000000..3f4c08afcc7
Binary files /dev/null and b/public/img/native-histograms/LightModeHeatmapClassicHistogram.png differ
diff --git a/public/img/native-histograms/LightModeHeatmapNativeHistogram.png b/public/img/native-histograms/LightModeHeatmapNativeHistogram.png
new file mode 100644
index 00000000000..8737db3a8cc
Binary files /dev/null and b/public/img/native-histograms/LightModeHeatmapNativeHistogram.png differ
diff --git a/public/img/native-histograms/LightModeHistogramClassicHistogram.png b/public/img/native-histograms/LightModeHistogramClassicHistogram.png
new file mode 100644
index 00000000000..4c1bcd9e671
Binary files /dev/null and b/public/img/native-histograms/LightModeHistogramClassicHistogram.png differ
diff --git a/public/img/native-histograms/LightModeHistogramNativeHistogram.png b/public/img/native-histograms/LightModeHistogramNativeHistogram.png
new file mode 100644
index 00000000000..539841315c8
Binary files /dev/null and b/public/img/native-histograms/LightModeHistogramNativeHistogram.png differ
diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json
index 9f2a6569ae2..ae10eb7c4e2 100644
--- a/public/locales/en-US/grafana.json
+++ b/public/locales/en-US/grafana.json
@@ -3345,9 +3345,24 @@
},
"metric-select": {
"filter-by": "Filter by",
+ "native-histogram": "Native Histogram",
"new-badge": "New",
"otel-switch": "This switch enables filtering by OTel resources for OTel native data sources."
},
+ "native-histogram-banner": {
+ "ch-heatmap": "Classic Histogram displayed as heatmap:",
+ "ch-histogram": "Classic Histogram displayed as histogram:",
+ "click-histogram": "Click any of the native histograms below to explore them:",
+ "hide-examples": "Hide examples",
+ "learn-more": "Learn more",
+ "metric-examples": "",
+ "nh-heatmap": "Native Histogram displayed as heatmap:",
+ "nh-histogram": "Native Histogram displayed as histogram:",
+ "now": "Now:",
+ "previously": "Previously:",
+ "see-examples": "> See examples",
+ "sentence": "Prometheus native histograms offer high resolution, high precision, simple usage in instrumentation and a way to combine and manipulate histograms in queries and in Grafana."
+ },
"recent-metrics": {
"or-view-a-recent-exploration": "Or view a recent exploration"
},
diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json
index 118e80758e0..705aa03d6e9 100644
--- a/public/locales/pseudo-LOCALE/grafana.json
+++ b/public/locales/pseudo-LOCALE/grafana.json
@@ -3345,9 +3345,24 @@
},
"metric-select": {
"filter-by": "Fįľŧęř þy",
+ "native-histogram": "Ńäŧįvę Ħįşŧőģřäm",
"new-badge": "Ńęŵ",
"otel-switch": "Ŧĥįş şŵįŧčĥ ęʼnäþľęş ƒįľŧęřįʼnģ þy ØŦęľ řęşőūřčęş ƒőř ØŦęľ ʼnäŧįvę đäŧä şőūřčęş."
},
+ "native-histogram-banner": {
+ "ch-heatmap": "Cľäşşįč Ħįşŧőģřäm đįşpľäyęđ äş ĥęäŧmäp:",
+ "ch-histogram": "Cľäşşįč Ħįşŧőģřäm đįşpľäyęđ äş ĥįşŧőģřäm:",
+ "click-histogram": "Cľįčĸ äʼny őƒ ŧĥę ʼnäŧįvę ĥįşŧőģřämş þęľőŵ ŧő ęχpľőřę ŧĥęm:",
+ "hide-examples": "Ħįđę ęχämpľęş",
+ "learn-more": "Ŀęäřʼn mőřę",
+ "metric-examples": "",
+ "nh-heatmap": "Ńäŧįvę Ħįşŧőģřäm đįşpľäyęđ äş ĥęäŧmäp:",
+ "nh-histogram": "Ńäŧįvę Ħįşŧőģřäm đįşpľäyęđ äş ĥįşŧőģřäm:",
+ "now": "Ńőŵ:",
+ "previously": "Přęvįőūşľy:",
+ "see-examples": "> Ŝęę ęχämpľęş",
+ "sentence": "Přőmęŧĥęūş ʼnäŧįvę ĥįşŧőģřämş őƒƒęř ĥįģĥ řęşőľūŧįőʼn, ĥįģĥ přęčįşįőʼn, şįmpľę ūşäģę įʼn įʼnşŧřūmęʼnŧäŧįőʼn äʼnđ ä ŵäy ŧő čőmþįʼnę äʼnđ mäʼnįpūľäŧę ĥįşŧőģřämş įʼn qūęřįęş äʼnđ įʼn Ğřäƒäʼnä."
+ },
"recent-metrics": {
"or-view-a-recent-exploration": "Øř vįęŵ ä řęčęʼnŧ ęχpľőřäŧįőʼn"
},