Recent dashboards: Add experimental toggle (#116121)

* Add experimentRecentlyViewedDashboards toggle

* Emit dashboards_browse_list_viewed event

* Move feature toggle to parent

* merge
This commit is contained in:
Alex Khomenko
2026-01-13 17:22:20 +02:00
committed by GitHub
parent fe5aa3e281
commit ec1ace398e
6 changed files with 53 additions and 8 deletions
+5
View File
@@ -984,6 +984,11 @@ export interface FeatureToggles {
*/
recentlyViewedDashboards?: boolean;
/**
* A/A test for recently viewed dashboards feature
* @default false
*/
experimentRecentlyViewedDashboards?: boolean;
/**
* Enable configuration of alert enrichments in Grafana Cloud.
* @default false
*/
+9
View File
@@ -1625,6 +1625,15 @@ var (
FrontendOnly: true,
Expression: "false",
},
{
Name: "experimentRecentlyViewedDashboards",
Description: "A/A test for recently viewed dashboards feature",
Stage: FeatureStageExperimental,
Owner: grafanaFrontendSearchNavOrganise,
FrontendOnly: true,
HideFromDocs: true,
Expression: "false",
},
{
Name: "alertEnrichment",
Description: "Enable configuration of alert enrichments in Grafana Cloud.",
+1
View File
@@ -223,6 +223,7 @@ kubernetesAuthnMutation,experimental,@grafana/identity-access-team,false,false,f
kubernetesExternalGroupMapping,experimental,@grafana/identity-access-team,false,false,false
restoreDashboards,experimental,@grafana/grafana-search-navigate-organise,false,false,false
recentlyViewedDashboards,experimental,@grafana/grafana-search-navigate-organise,false,false,true
experimentRecentlyViewedDashboards,experimental,@grafana/grafana-search-navigate-organise,false,false,true
alertEnrichment,experimental,@grafana/alerting-squad,false,false,false
alertEnrichmentMultiStep,experimental,@grafana/alerting-squad,false,false,false
alertEnrichmentConditional,experimental,@grafana/alerting-squad,false,false,false
1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
223 kubernetesExternalGroupMapping experimental @grafana/identity-access-team false false false
224 restoreDashboards experimental @grafana/grafana-search-navigate-organise false false false
225 recentlyViewedDashboards experimental @grafana/grafana-search-navigate-organise false false true
226 experimentRecentlyViewedDashboards experimental @grafana/grafana-search-navigate-organise false false true
227 alertEnrichment experimental @grafana/alerting-squad false false false
228 alertEnrichmentMultiStep experimental @grafana/alerting-squad false false false
229 alertEnrichmentConditional experimental @grafana/alerting-squad false false false
+15
View File
@@ -1365,6 +1365,21 @@
"hideFromDocs": true
}
},
{
"metadata": {
"name": "experimentRecentlyViewedDashboards",
"resourceVersion": "1768214542023",
"creationTimestamp": "2026-01-12T10:42:22Z"
},
"spec": {
"description": "A/A test for recently viewed dashboards feature",
"stage": "experimental",
"codeowner": "@grafana/grafana-search-navigate-organise",
"frontend": true,
"hideFromDocs": true,
"expression": "false"
}
},
{
"metadata": {
"name": "exploreLogsAggregatedMetrics",
@@ -1,11 +1,12 @@
import { css } from '@emotion/css';
import { memo, useEffect, useMemo } from 'react';
import { memo, useEffect, useMemo, useRef } from 'react';
import { useLocation, useParams } from 'react-router-dom-v5-compat';
import AutoSizer from 'react-virtualized-auto-sizer';
import { GrafanaTheme2 } from '@grafana/data';
import { Trans } from '@grafana/i18n';
import { config, reportInteraction } from '@grafana/runtime';
import { evaluateBooleanFlag } from '@grafana/runtime/internal';
import { LinkButton, FilterInput, useStyles2, Text, Stack } from '@grafana/ui';
import { useGetFolderQueryFacade, useUpdateFolder } from 'app/api/clients/folder/v1beta1/hooks';
import { Page } from 'app/core/components/Page/Page';
@@ -44,6 +45,7 @@ const BrowseDashboardsPage = memo(({ queryParams }: { queryParams: Record<string
const location = useLocation();
const search = useMemo(() => new URLSearchParams(location.search), [location.search]);
const { isReadOnlyRepo, repoType } = useGetResourceRepositoryView({ folderName: folderUID });
const isRecentlyViewedEnabled = !folderUID && evaluateBooleanFlag('recentlyViewedDashboards', false);
useEffect(() => {
stateManager.initStateFromUrl(folderUID);
@@ -73,6 +75,23 @@ const BrowseDashboardsPage = memo(({ queryParams }: { queryParams: Record<string
}
}, [isSearching, searchState.result, stateManager]);
// Emit exposure event for A/A test once when page loads
const hasEmittedExposureEvent = useRef(false);
useEffect(() => {
if (!isRecentlyViewedEnabled || hasEmittedExposureEvent.current) {
return;
}
hasEmittedExposureEvent.current = true;
const isExperimentTreatment = evaluateBooleanFlag('experimentRecentlyViewedDashboards', false);
reportInteraction('dashboards_browse_list_viewed', {
experiment_dashboard_list_recently_viewed: isExperimentTreatment ? 'treatment' : 'control',
has_recently_viewed_component: isExperimentTreatment,
});
}, [isRecentlyViewedEnabled]);
const { data: folderDTO } = useGetFolderQueryFacade(folderUID);
const [saveFolder] = useUpdateFolder();
const navModel = useMemo(() => {
@@ -179,8 +198,8 @@ const BrowseDashboardsPage = memo(({ queryParams }: { queryParams: Record<string
>
<Page.Contents className={styles.pageContents}>
<ProvisionedFolderPreviewBanner queryParams={queryParams} />
{/* only show recently viewed dashboards when in root */}
{!folderUID && <RecentlyViewedDashboards />}
{/* only show recently viewed dashboards when in root and flag is enabled */}
{isRecentlyViewedEnabled && <RecentlyViewedDashboards />}
<div>
<FilterInput
placeholder={getSearchPlaceholder(searchState.includePanels)}
@@ -5,7 +5,6 @@ import { useAsyncRetry } from 'react-use';
import { GrafanaTheme2, store } from '@grafana/data';
import { t, Trans } from '@grafana/i18n';
import { reportInteraction } from '@grafana/runtime';
import { evaluateBooleanFlag } from '@grafana/runtime/internal';
import { Button, CollapsableSection, Spinner, Stack, Text, useStyles2, Grid } from '@grafana/ui';
import { contextSrv } from 'app/core/services/context_srv';
import { useDashboardLocationInfo } from 'app/features/search/hooks/useDashboardLocationInfo';
@@ -28,9 +27,6 @@ export function RecentlyViewedDashboards() {
retry,
error,
} = useAsyncRetry(async () => {
if (!evaluateBooleanFlag('recentlyViewedDashboards', false)) {
return [];
}
return getRecentlyViewedDashboards(MAX_RECENT);
}, []);
const { foldersByUid } = useDashboardLocationInfo(recentDashboards.length > 0);
@@ -48,7 +44,7 @@ export function RecentlyViewedDashboards() {
setIsOpen(!isOpen);
};
if (!evaluateBooleanFlag('recentlyViewedDashboards', false) || recentDashboards.length === 0) {
if (recentDashboards.length === 0) {
return null;
}