mirror of
https://github.com/grafana/grafana.git
synced 2026-02-03 20:49:50 -05:00
Remove dashboardSceneSolo and dashboardSceneForViewers feature flags (#117083)
* Remove dashboardSceneSolo and dashboardSceneForViewers feature flags * e2e updates Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
2074778af5
commit
58bf5a1ba2
19 changed files with 133 additions and 380 deletions
|
|
@ -35,8 +35,7 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general-
|
|||
| `awsAsyncQueryCaching` | Enable caching for async queries for Redshift and Athena. Requires that the datasource has caching and async query support enabled | Yes |
|
||||
| `dashgpt` | Enable AI powered features in dashboards | Yes |
|
||||
| `kubernetesDashboards` | Use the kubernetes API in the frontend for dashboards | Yes |
|
||||
| `dashboardSceneForViewers` | Enables dashboard rendering using Scenes for viewer roles | Yes |
|
||||
| `dashboardSceneSolo` | Enables rendering dashboards using scenes for solo panels | Yes |
|
||||
| `annotationPermissionUpdate` | Change the way annotation permissions work by scoping them to folders and dashboards. | Yes |
|
||||
| `dashboardScene` | Enables dashboard rendering using scenes for all roles | Yes |
|
||||
| `alertingQueryOptimization` | Optimizes eligible queries in order to reduce load on datasources | |
|
||||
| `cloudWatchNewLabelParsing` | Updates CloudWatch label parsing to be more accurate | Yes |
|
||||
|
|
|
|||
|
|
@ -280,7 +280,7 @@ You can also update these parameters in the [image rendering configuration](http
|
|||
The following example shows a link to a server-side rendered PNG:
|
||||
|
||||
```bash
|
||||
https://play.grafana.org/render/d-solo/ktMs4D6Mk?from=2024-09-03T11:55:44.442Z&to=2024-09-03T17:55:44.442Z&panelId=panel-13&__feature.dashboardSceneSolo&width=1000&height=500&tz=UTC
|
||||
https://play.grafana.org/render/d-solo/ktMs4D6Mk?from=2024-09-03T11:55:44.442Z&to=2024-09-03T17:55:44.442Z&panelId=panel-13&__feature.dashboardScene&width=1000&height=500&tz=UTC
|
||||
```
|
||||
|
||||
### Share an embed
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ test.describe(
|
|||
test('Can view solo panel in scenes', async ({ page, selectors }) => {
|
||||
// open Panel Tests - Graph NG
|
||||
const soloPanelUrl = selectors.pages.SoloPanel.url(
|
||||
'TkZXxlNG3/panel-tests-graph-ng?orgId=1&from=1699954597665&to=1699956397665&panelId=54&__feature.dashboardSceneSolo=true'
|
||||
'TkZXxlNG3/panel-tests-graph-ng?orgId=1&from=1699954597665&to=1699956397665&panelId=54&__feature.dashboardScene=true'
|
||||
);
|
||||
await page.goto(soloPanelUrl);
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ test.describe(
|
|||
test('Can view solo repeated panel in scenes', async ({ page, selectors }) => {
|
||||
// open Panel Tests - Graph NG
|
||||
const soloPanelUrl = selectors.pages.SoloPanel.url(
|
||||
'templating-repeating-panels/templating-repeating-panels?orgId=1&from=1699934989607&to=1699956589607&panelId=A$panel-2&__feature.dashboardSceneSolo=true'
|
||||
'templating-repeating-panels/templating-repeating-panels?orgId=1&from=1699934989607&to=1699956589607&panelId=A$panel-2&__feature.dashboardScene=true'
|
||||
);
|
||||
await page.goto(soloPanelUrl);
|
||||
|
||||
|
|
@ -51,7 +51,7 @@ test.describe(
|
|||
test('Can view solo in repeated row and panel in scenes', async ({ page, selectors }) => {
|
||||
// open Panel Tests - Graph NG
|
||||
const soloPanelUrl = selectors.pages.SoloPanel.url(
|
||||
'Repeating-rows-uid/repeating-rows?orgId=1&var-server=A&var-server=B&var-server=D&var-pod=1&var-pod=2&var-pod=3&panelId=B$2$panel-2&__feature.dashboardSceneSolo=true'
|
||||
'Repeating-rows-uid/repeating-rows?orgId=1&var-server=A&var-server=B&var-server=D&var-pod=1&var-pod=2&var-pod=3&panelId=B$2$panel-2&__feature.dashboardScene=true'
|
||||
);
|
||||
await page.goto(soloPanelUrl);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,21 +11,28 @@ describe('Solo Route', () => {
|
|||
|
||||
cy.get('canvas').should('have.length', 6);
|
||||
});
|
||||
});
|
||||
|
||||
// Scenes solo panel tests - these require dashboardScene=true and a fresh app load
|
||||
describe('Solo Route (Scenes)', () => {
|
||||
beforeEach(() => {
|
||||
// Override the old-arch default and enable scenes
|
||||
cy.setLocalStorage('grafana.featureToggles', 'dashboardScene=true');
|
||||
// Reload to pick up the new toggle before routes are initialized
|
||||
cy.reload();
|
||||
e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD'), false);
|
||||
});
|
||||
|
||||
it('Can view solo panel in scenes', () => {
|
||||
// open Panel Tests - Graph NG
|
||||
e2e.pages.SoloPanel.visit(
|
||||
'TkZXxlNG3/panel-tests-graph-ng?orgId=1&from=1699954597665&to=1699956397665&panelId=54&__feature.dashboardSceneSolo=true'
|
||||
);
|
||||
e2e.pages.SoloPanel.visit('TkZXxlNG3/panel-tests-graph-ng?orgId=1&from=1699954597665&to=1699956397665&panelId=54');
|
||||
|
||||
e2e.components.Panels.Panel.title('Interpolation: Step before').should('exist');
|
||||
cy.contains('uplot-main-div').should('not.exist');
|
||||
});
|
||||
|
||||
it('Can view solo repeated panel in scenes', () => {
|
||||
// open Panel Tests - Graph NG
|
||||
e2e.pages.SoloPanel.visit(
|
||||
'templating-repeating-panels/templating-repeating-panels?orgId=1&from=1699934989607&to=1699956589607&panelId=A$panel-2&__feature.dashboardSceneSolo=true'
|
||||
'templating-repeating-panels/templating-repeating-panels?orgId=1&from=1699934989607&to=1699956589607&panelId=A$panel-2'
|
||||
);
|
||||
|
||||
e2e.components.Panels.Panel.title('server=A').should('exist');
|
||||
|
|
@ -33,9 +40,8 @@ describe('Solo Route', () => {
|
|||
});
|
||||
|
||||
it('Can view solo in repeated row and panel in scenes', () => {
|
||||
// open Panel Tests - Graph NG
|
||||
e2e.pages.SoloPanel.visit(
|
||||
'Repeating-rows-uid/repeating-rows?orgId=1&var-server=A&var-server=B&var-server=D&var-pod=1&var-pod=2&var-pod=3&panelId=B$2$panel-2&__feature.dashboardSceneSolo=true'
|
||||
'Repeating-rows-uid/repeating-rows?orgId=1&var-server=A&var-server=B&var-server=D&var-pod=1&var-pod=2&var-pod=3&panelId=B$2$panel-2'
|
||||
);
|
||||
|
||||
e2e.components.Panels.Panel.title('server = B, pod = Rob').should('exist');
|
||||
|
|
|
|||
|
|
@ -2174,11 +2174,6 @@
|
|||
"count": 1
|
||||
}
|
||||
},
|
||||
"public/app/features/dashboard/containers/DashboardPageProxy.tsx": {
|
||||
"@typescript-eslint/consistent-type-assertions": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"public/app/features/dashboard/containers/PublicDashboardPage.tsx": {
|
||||
"@typescript-eslint/consistent-type-assertions": {
|
||||
"count": 1
|
||||
|
|
|
|||
|
|
@ -364,15 +364,10 @@ export interface FeatureToggles {
|
|||
*/
|
||||
alertmanagerRemotePrimary?: boolean;
|
||||
/**
|
||||
* Enables dashboard rendering using Scenes for viewer roles
|
||||
* Change the way annotation permissions work by scoping them to folders and dashboards.
|
||||
* @default true
|
||||
*/
|
||||
dashboardSceneForViewers?: boolean;
|
||||
/**
|
||||
* Enables rendering dashboards using scenes for solo panels
|
||||
* @default true
|
||||
*/
|
||||
dashboardSceneSolo?: boolean;
|
||||
annotationPermissionUpdate?: boolean;
|
||||
/**
|
||||
* Enables dashboard rendering using scenes for all roles
|
||||
* @default true
|
||||
|
|
|
|||
|
|
@ -324,7 +324,7 @@ function overrideFeatureTogglesFromUrl(config: GrafanaBootConfig) {
|
|||
|
||||
// Although most flags can not be changed from the URL in production,
|
||||
// some of them are safe (and useful!) to change dynamically from the browser URL
|
||||
const safeRuntimeFeatureFlags = new Set(['queryServiceFromUI', 'dashboardSceneSolo']);
|
||||
const safeRuntimeFeatureFlags = new Set(['queryServiceFromUI']);
|
||||
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
params.forEach((value, key) => {
|
||||
|
|
|
|||
|
|
@ -553,20 +553,12 @@ var (
|
|||
Expression: "false",
|
||||
},
|
||||
{
|
||||
Name: "dashboardSceneForViewers",
|
||||
Description: "Enables dashboard rendering using Scenes for viewer roles",
|
||||
Stage: FeatureStageGeneralAvailability,
|
||||
FrontendOnly: true,
|
||||
Owner: grafanaDashboardsSquad,
|
||||
Expression: "true", // enabled by default
|
||||
},
|
||||
{
|
||||
Name: "dashboardSceneSolo",
|
||||
Description: "Enables rendering dashboards using scenes for solo panels",
|
||||
Stage: FeatureStageGeneralAvailability,
|
||||
FrontendOnly: true,
|
||||
Owner: grafanaDashboardsSquad,
|
||||
Expression: "true", // enabled by default
|
||||
Name: "annotationPermissionUpdate",
|
||||
Description: "Change the way annotation permissions work by scoping them to folders and dashboards.",
|
||||
Stage: FeatureStageGeneralAvailability,
|
||||
RequiresDevMode: false,
|
||||
Expression: "true", // enabled by default
|
||||
Owner: identityAccessTeam,
|
||||
},
|
||||
{
|
||||
Name: "dashboardScene",
|
||||
|
|
|
|||
63
pkg/services/featuremgmt/toggles_gen.csv
generated
63
pkg/services/featuremgmt/toggles_gen.csv
generated
|
|
@ -23,7 +23,7 @@ Created,Name,Stage,Owner,requiresDevMode,RequiresRestart,FrontendOnly
|
|||
2023-04-12,disableSSEDataplane,experimental,@grafana/grafana-datasources-core-services,false,false,false
|
||||
2023-04-03,renderAuthJWT,preview,@grafana/grafana-operator-experience-squad,false,false,false
|
||||
2023-06-06,refactorVariablesTimeRange,preview,@grafana/dashboards-squad,false,false,false
|
||||
2023-05-04,faroDatasourceSelector,preview,@grafana/app-o11y,false,false,true
|
||||
2023-05-05,faroDatasourceSelector,preview,@grafana/app-o11y,false,false,true
|
||||
2023-04-24,enableDatagridEditing,preview,@grafana/dataviz-squad,false,false,false
|
||||
2023-07-12,logsExploreTableVisualisation,GA,@grafana/observability-logs,false,false,true
|
||||
2023-07-06,awsDatasourcesTempCredentials,GA,@grafana/aws-datasources,false,false,false
|
||||
|
|
@ -43,11 +43,11 @@ Created,Name,Stage,Owner,requiresDevMode,RequiresRestart,FrontendOnly
|
|||
2023-09-19,lokiRunQueriesInParallel,privatePreview,@grafana/oss-big-tent,false,false,false
|
||||
2023-09-28,externalServiceAccounts,preview,@grafana/identity-access-team,false,false,false
|
||||
2023-12-05,kubernetesSnapshots,experimental,@grafana/grafana-app-platform-squad,false,true,false
|
||||
2025-06-25,kubernetesLibraryPanels,experimental,@grafana/grafana-app-platform-squad,false,true,false
|
||||
2025-06-26,kubernetesLibraryPanels,experimental,@grafana/grafana-app-platform-squad,false,true,false
|
||||
2024-06-05,kubernetesDashboards,GA,@grafana/dashboards-squad,false,false,false
|
||||
2025-07-31,kubernetesShortURLs,experimental,@grafana/grafana-app-platform-squad,false,true,false
|
||||
2025-08-01,kubernetesShortURLs,experimental,@grafana/grafana-app-platform-squad,false,true,false
|
||||
2025-08-29,useKubernetesShortURLsAPI,experimental,@grafana/sharing-squad,false,false,true
|
||||
2025-07-31,kubernetesAlertingRules,experimental,@grafana/alerting-squad,false,true,false
|
||||
2025-08-01,kubernetesAlertingRules,experimental,@grafana/alerting-squad,false,true,false
|
||||
2025-08-29,kubernetesCorrelations,experimental,@grafana/datapro,false,true,false
|
||||
2025-12-09,kubernetesUnifiedStorageQuotas,experimental,@grafana/search-and-storage,false,true,false
|
||||
2025-10-16,kubernetesLogsDrilldown,experimental,@grafana/observability-logs,false,true,false
|
||||
|
|
@ -68,8 +68,7 @@ Created,Name,Stage,Owner,requiresDevMode,RequiresRestart,FrontendOnly
|
|||
2025-11-13,alertingUIUseBackendFilters,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-11-24,alertingUIUseFullyCompatBackendFilters,experimental,@grafana/alerting-squad,false,false,false
|
||||
2023-10-30,alertmanagerRemotePrimary,experimental,@grafana/alerting-squad,false,false,false
|
||||
2023-11-02,dashboardSceneForViewers,GA,@grafana/dashboards-squad,false,false,true
|
||||
2024-02-11,dashboardSceneSolo,GA,@grafana/dashboards-squad,false,false,true
|
||||
2023-10-31,annotationPermissionUpdate,GA,@grafana/identity-access-team,false,false,false
|
||||
2023-11-13,dashboardScene,GA,@grafana/dashboards-squad,false,false,true
|
||||
2024-10-23,dashboardNewLayouts,preview,@grafana/dashboards-squad,false,false,false
|
||||
2025-08-29,dashboardUndoRedo,experimental,@grafana/dashboards-squad,false,false,true
|
||||
|
|
@ -88,10 +87,10 @@ Created,Name,Stage,Owner,requiresDevMode,RequiresRestart,FrontendOnly
|
|||
2024-01-18,jitterAlertRulesWithinGroups,preview,@grafana/alerting-squad,false,true,false
|
||||
2025-12-29,auditLoggingAppPlatform,experimental,@grafana/grafana-operator-experience-squad,false,true,false
|
||||
2025-03-19,secretsManagementAppPlatform,experimental,@grafana/grafana-operator-experience-squad,false,false,false
|
||||
2025-07-31,secretsManagementAppPlatformUI,experimental,@grafana/grafana-operator-experience-squad,false,false,false
|
||||
2025-08-01,secretsManagementAppPlatformUI,experimental,@grafana/grafana-operator-experience-squad,false,false,false
|
||||
2024-01-23,alertingSaveStatePeriodic,privatePreview,@grafana/alerting-squad,false,false,false
|
||||
2025-01-27,alertingSaveStateCompressed,preview,@grafana/alerting-squad,false,false,false
|
||||
2024-11-26,scopeApi,experimental,@grafana/grafana-app-platform-squad,false,false,false
|
||||
2024-11-27,scopeApi,experimental,@grafana/grafana-app-platform-squad,false,false,false
|
||||
2025-07-31,useScopeSingleNodeEndpoint,experimental,@grafana/grafana-operator-experience-squad,false,false,true
|
||||
2025-08-29,useMultipleScopeNodesEndpoint,experimental,@grafana/grafana-operator-experience-squad,false,false,true
|
||||
2024-11-11,logQLScope,privatePreview,@grafana/oss-big-tent,false,false,false
|
||||
|
|
@ -132,13 +131,13 @@ Created,Name,Stage,Owner,requiresDevMode,RequiresRestart,FrontendOnly
|
|||
2024-09-11,alertingFilterV2,experimental,@grafana/alerting-squad,false,false,false
|
||||
2024-08-09,dataplaneAggregator,experimental,@grafana/grafana-app-platform-squad,false,true,false
|
||||
2024-08-30,newFiltersUI,GA,@grafana/dashboards-squad,false,false,false
|
||||
2025-07-31,vizActionsAuth,preview,@grafana/dataviz-squad,false,false,true
|
||||
2025-08-01,vizActionsAuth,preview,@grafana/dataviz-squad,false,false,true
|
||||
2024-09-27,alertingPrometheusRulesPrimary,experimental,@grafana/alerting-squad,false,false,true
|
||||
2024-08-29,exploreLogsShardSplitting,experimental,@grafana/observability-logs,false,false,true
|
||||
2024-08-29,exploreLogsAggregatedMetrics,experimental,@grafana/observability-logs,false,false,true
|
||||
2024-10-14,appPlatformGrpcClientAuth,experimental,@grafana/identity-access-team,false,false,false
|
||||
2024-09-09,groupAttributeSync,privatePreview,@grafana/identity-access-team,false,false,false
|
||||
2024-09-25,alertingQueryAndExpressionsStepMode,GA,@grafana/alerting-squad,false,false,true
|
||||
2024-09-26,alertingQueryAndExpressionsStepMode,GA,@grafana/alerting-squad,false,false,true
|
||||
2024-09-17,improvedExternalSessionHandling,GA,@grafana/identity-access-team,false,false,false
|
||||
2024-09-23,useSessionStorageForRedirection,GA,@grafana/identity-access-team,false,false,false
|
||||
2024-09-26,rolePickerDrawer,experimental,@grafana/identity-access-team,false,false,false
|
||||
|
|
@ -146,10 +145,10 @@ Created,Name,Stage,Owner,requiresDevMode,RequiresRestart,FrontendOnly
|
|||
2024-10-04,pluginsSriChecks,GA,@grafana/plugins-platform-backend,false,false,false
|
||||
2024-10-17,unifiedStorageBigObjectsSupport,experimental,@grafana/search-and-storage,false,false,false
|
||||
2024-10-22,timeRangeProvider,experimental,@grafana/grafana-frontend-platform,false,false,false
|
||||
2025-11-04,timeRangePan,GA,@grafana/dataviz-squad,false,false,true
|
||||
2025-11-05,timeRangePan,GA,@grafana/dataviz-squad,false,false,true
|
||||
2025-11-20,newTimeRangeZoomShortcuts,GA,@grafana/dataviz-squad,false,false,true
|
||||
2024-10-24,azureMonitorDisableLogLimit,GA,@grafana/partner-datasources,false,false,false
|
||||
2024-12-19,playlistsReconciler,experimental,@grafana/grafana-app-platform-squad,false,true,false
|
||||
2024-12-20,playlistsReconciler,experimental,@grafana/grafana-app-platform-squad,false,true,false
|
||||
2024-11-14,passwordlessMagicLinkAuthentication,experimental,@grafana/identity-access-team,false,false,false
|
||||
2024-12-18,prometheusSpecialCharsInLabelValues,experimental,@grafana/oss-big-tent,false,false,true
|
||||
2024-11-05,enableExtensionsAdminPage,experimental,@grafana/plugins-platform-backend,false,true,false
|
||||
|
|
@ -161,7 +160,7 @@ Created,Name,Stage,Owner,requiresDevMode,RequiresRestart,FrontendOnly
|
|||
2025-07-23,alertingAIFeedback,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-07-16,alertingAIImproveAlertRules,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-07-16,alertingAIGenTemplates,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-07-31,alertingEnrichmentPerRule,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-08-01,alertingEnrichmentPerRule,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-08-29,alertingEnrichmentAssistantInvestigations,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-07-16,alertingAIAnalyzeCentralStateHistory,experimental,@grafana/alerting-squad,false,false,false
|
||||
2024-11-22,alertingNotificationsStepMode,GA,@grafana/alerting-squad,false,false,true
|
||||
|
|
@ -199,7 +198,7 @@ Created,Name,Stage,Owner,requiresDevMode,RequiresRestart,FrontendOnly
|
|||
2025-04-09,unifiedNavbars,GA,@grafana/plugins-platform-backend,false,false,true
|
||||
2025-04-07,logsPanelControls,preview,@grafana/observability-logs,false,false,true
|
||||
2025-04-09,metricsFromProfiles,experimental,@grafana/observability-traces-and-profiling,false,false,true
|
||||
2025-07-31,grafanaAssistantInProfilesDrilldown,GA,@grafana/observability-traces-and-profiling,false,false,true
|
||||
2025-08-01,grafanaAssistantInProfilesDrilldown,GA,@grafana/observability-traces-and-profiling,false,false,true
|
||||
2025-07-15,tempoAlerting,experimental,@grafana/observability-traces-and-profiling,false,false,false
|
||||
2025-04-16,pluginsAutoUpdate,experimental,@grafana/plugins-platform-backend,false,false,false
|
||||
2025-04-22,alertingListViewV2PreviewToggle,privatePreview,@grafana/alerting-squad,false,false,true
|
||||
|
|
@ -207,12 +206,12 @@ Created,Name,Stage,Owner,requiresDevMode,RequiresRestart,FrontendOnly
|
|||
2025-04-24,alertingBulkActionsInUI,GA,@grafana/alerting-squad,false,false,true
|
||||
2025-06-18,kubernetesAuthzApis,deprecated,@grafana/identity-access-team,false,false,false
|
||||
2025-08-29,kubernetesAuthZHandlerRedirect,experimental,@grafana/identity-access-team,false,false,false
|
||||
2025-07-31,kubernetesAuthzResourcePermissionApis,experimental,@grafana/identity-access-team,false,false,false
|
||||
2025-08-01,kubernetesAuthzResourcePermissionApis,experimental,@grafana/identity-access-team,false,false,false
|
||||
2025-10-13,kubernetesAuthzZanzanaSync,experimental,@grafana/identity-access-team,false,false,false
|
||||
2026-01-12,kubernetesAuthzCoreRolesApi,experimental,@grafana/identity-access-team,false,false,false
|
||||
2026-01-15,kubernetesAuthzGlobalRolesApi,experimental,@grafana/identity-access-team,false,false,false
|
||||
2026-01-12,kubernetesAuthzRolesApi,experimental,@grafana/identity-access-team,false,false,false
|
||||
2026-01-14,kubernetesAuthzTeamLBACRuleApi,experimental,@grafana/identity-access-team,false,false,false
|
||||
2026-01-15,kubernetesAuthzTeamLBACRuleApi,experimental,@grafana/identity-access-team,false,false,false
|
||||
2026-01-12,kubernetesAuthzRoleBindingsApi,experimental,@grafana/identity-access-team,false,false,false
|
||||
2025-07-25,kubernetesAuthnMutation,experimental,@grafana/identity-access-team,false,false,false
|
||||
2025-11-25,kubernetesExternalGroupMapping,experimental,@grafana/identity-access-team,false,false,false
|
||||
|
|
@ -220,16 +219,16 @@ Created,Name,Stage,Owner,requiresDevMode,RequiresRestart,FrontendOnly
|
|||
2025-12-10,recentlyViewedDashboards,experimental,@grafana/grafana-search-navigate-organise,false,false,true
|
||||
2026-01-13,experimentRecentlyViewedDashboards,experimental,@grafana/grafana-search-navigate-organise,false,false,true
|
||||
2025-06-06,alertEnrichment,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-07-31,alertEnrichmentMultiStep,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-07-31,alertEnrichmentConditional,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-08-01,alertEnrichmentMultiStep,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-08-01,alertEnrichmentConditional,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-06-10,alertingImportAlertmanagerAPI,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-07-31,alertingImportAlertmanagerUI,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-08-01,alertingImportAlertmanagerUI,experimental,@grafana/alerting-squad,false,false,false
|
||||
2026-01-26,alertingDisableDMAinUI,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-07-15,sharingDashboardImage,GA,@grafana/sharing-squad,false,false,true
|
||||
2025-06-17,preferLibraryPanelTitle,privatePreview,@grafana/dashboards-squad,false,false,false
|
||||
2025-06-24,tabularNumbers,GA,@grafana/grafana-frontend-platform,false,false,false
|
||||
2025-06-25,newInfluxDSConfigPageDesign,privatePreview,@grafana/partner-datasources,false,false,false
|
||||
2025-06-29,enableAppChromeExtensions,experimental,@grafana/plugins-platform-backend,false,false,true
|
||||
2025-06-30,enableAppChromeExtensions,experimental,@grafana/plugins-platform-backend,false,false,true
|
||||
2025-10-13,enableDashboardEmptyExtensions,experimental,@grafana/dashboards-squad,false,false,true
|
||||
2025-07-03,foldersAppPlatformAPI,experimental,@grafana/grafana-search-navigate-organise,false,false,true
|
||||
2025-07-16,otelLogsFormatting,experimental,@grafana/observability-logs,false,false,true
|
||||
|
|
@ -237,23 +236,23 @@ Created,Name,Stage,Owner,requiresDevMode,RequiresRestart,FrontendOnly
|
|||
2025-07-18,unifiedStorageSearchDualReaderEnabled,experimental,@grafana/search-and-storage,false,false,false
|
||||
2025-07-31,dashboardLevelTimeMacros,experimental,@grafana/dashboards-squad,false,false,true
|
||||
2025-07-25,alertmanagerRemoteSecondaryWithRemoteState,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-07-31,restrictedPluginApis,experimental,@grafana/plugins-platform-backend,false,false,true
|
||||
2025-07-31,favoriteDatasources,experimental,@grafana/plugins-platform-backend,false,false,true
|
||||
2025-07-31,newLogContext,experimental,@grafana/observability-logs,false,false,true
|
||||
2025-07-31,newClickhouseConfigPageDesign,privatePreview,@grafana/partner-datasources,false,false,false
|
||||
2025-07-31,teamFolders,experimental,@grafana/grafana-search-navigate-organise,false,false,false
|
||||
2025-08-01,restrictedPluginApis,experimental,@grafana/plugins-platform-backend,false,false,true
|
||||
2025-08-01,favoriteDatasources,experimental,@grafana/plugins-platform-backend,false,false,true
|
||||
2025-08-01,newLogContext,experimental,@grafana/observability-logs,false,false,true
|
||||
2025-08-01,newClickhouseConfigPageDesign,privatePreview,@grafana/partner-datasources,false,false,false
|
||||
2025-08-01,teamFolders,experimental,@grafana/grafana-search-navigate-organise,false,false,false
|
||||
2025-10-22,interactiveLearning,preview,@grafana/pathfinder,false,false,false
|
||||
2025-07-31,alertingTriage,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-07-31,graphiteBackendMode,privatePreview,@grafana/partner-datasources,false,false,false
|
||||
2025-07-31,azureResourcePickerUpdates,GA,@grafana/partner-datasources,false,false,true
|
||||
2025-07-31,prometheusTypeMigration,experimental,@grafana/partner-datasources,false,true,false
|
||||
2025-07-31,pluginContainers,privatePreview,@grafana/plugins-platform-backend,false,true,false
|
||||
2025-08-01,alertingTriage,experimental,@grafana/alerting-squad,false,false,false
|
||||
2025-08-01,graphiteBackendMode,privatePreview,@grafana/partner-datasources,false,false,false
|
||||
2025-08-01,azureResourcePickerUpdates,GA,@grafana/partner-datasources,false,false,true
|
||||
2025-08-01,prometheusTypeMigration,experimental,@grafana/partner-datasources,false,true,false
|
||||
2025-08-01,pluginContainers,privatePreview,@grafana/plugins-platform-backend,false,true,false
|
||||
2025-08-29,cdnPluginsLoadFirst,experimental,@grafana/plugins-platform-backend,false,false,false
|
||||
2025-08-29,cdnPluginsUrls,experimental,@grafana/plugins-platform-backend,false,false,false
|
||||
2025-10-24,pluginInstallAPISync,experimental,@grafana/plugins-platform-backend,false,false,false
|
||||
2025-10-20,newGauge,preview,@grafana/dataviz-squad,false,false,true
|
||||
2025-11-12,newVizSuggestions,preview,@grafana/dataviz-squad,false,false,true
|
||||
2025-12-01,externalVizSuggestions,experimental,@grafana/dataviz-squad,false,false,true
|
||||
2025-12-02,externalVizSuggestions,experimental,@grafana/dataviz-squad,false,false,true
|
||||
2025-12-18,heatmapRowsAxisOptions,experimental,@grafana/dataviz-squad,false,false,true
|
||||
2025-10-17,preventPanelChromeOverflow,preview,@grafana/grafana-frontend-platform,false,false,true
|
||||
2025-10-31,jaegerEnableGrpcEndpoint,experimental,@grafana/oss-big-tent,false,false,false
|
||||
|
|
@ -271,7 +270,7 @@ Created,Name,Stage,Owner,requiresDevMode,RequiresRestart,FrontendOnly
|
|||
2025-11-21,lokiQueryLimitsContext,experimental,@grafana/observability-logs,false,false,true
|
||||
2025-11-19,rudderstackUpgrade,experimental,@grafana/grafana-frontend-platform,false,false,true
|
||||
2025-11-27,kubernetesAlertingHistorian,experimental,@grafana/alerting-squad,false,true,false
|
||||
2025-12-04,useMTPlugins,experimental,@grafana/plugins-platform-backend,false,false,true
|
||||
2025-12-05,useMTPlugins,experimental,@grafana/plugins-platform-backend,false,false,true
|
||||
2025-12-09,multiPropsVariables,experimental,@grafana/dashboards-squad,false,false,true
|
||||
2026-01-05,smoothingTransformation,experimental,@grafana/datapro,false,false,true
|
||||
2026-01-06,secretsManagementAppPlatformAwsKeeper,experimental,@grafana/grafana-operator-experience-squad,false,false,false
|
||||
|
|
|
|||
|
4
pkg/services/featuremgmt/toggles_gen.go
generated
4
pkg/services/featuremgmt/toggles_gen.go
generated
|
|
@ -231,6 +231,10 @@ const (
|
|||
// Enable Grafana to have a remote Alertmanager instance as the primary Alertmanager.
|
||||
FlagAlertmanagerRemotePrimary = "alertmanagerRemotePrimary"
|
||||
|
||||
// FlagAnnotationPermissionUpdate
|
||||
// Change the way annotation permissions work by scoping them to folders and dashboards.
|
||||
FlagAnnotationPermissionUpdate = "annotationPermissionUpdate"
|
||||
|
||||
// FlagDashboardNewLayouts
|
||||
// Enables new dashboard layouts
|
||||
FlagDashboardNewLayouts = "dashboardNewLayouts"
|
||||
|
|
|
|||
6
pkg/services/featuremgmt/toggles_gen.json
generated
6
pkg/services/featuremgmt/toggles_gen.json
generated
|
|
@ -1242,7 +1242,8 @@
|
|||
"metadata": {
|
||||
"name": "dashboardSceneForViewers",
|
||||
"resourceVersion": "1764664939750",
|
||||
"creationTimestamp": "2023-11-02T19:02:25Z"
|
||||
"creationTimestamp": "2023-11-02T19:02:25Z",
|
||||
"deletionTimestamp": "2026-01-29T16:02:04Z"
|
||||
},
|
||||
"spec": {
|
||||
"description": "Enables dashboard rendering using Scenes for viewer roles",
|
||||
|
|
@ -1256,7 +1257,8 @@
|
|||
"metadata": {
|
||||
"name": "dashboardSceneSolo",
|
||||
"resourceVersion": "1764664939750",
|
||||
"creationTimestamp": "2024-02-11T08:08:47Z"
|
||||
"creationTimestamp": "2024-02-11T08:08:47Z",
|
||||
"deletionTimestamp": "2026-01-29T16:02:04Z"
|
||||
},
|
||||
"spec": {
|
||||
"description": "Enables rendering dashboards using scenes for solo panels",
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ describe('ShareLinkTab', () => {
|
|||
config.appUrl = 'http://dashboards.grafana.com/grafana/';
|
||||
config.rendererAvailable = true;
|
||||
contextSrv.user.orgId = 1;
|
||||
config.featureToggles.dashboardSceneForViewers = true;
|
||||
config.featureToggles.dashboardScene = true;
|
||||
locationService.push('/d/dash-1?from=now-6h&to=now');
|
||||
});
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ describe('ShareLinkTab', () => {
|
|||
await screen.findByRole('link', { name: selectors.pages.SharePanelModal.linkToRenderedImage })
|
||||
).toHaveAttribute(
|
||||
'href',
|
||||
'http://dashboards.grafana.com/grafana/render/d-solo/dash-1?from=2019-02-11T13:00:00.000Z&to=2019-02-11T19:00:00.000Z&panelId=A$panel-12&__feature.dashboardSceneSolo=true&hideLogo=true&width=1000&height=500&tz=Pacific%2FEaster'
|
||||
'http://dashboards.grafana.com/grafana/render/d-solo/dash-1?from=2019-02-11T13:00:00.000Z&to=2019-02-11T19:00:00.000Z&panelId=A$panel-12&__feature.dashboardScene=true&hideLogo=true&width=1000&height=500&tz=Pacific%2FEaster'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ export class ShareLinkTab extends SceneObjectBase<ShareLinkTabState> implements
|
|||
delete imageQueryParams.viewPanel;
|
||||
imageQueryParams.panelId = panel.getPathId();
|
||||
// force solo route to use scenes
|
||||
imageQueryParams['__feature.dashboardSceneSolo'] = true;
|
||||
imageQueryParams['__feature.dashboardScene'] = true;
|
||||
}
|
||||
|
||||
// hide Grafana logo in the rendered image
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ const getIframeBuilder =
|
|||
params.set('panelId', editOrViewPanel);
|
||||
params.delete('editPanel');
|
||||
params.delete('viewPanel');
|
||||
params.set('__feature.dashboardSceneSolo', 'true');
|
||||
params.set('__feature.dashboardScene', 'true');
|
||||
|
||||
const soloUrl = getDashboardUrl({
|
||||
absolute: true,
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@ import { Dashboard, Panel, RowPanel } from '@grafana/schema';
|
|||
|
||||
import {
|
||||
isDashboardSceneEnabled,
|
||||
isDashboardSceneForViewersEnabled,
|
||||
isDashboardSceneSoloEnabled,
|
||||
isPublicDashboardsSceneEnabled,
|
||||
isValidLibraryPanelRef,
|
||||
hasLibraryPanelsInV1Dashboard,
|
||||
|
|
@ -413,40 +411,4 @@ describe('utils', () => {
|
|||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('isDashboardSceneForViewersEnabled', () => {
|
||||
it.each([
|
||||
{ dashboardSceneForViewers: true, dashboardNewLayouts: false, expected: true },
|
||||
{ dashboardSceneForViewers: false, dashboardNewLayouts: true, expected: true },
|
||||
{ dashboardSceneForViewers: true, dashboardNewLayouts: true, expected: true },
|
||||
{ dashboardSceneForViewers: false, dashboardNewLayouts: false, expected: false },
|
||||
])(
|
||||
'should return $expected when dashboardSceneForViewers=$dashboardSceneForViewers and dashboardNewLayouts=$dashboardNewLayouts',
|
||||
({ dashboardSceneForViewers, dashboardNewLayouts, expected }) => {
|
||||
config.featureToggles = {
|
||||
dashboardSceneForViewers,
|
||||
dashboardNewLayouts,
|
||||
};
|
||||
expect(isDashboardSceneForViewersEnabled()).toBe(expected);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('isDashboardSceneSoloEnabled', () => {
|
||||
it.each([
|
||||
{ dashboardSceneSolo: true, dashboardNewLayouts: false, expected: true },
|
||||
{ dashboardSceneSolo: false, dashboardNewLayouts: true, expected: true },
|
||||
{ dashboardSceneSolo: true, dashboardNewLayouts: true, expected: true },
|
||||
{ dashboardSceneSolo: false, dashboardNewLayouts: false, expected: false },
|
||||
])(
|
||||
'should return $expected when dashboardSceneSolo=$dashboardSceneSolo and dashboardNewLayouts=$dashboardNewLayouts',
|
||||
({ dashboardSceneSolo, dashboardNewLayouts, expected }) => {
|
||||
config.featureToggles = {
|
||||
dashboardSceneSolo,
|
||||
dashboardNewLayouts,
|
||||
};
|
||||
expect(isDashboardSceneSoloEnabled()).toBe(expected);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -502,11 +502,3 @@ export function isDashboardSceneEnabled(): boolean {
|
|||
export function isPublicDashboardsSceneEnabled(): boolean {
|
||||
return !!(config.featureToggles.publicDashboardsScene || config.featureToggles.dashboardNewLayouts);
|
||||
}
|
||||
|
||||
export function isDashboardSceneForViewersEnabled(): boolean {
|
||||
return !!(config.featureToggles.dashboardSceneForViewers || config.featureToggles.dashboardNewLayouts);
|
||||
}
|
||||
|
||||
export function isDashboardSceneSoloEnabled(): boolean {
|
||||
return !!(config.featureToggles.dashboardSceneSolo || config.featureToggles.dashboardNewLayouts);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,65 +3,11 @@ import { useParams } from 'react-router-dom-v5-compat';
|
|||
import { Props } from 'react-virtualized-auto-sizer';
|
||||
import { render } from 'test/test-utils';
|
||||
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { config, locationService } from '@grafana/runtime';
|
||||
import {
|
||||
HOME_DASHBOARD_CACHE_KEY,
|
||||
getDashboardScenePageStateManager,
|
||||
} from 'app/features/dashboard-scene/pages/DashboardScenePageStateManager';
|
||||
import {
|
||||
setupLoadDashboardMockReject,
|
||||
setupLoadDashboardRuntimeErrorMock,
|
||||
} from 'app/features/dashboard-scene/utils/test-utils';
|
||||
import { DashboardDTO, DashboardRoutes } from 'app/types/dashboard';
|
||||
|
||||
import { DashboardLoaderSrv, setDashboardLoaderSrv } from '../services/DashboardLoaderSrv';
|
||||
import { DashboardRoutes } from 'app/types/dashboard';
|
||||
|
||||
import DashboardPageProxy, { DashboardPageProxyProps } from './DashboardPageProxy';
|
||||
|
||||
const dashMock: DashboardDTO = {
|
||||
dashboard: {
|
||||
id: 1,
|
||||
annotations: {
|
||||
list: [],
|
||||
},
|
||||
uid: 'uid',
|
||||
title: 'title',
|
||||
panels: [],
|
||||
version: 1,
|
||||
schemaVersion: 1,
|
||||
},
|
||||
meta: {
|
||||
canEdit: false,
|
||||
created: 'Friday, 4 July 2025 07:56:41 GMT+05:30',
|
||||
},
|
||||
};
|
||||
|
||||
const homeMock = {
|
||||
...dashMock,
|
||||
dashboard: {
|
||||
...dashMock.dashboard,
|
||||
uid: '',
|
||||
title: 'Home',
|
||||
},
|
||||
};
|
||||
|
||||
const homeMockEditable = {
|
||||
...homeMock,
|
||||
meta: {
|
||||
...homeMock.meta,
|
||||
canEdit: true,
|
||||
},
|
||||
};
|
||||
|
||||
const dashMockEditable = {
|
||||
...dashMock,
|
||||
meta: {
|
||||
...dashMock.meta,
|
||||
canEdit: true,
|
||||
},
|
||||
};
|
||||
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
...jest.requireActual('@grafana/runtime'),
|
||||
getDataSourceSrv: jest.fn().mockReturnValue({
|
||||
|
|
@ -88,12 +34,6 @@ jest.mock('react-virtualized-auto-sizer', () => {
|
|||
});
|
||||
});
|
||||
|
||||
setDashboardLoaderSrv({
|
||||
loadDashboard: jest.fn().mockResolvedValue(dashMock),
|
||||
// disabling type checks since this is a test util
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
} as unknown as DashboardLoaderSrv);
|
||||
|
||||
jest.mock('react-router-dom-v5-compat', () => ({
|
||||
...jest.requireActual('react-router-dom-v5-compat'),
|
||||
useParams: jest.fn().mockReturnValue({}),
|
||||
|
|
@ -112,14 +52,53 @@ function setup(props: Partial<DashboardPageProxyProps> & { uid?: string }) {
|
|||
}
|
||||
|
||||
describe('DashboardPageProxy', () => {
|
||||
describe('when dashboardSceneForViewers feature toggle disabled', () => {
|
||||
describe('when dashboardScene feature toggle is enabled (default)', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
config.featureToggles.dashboardSceneForViewers = false;
|
||||
config.featureToggles.dashboardScene = true;
|
||||
});
|
||||
|
||||
it('home dashboard', async () => {
|
||||
getDashboardScenePageStateManager().setDashboardCache(HOME_DASHBOARD_CACHE_KEY, dashMock);
|
||||
it('should render DashboardScenePage for home route', async () => {
|
||||
setup({
|
||||
route: { routeName: DashboardRoutes.Home, component: () => null, path: '/' },
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryAllByTestId('dashboard-scene-page')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('should render DashboardScenePage for normal route with uid', async () => {
|
||||
setup({
|
||||
route: { routeName: DashboardRoutes.Normal, component: () => null, path: '/' },
|
||||
uid: 'abc-def',
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryAllByTestId('dashboard-scene-page')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('should render legacy DashboardPage when forceOld query param is set', async () => {
|
||||
setup({
|
||||
route: { routeName: DashboardRoutes.Normal, component: () => null, path: '/' },
|
||||
uid: 'abc-def',
|
||||
queryParams: { scenes: false },
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryAllByTestId('dashboard-scene-page')).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when dashboardScene feature toggle is disabled', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
config.featureToggles.dashboardScene = false;
|
||||
});
|
||||
|
||||
it('should render legacy DashboardPage for home route', async () => {
|
||||
setup({
|
||||
route: { routeName: DashboardRoutes.Home, component: () => null, path: '/' },
|
||||
});
|
||||
|
|
@ -129,9 +108,7 @@ describe('DashboardPageProxy', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('uid dashboard', async () => {
|
||||
getDashboardScenePageStateManager().setDashboardCache('abc-def', dashMock);
|
||||
|
||||
it('should render legacy DashboardPage for normal route with uid', async () => {
|
||||
setup({
|
||||
route: { routeName: DashboardRoutes.Normal, component: () => null, path: '/' },
|
||||
uid: 'abc-def',
|
||||
|
|
@ -141,132 +118,17 @@ describe('DashboardPageProxy', () => {
|
|||
expect(screen.queryAllByTestId('dashboard-scene-page')).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when dashboardSceneForViewers feature toggle enabled', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
config.featureToggles.dashboardSceneForViewers = true;
|
||||
});
|
||||
|
||||
describe('when user can edit a dashboard ', () => {
|
||||
it('should not render DashboardScenePage if route is Home', async () => {
|
||||
getDashboardScenePageStateManager().setDashboardCache(HOME_DASHBOARD_CACHE_KEY, homeMockEditable);
|
||||
setup({
|
||||
route: { routeName: DashboardRoutes.Home, component: () => null, path: '/' },
|
||||
uid: '',
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryAllByTestId('dashboard-scene-page')).toHaveLength(0);
|
||||
});
|
||||
it('should render DashboardScenePage when forceScenes query param is set', async () => {
|
||||
setup({
|
||||
route: { routeName: DashboardRoutes.Normal, component: () => null, path: '/' },
|
||||
uid: 'abc-def',
|
||||
queryParams: { scenes: true },
|
||||
});
|
||||
|
||||
it('should not render DashboardScenePage if route is Normal and has uid', async () => {
|
||||
getDashboardScenePageStateManager().setDashboardCache('abc-def', dashMockEditable);
|
||||
setup({
|
||||
route: { routeName: DashboardRoutes.Normal, component: () => null, path: '/' },
|
||||
uid: 'abc-def',
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.queryAllByTestId('dashboard-scene-page')).toHaveLength(0);
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.queryAllByTestId('dashboard-scene-page')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when user can only view a dashboard ', () => {
|
||||
it('should render DashboardScenePage if route is Home', async () => {
|
||||
getDashboardScenePageStateManager().setDashboardCache(HOME_DASHBOARD_CACHE_KEY, homeMock);
|
||||
setup({
|
||||
route: { routeName: DashboardRoutes.Home, component: () => null, path: '/' },
|
||||
uid: '',
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryAllByTestId('dashboard-scene-page')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('should render DashboardScenePage if route is Normal and has uid', async () => {
|
||||
getDashboardScenePageStateManager().setDashboardCache('uid', dashMock);
|
||||
setup({
|
||||
route: { routeName: DashboardRoutes.Normal, component: () => null, path: '/' },
|
||||
uid: 'uid',
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.queryAllByTestId('dashboard-scene-page')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('should render not DashboardScenePage if dashboard UID does not match route UID', async () => {
|
||||
getDashboardScenePageStateManager().setDashboardCache('uid', dashMock);
|
||||
setup({
|
||||
route: { routeName: DashboardRoutes.Normal, component: () => null, path: '/' },
|
||||
uid: 'wrongUID',
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.queryAllByTestId('dashboard-scene-page')).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('errors rendering', () => {
|
||||
it('should render dashboard not found notice when dashboard... not found', async () => {
|
||||
setupLoadDashboardMockReject({
|
||||
status: 404,
|
||||
statusText: 'Not Found',
|
||||
data: {
|
||||
message: 'Dashboard not found',
|
||||
},
|
||||
config: {
|
||||
method: 'GET',
|
||||
url: 'api/dashboards/uid/adfjq9edwm0hsdsa',
|
||||
retry: 0,
|
||||
headers: {
|
||||
'X-Grafana-Org-Id': 1,
|
||||
},
|
||||
hideFromInspector: true,
|
||||
},
|
||||
isHandled: true,
|
||||
});
|
||||
|
||||
setup({ route: { routeName: DashboardRoutes.Normal, component: () => null, path: '/' }, uid: 'abc' });
|
||||
|
||||
expect(await screen.findByTestId(selectors.components.EntityNotFound.container)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render error alert for backend errors', async () => {
|
||||
setupLoadDashboardMockReject({
|
||||
status: 500,
|
||||
statusText: 'internal server error',
|
||||
data: {
|
||||
message: 'Internal server error',
|
||||
},
|
||||
config: {
|
||||
method: 'GET',
|
||||
url: 'api/dashboards/uid/adfjq9edwm0hsdsa',
|
||||
retry: 0,
|
||||
headers: {
|
||||
'X-Grafana-Org-Id': 1,
|
||||
},
|
||||
hideFromInspector: true,
|
||||
},
|
||||
isHandled: true,
|
||||
});
|
||||
|
||||
setup({ route: { routeName: DashboardRoutes.Normal, component: () => null, path: '/' }, uid: 'abc' });
|
||||
|
||||
expect(await screen.findByTestId('dashboard-page-error')).toBeInTheDocument();
|
||||
expect(await screen.findByTestId('dashboard-page-error')).toHaveTextContent('Internal server error');
|
||||
});
|
||||
it('should render error alert for runtime errors', async () => {
|
||||
setupLoadDashboardRuntimeErrorMock();
|
||||
|
||||
setup({ route: { routeName: DashboardRoutes.Normal, component: () => null, path: '/' }, uid: 'abc' });
|
||||
|
||||
expect(await screen.findByTestId('dashboard-page-error')).toBeInTheDocument();
|
||||
expect(await screen.findByTestId('dashboard-page-error')).toHaveTextContent('Runtime error');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,16 +1,11 @@
|
|||
import { useLocation, useParams } from 'react-router-dom-v5-compat';
|
||||
import { useAsync } from 'react-use';
|
||||
|
||||
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
||||
import DashboardScenePage from 'app/features/dashboard-scene/pages/DashboardScenePage';
|
||||
import { getDashboardScenePageStateManager } from 'app/features/dashboard-scene/pages/DashboardScenePageStateManager';
|
||||
import { DashboardRoutes } from 'app/types/dashboard';
|
||||
|
||||
import { isDashboardSceneEnabled, isDashboardSceneForViewersEnabled } from '../../dashboard-scene/utils/utils';
|
||||
import { isDashboardV2Resource } from '../api/utils';
|
||||
import { isDashboardSceneEnabled } from '../../dashboard-scene/utils/utils';
|
||||
|
||||
import DashboardPage, { DashboardPageParams } from './DashboardPage';
|
||||
import { DashboardPageError } from './DashboardPageError';
|
||||
import { DashboardPageRouteParams, DashboardPageRouteSearchParams } from './types';
|
||||
|
||||
export type DashboardPageProxyProps = Omit<
|
||||
|
|
@ -19,71 +14,21 @@ export type DashboardPageProxyProps = Omit<
|
|||
>;
|
||||
|
||||
// This proxy component is used for Dashboard -> Scenes migration.
|
||||
// It will render DashboardScenePage if the user is only allowed to view the dashboard.
|
||||
// When dashboardScene is enabled (default), it renders DashboardScenePage for all users.
|
||||
// Otherwise - use the legacy DashboardPage ¯\_ (ツ)_/¯
|
||||
function DashboardPageProxy(props: DashboardPageProxyProps) {
|
||||
const forceScenes = props.queryParams.scenes === true;
|
||||
const forceOld = props.queryParams.scenes === false;
|
||||
const params = useParams<DashboardPageParams>();
|
||||
const location = useLocation();
|
||||
const stateManager = getDashboardScenePageStateManager();
|
||||
|
||||
if (forceScenes || (isDashboardSceneEnabled() && !forceOld)) {
|
||||
const useScenes = forceScenes || (isDashboardSceneEnabled() && !forceOld);
|
||||
|
||||
if (useScenes) {
|
||||
return <DashboardScenePage {...props} />;
|
||||
}
|
||||
|
||||
const isScenesSupportedRoute = Boolean(
|
||||
props.route.routeName === DashboardRoutes.Home ||
|
||||
props.route.routeName === DashboardRoutes.Template ||
|
||||
(props.route.routeName === DashboardRoutes.Normal && params.uid)
|
||||
);
|
||||
|
||||
// We pre-fetch dashboard to render dashboard page component depending on dashboard permissions.
|
||||
// To avoid querying single dashboard multiple times, stateManager.fetchDashboard uses a simple, short-lived cache.
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const dashboard = useAsync(async () => {
|
||||
if (params.type === 'snapshot') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return stateManager.fetchDashboard({
|
||||
route: props.route.routeName as DashboardRoutes,
|
||||
uid: params.uid ?? '',
|
||||
type: params.type,
|
||||
slug: params.slug,
|
||||
});
|
||||
}, [params.uid, props.route.routeName]);
|
||||
|
||||
if (dashboard.error) {
|
||||
return <DashboardPageError error={dashboard.error} />;
|
||||
}
|
||||
|
||||
if (dashboard.loading) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const uid =
|
||||
dashboard.value && isDashboardV2Resource(dashboard.value)
|
||||
? dashboard.value.metadata.name
|
||||
: dashboard.value?.meta.uid;
|
||||
const canEdit =
|
||||
dashboard.value && isDashboardV2Resource(dashboard.value)
|
||||
? dashboard.value?.access.canEdit
|
||||
: dashboard.value?.meta?.canEdit || dashboard.value?.meta?.canMakeEditable;
|
||||
const isNew = !uid;
|
||||
|
||||
if (uid !== params.uid && !isNew) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isDashboardSceneForViewersEnabled()) {
|
||||
return <DashboardPage {...props} params={params} location={location} />;
|
||||
}
|
||||
|
||||
if (!canEdit && isScenesSupportedRoute && !forceOld) {
|
||||
return <DashboardScenePage {...props} />;
|
||||
} else {
|
||||
return <DashboardPage {...props} params={params} location={location} />;
|
||||
}
|
||||
return <DashboardPage {...props} params={params} location={location} />;
|
||||
}
|
||||
|
||||
export default DashboardPageProxy;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import { DashboardRoutes } from 'app/types/dashboard';
|
|||
import { SafeDynamicImport } from '../core/components/DynamicImports/SafeDynamicImport';
|
||||
import { RouteDescriptor } from '../core/navigation/types';
|
||||
import { getPublicDashboardRoutes } from '../features/dashboard/routes';
|
||||
import { isDashboardSceneSoloEnabled } from '../features/dashboard-scene/utils/utils';
|
||||
import { isDashboardSceneEnabled } from '../features/dashboard-scene/utils/utils';
|
||||
import { getProvisioningRoutes } from '../features/provisioning/utils/routes';
|
||||
|
||||
const isDevEnv = config.buildInfo.env === 'development';
|
||||
|
|
@ -109,7 +109,7 @@ export function getAppRoutes(): RouteDescriptor[] {
|
|||
routeName: DashboardRoutes.Normal,
|
||||
chromeless: true,
|
||||
component: SafeDynamicImport(() =>
|
||||
isDashboardSceneSoloEnabled()
|
||||
isDashboardSceneEnabled()
|
||||
? import(/* webpackChunkName: "SoloPanelPage" */ '../features/dashboard-scene/solo/SoloPanelPage')
|
||||
: import(/* webpackChunkName: "SoloPanelPageOld" */ '../features/dashboard/containers/SoloPanelPage')
|
||||
),
|
||||
|
|
@ -120,7 +120,7 @@ export function getAppRoutes(): RouteDescriptor[] {
|
|||
routeName: DashboardRoutes.Normal,
|
||||
chromeless: true,
|
||||
component: SafeDynamicImport(() =>
|
||||
isDashboardSceneSoloEnabled()
|
||||
isDashboardSceneEnabled()
|
||||
? import(/* webpackChunkName: "SoloPanelPage" */ '../features/dashboard-scene/solo/SoloPanelPage')
|
||||
: import(/* webpackChunkName: "SoloPanelPageOld" */ '../features/dashboard/containers/SoloPanelPage')
|
||||
),
|
||||
|
|
|
|||
Loading…
Reference in a new issue