Plugins: Adds AppChrome extension point (#106623)
* Plugins: adds basic PopupExtension point * Simplify the extension point. * Excluding the app chrome extension to be rendered on login/signup pages. * Added feature toggle to be able to disable the app chrome extensions. * Adding an error boundary around the extension point. * Changed the way we use the feature toggle. * moved to use the helper function instead of filtering. * removed duplace info. * chore: remove leftover useMemo --------- Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
This commit is contained in:
co-authored by
Marcus Andersson
parent
470f3c1578
commit
15293a2ceb
@@ -1031,4 +1031,9 @@ export interface FeatureToggles {
|
||||
* @default false
|
||||
*/
|
||||
newInfluxDSConfigPageDesign?: boolean;
|
||||
/**
|
||||
* Set this to true to enable all app chrome extensions registered by plugins.
|
||||
* @default false
|
||||
*/
|
||||
enableAppChromeExtensions?: boolean;
|
||||
}
|
||||
|
||||
@@ -194,6 +194,7 @@ export enum PluginExtensionPoints {
|
||||
QueryEditorRowAdaptiveTelemetryV1 = 'grafana/query-editor-row/adaptivetelemetry/v1',
|
||||
TraceViewResourceAttributes = 'grafana/traceview/resource-attributes',
|
||||
LogsViewResourceAttributes = 'grafana/logsview/resource-attributes',
|
||||
AppChrome = 'grafana/app/chrome/v1',
|
||||
}
|
||||
|
||||
export type PluginExtensionPanelContext = {
|
||||
|
||||
@@ -1771,6 +1771,16 @@ var (
|
||||
Owner: grafanaPartnerPluginsSquad,
|
||||
Expression: "false",
|
||||
},
|
||||
{
|
||||
Name: "enableAppChromeExtensions",
|
||||
Description: "Set this to true to enable all app chrome extensions registered by plugins.",
|
||||
Stage: FeatureStageExperimental,
|
||||
Owner: grafanaPluginsPlatformSquad,
|
||||
HideFromAdminPage: true,
|
||||
HideFromDocs: true,
|
||||
FrontendOnly: true,
|
||||
Expression: "false", // extensions will be disabled by default
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -231,3 +231,4 @@ alertingImportAlertmanagerAPI,experimental,@grafana/alerting-squad,false,false,f
|
||||
preferLibraryPanelTitle,privatePreview,@grafana/dashboards-squad,false,false,false
|
||||
tabularNumbers,GA,@grafana/grafana-frontend-platform,false,false,false
|
||||
newInfluxDSConfigPageDesign,privatePreview,@grafana/partner-datasources,false,false,false
|
||||
enableAppChromeExtensions,experimental,@grafana/plugins-platform-backend,false,false,true
|
||||
|
||||
|
@@ -934,4 +934,8 @@ const (
|
||||
// FlagNewInfluxDSConfigPageDesign
|
||||
// Enables new design for the InfluxDB data source configuration page
|
||||
FlagNewInfluxDSConfigPageDesign = "newInfluxDSConfigPageDesign"
|
||||
|
||||
// FlagEnableAppChromeExtensions
|
||||
// Set this to true to enable all app chrome extensions registered by plugins.
|
||||
FlagEnableAppChromeExtensions = "enableAppChromeExtensions"
|
||||
)
|
||||
|
||||
@@ -943,6 +943,22 @@
|
||||
"codeowner": "@grafana/aws-datasources"
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "enableAppChromeExtensions",
|
||||
"resourceVersion": "1750235111726",
|
||||
"creationTimestamp": "2025-06-18T08:25:11Z"
|
||||
},
|
||||
"spec": {
|
||||
"description": "Set this to true to enable all app chrome extensions registered by plugins.",
|
||||
"stage": "experimental",
|
||||
"codeowner": "@grafana/plugins-platform-backend",
|
||||
"frontend": true,
|
||||
"hideFromAdminPage": true,
|
||||
"hideFromDocs": true,
|
||||
"expression": "false"
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "enableDatagridEditing",
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
import { PluginExtensionPoints } from '@grafana/data';
|
||||
import { config, renderLimitedComponents, usePluginComponents } from '@grafana/runtime';
|
||||
import { ErrorBoundaryAlert } from '@grafana/ui';
|
||||
|
||||
const excludedRoutes: Record<string, boolean> = {
|
||||
'/login': true,
|
||||
'/signup': true,
|
||||
'/verify': true,
|
||||
'/user/password/send-reset-email': true,
|
||||
'/user/password/reset': true,
|
||||
'/sandbox/benchmarks': true,
|
||||
};
|
||||
|
||||
export function AppChromeExtensionPoint(): JSX.Element | null {
|
||||
const location = useLocation();
|
||||
|
||||
if (config.featureToggles.enableAppChromeExtensions !== true) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (excludedRoutes[location.pathname]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ErrorBoundaryAlert>
|
||||
<InternalAppChromeExtensionPoint />
|
||||
</ErrorBoundaryAlert>
|
||||
);
|
||||
}
|
||||
|
||||
function InternalAppChromeExtensionPoint(): JSX.Element | null {
|
||||
const { components, isLoading } = usePluginComponents({
|
||||
extensionPointId: PluginExtensionPoints.AppChrome,
|
||||
});
|
||||
|
||||
if (isLoading) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return renderLimitedComponents({
|
||||
props: {},
|
||||
components: components,
|
||||
pluginId: 'grafana-setupguide-app',
|
||||
});
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import { locationService, LocationServiceProvider } from '@grafana/runtime';
|
||||
import { ModalRoot, Stack } from '@grafana/ui';
|
||||
|
||||
import { AppChrome } from '../core/components/AppChrome/AppChrome';
|
||||
import { AppChromeExtensionPoint } from '../core/components/AppChrome/AppChromeExtensionPoint';
|
||||
import { AppNotificationList } from '../core/components/AppNotifications/AppNotificationList';
|
||||
import { ModalsContextProvider } from '../core/context/ModalsContextProvider';
|
||||
import { QueriesDrawerContextProvider } from '../features/explore/QueriesDrawer/QueriesDrawerContext';
|
||||
@@ -41,6 +42,7 @@ export function RouterWrapper(props: RouterWrapperProps) {
|
||||
{props.bodyRenderHooks.map((Hook, index) => (
|
||||
<Hook key={index.toString()} />
|
||||
))}
|
||||
<AppChromeExtensionPoint />
|
||||
</AppChrome>
|
||||
<ModalRoot />
|
||||
</ModalsContextProvider>
|
||||
|
||||
Reference in New Issue
Block a user