ExtensionSidebar: Remove feature flag and enable by default (#109906)

* ExtensionSidebar: Remove feature flag and enable by default

* ExtensionSidebar: Remove `isEnabled`

* ExtensionSidebar: Lint

* ExtensionSidebar: Lint

* ExtensionSidebar: Remove more FF

* i dont know why, but okay
This commit is contained in:
Sven Grossmann 2025-09-01 12:14:17 +02:00 committed by GitHub
parent d31e682345
commit b6d7374b25
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 26 additions and 151 deletions

View File

@ -907,10 +907,6 @@ export interface FeatureToggles {
*/ */
unifiedStorageGrpcConnectionPool?: boolean; unifiedStorageGrpcConnectionPool?: boolean;
/** /**
* Enables the extension sidebar
*/
extensionSidebar?: boolean;
/**
* Enables UI functionality to permanently delete alert rules * Enables UI functionality to permanently delete alert rules
* @default true * @default true
*/ */

View File

@ -1563,13 +1563,6 @@ var (
HideFromAdminPage: true, HideFromAdminPage: true,
HideFromDocs: true, HideFromDocs: true,
}, },
{
Name: "extensionSidebar",
Description: "Enables the extension sidebar",
Stage: FeatureStageExperimental,
FrontendOnly: true,
Owner: grafanaObservabilityLogsSquad,
},
{ {
Name: "alertingRulePermanentlyDelete", Name: "alertingRulePermanentlyDelete",
Description: "Enables UI functionality to permanently delete alert rules", Description: "Enables UI functionality to permanently delete alert rules",

View File

@ -203,7 +203,6 @@ unifiedStorageHistoryPruner,GA,@grafana/search-and-storage,false,false,false
azureMonitorLogsBuilderEditor,preview,@grafana/partner-datasources,false,false,false azureMonitorLogsBuilderEditor,preview,@grafana/partner-datasources,false,false,false
localeFormatPreference,preview,@grafana/grafana-frontend-platform,false,false,false localeFormatPreference,preview,@grafana/grafana-frontend-platform,false,false,false
unifiedStorageGrpcConnectionPool,experimental,@grafana/search-and-storage,false,false,false unifiedStorageGrpcConnectionPool,experimental,@grafana/search-and-storage,false,false,false
extensionSidebar,experimental,@grafana/observability-logs,false,false,true
alertingRulePermanentlyDelete,GA,@grafana/alerting-squad,false,false,true alertingRulePermanentlyDelete,GA,@grafana/alerting-squad,false,false,true
alertingRuleRecoverDeleted,GA,@grafana/alerting-squad,false,false,true alertingRuleRecoverDeleted,GA,@grafana/alerting-squad,false,false,true
multiTenantTempCredentials,experimental,@grafana/aws-datasources,false,false,false multiTenantTempCredentials,experimental,@grafana/aws-datasources,false,false,false

1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
203 azureMonitorLogsBuilderEditor preview @grafana/partner-datasources false false false
204 localeFormatPreference preview @grafana/grafana-frontend-platform false false false
205 unifiedStorageGrpcConnectionPool experimental @grafana/search-and-storage false false false
extensionSidebar experimental @grafana/observability-logs false false true
206 alertingRulePermanentlyDelete GA @grafana/alerting-squad false false true
207 alertingRuleRecoverDeleted GA @grafana/alerting-squad false false true
208 multiTenantTempCredentials experimental @grafana/aws-datasources false false false

View File

@ -823,10 +823,6 @@ const (
// Enables the unified storage grpc connection pool // Enables the unified storage grpc connection pool
FlagUnifiedStorageGrpcConnectionPool = "unifiedStorageGrpcConnectionPool" FlagUnifiedStorageGrpcConnectionPool = "unifiedStorageGrpcConnectionPool"
// FlagExtensionSidebar
// Enables the extension sidebar
FlagExtensionSidebar = "extensionSidebar"
// FlagAlertingRulePermanentlyDelete // FlagAlertingRulePermanentlyDelete
// Enables UI functionality to permanently delete alert rules // Enables UI functionality to permanently delete alert rules
FlagAlertingRulePermanentlyDelete = "alertingRulePermanentlyDelete" FlagAlertingRulePermanentlyDelete = "alertingRulePermanentlyDelete"

View File

@ -1322,7 +1322,8 @@
"metadata": { "metadata": {
"name": "extensionSidebar", "name": "extensionSidebar",
"resourceVersion": "1753448760331", "resourceVersion": "1753448760331",
"creationTimestamp": "2025-04-03T10:16:35Z" "creationTimestamp": "2025-04-03T10:16:35Z",
"deletionTimestamp": "2025-08-20T11:59:44Z"
}, },
"spec": { "spec": {
"description": "Enables the extension sidebar", "description": "Enables the extension sidebar",

View File

@ -105,9 +105,6 @@ export class AppWrapper extends Component<AppWrapperProps, AppWrapperState> {
}; };
const MaybeTimeRangeProvider = config.featureToggles.timeRangeProvider ? TimeRangeProvider : Fragment; const MaybeTimeRangeProvider = config.featureToggles.timeRangeProvider ? TimeRangeProvider : Fragment;
const MaybeExtensionSidebarProvider = config.featureToggles.extensionSidebar
? ExtensionSidebarContextProvider
: Fragment;
return ( return (
<Provider store={store}> <Provider store={store}>
@ -122,7 +119,7 @@ export class AppWrapper extends Component<AppWrapperProps, AppWrapperState> {
<MaybeTimeRangeProvider> <MaybeTimeRangeProvider>
<ScopesContextProvider> <ScopesContextProvider>
<ExtensionRegistriesProvider registries={pluginExtensionRegistries}> <ExtensionRegistriesProvider registries={pluginExtensionRegistries}>
<MaybeExtensionSidebarProvider> <ExtensionSidebarContextProvider>
<UNSAFE_PortalProvider getContainer={getPortalContainer}> <UNSAFE_PortalProvider getContainer={getPortalContainer}>
<GlobalStylesWrapper /> <GlobalStylesWrapper />
<div className="grafana-app"> <div className="grafana-app">
@ -131,7 +128,7 @@ export class AppWrapper extends Component<AppWrapperProps, AppWrapperState> {
<PortalContainer /> <PortalContainer />
</div> </div>
</UNSAFE_PortalProvider> </UNSAFE_PortalProvider>
</MaybeExtensionSidebarProvider> </ExtensionSidebarContextProvider>
</ExtensionRegistriesProvider> </ExtensionRegistriesProvider>
</ScopesContextProvider> </ScopesContextProvider>
</MaybeTimeRangeProvider> </MaybeTimeRangeProvider>

View File

@ -33,7 +33,6 @@ export function AppChrome({ children }: Props) {
const { chrome } = useGrafana(); const { chrome } = useGrafana();
const { const {
isOpen: isExtensionSidebarOpen, isOpen: isExtensionSidebarOpen,
isEnabled: isExtensionSidebarEnabled,
extensionSidebarWidth, extensionSidebarWidth,
setExtensionSidebarWidth, setExtensionSidebarWidth,
} = useExtensionSidebarContext(); } = useExtensionSidebarContext();
@ -138,7 +137,7 @@ export function AppChrome({ children }: Props) {
> >
{children} {children}
</main> </main>
{!state.chromeless && isExtensionSidebarEnabled && isExtensionSidebarOpen && ( {!state.chromeless && isExtensionSidebarOpen && (
<Resizable <Resizable
className={styles.sidebarContainer} className={styles.sidebarContainer}
defaultSize={{ width: extensionSidebarWidth }} defaultSize={{ width: extensionSidebarWidth }}

View File

@ -44,7 +44,6 @@ const addedComponentConfigMock: ExtensionInfo = {
const extensionSidebarContextMock: ExtensionSidebarContextType = { const extensionSidebarContextMock: ExtensionSidebarContextType = {
dockedComponentId: getComponentIdFromComponentMeta(pluginId, addedComponentConfigMock), dockedComponentId: getComponentIdFromComponentMeta(pluginId, addedComponentConfigMock),
isEnabled: true,
props: {}, props: {},
isOpen: true, isOpen: true,
setDockedComponentId: jest.fn(), setDockedComponentId: jest.fn(),
@ -71,25 +70,9 @@ describe('ExtensionSidebar', () => {
config.buildInfo.env = originalEnv; config.buildInfo.env = originalEnv;
}); });
it('should render nothing when the extension sidebar is not enabled', () => {
mockUseExtensionSidebarContext.mockReturnValue({
...extensionSidebarContextMock,
isEnabled: false,
});
mockUsePluginComponents.mockReturnValue({
components: [createComponentWithMeta(addedComponentRegistryItemMock, extensionPointId)],
isLoading: false,
});
const { container } = render(<ExtensionSidebar />);
expect(container.firstChild).toBeNull();
});
it('should render nothing when the extension sidebar is enabled but no component is docked', () => { it('should render nothing when the extension sidebar is enabled but no component is docked', () => {
mockUseExtensionSidebarContext.mockReturnValue({ mockUseExtensionSidebarContext.mockReturnValue({
...extensionSidebarContextMock, ...extensionSidebarContextMock,
isEnabled: true,
dockedComponentId: undefined, dockedComponentId: undefined,
}); });
@ -105,7 +88,6 @@ describe('ExtensionSidebar', () => {
it('should render nothing when the extension sidebar is enabled but the component docked is not found in the available components', () => { it('should render nothing when the extension sidebar is enabled but the component docked is not found in the available components', () => {
mockUseExtensionSidebarContext.mockReturnValue({ mockUseExtensionSidebarContext.mockReturnValue({
...extensionSidebarContextMock, ...extensionSidebarContextMock,
isEnabled: true,
dockedComponentId: 'test-component-id-not-found', dockedComponentId: 'test-component-id-not-found',
}); });
@ -121,7 +103,6 @@ describe('ExtensionSidebar', () => {
it('should render nothing when the extension sidebar is enabled but the component docked is not found in the available components', () => { it('should render nothing when the extension sidebar is enabled but the component docked is not found in the available components', () => {
mockUseExtensionSidebarContext.mockReturnValue({ mockUseExtensionSidebarContext.mockReturnValue({
...extensionSidebarContextMock, ...extensionSidebarContextMock,
isEnabled: true,
dockedComponentId: 'test-component-id-not-found', dockedComponentId: 'test-component-id-not-found',
}); });
@ -137,7 +118,6 @@ describe('ExtensionSidebar', () => {
it('should render nothing when components are loading', () => { it('should render nothing when components are loading', () => {
mockUseExtensionSidebarContext.mockReturnValue({ mockUseExtensionSidebarContext.mockReturnValue({
...extensionSidebarContextMock, ...extensionSidebarContextMock,
isEnabled: true,
}); });
mockUsePluginComponents.mockReturnValue({ mockUsePluginComponents.mockReturnValue({
@ -152,7 +132,6 @@ describe('ExtensionSidebar', () => {
it('should render the component when all conditions are met', () => { it('should render the component when all conditions are met', () => {
mockUseExtensionSidebarContext.mockReturnValue({ mockUseExtensionSidebarContext.mockReturnValue({
...extensionSidebarContextMock, ...extensionSidebarContextMock,
isEnabled: true,
}); });
mockUsePluginComponents.mockReturnValue({ mockUsePluginComponents.mockReturnValue({

View File

@ -16,12 +16,12 @@ type ExtensionSidebarComponentProps = {
export function ExtensionSidebar() { export function ExtensionSidebar() {
const styles = getStyles(useTheme2()); const styles = getStyles(useTheme2());
const { dockedComponentId, isEnabled, props = {} } = useExtensionSidebarContext(); const { dockedComponentId, props = {} } = useExtensionSidebarContext();
const { components, isLoading } = usePluginComponents<ExtensionSidebarComponentProps>({ const { components, isLoading } = usePluginComponents<ExtensionSidebarComponentProps>({
extensionPointId: PluginExtensionPoints.ExtensionSidebar, extensionPointId: PluginExtensionPoints.ExtensionSidebar,
}); });
if (isLoading || !dockedComponentId || !isEnabled) { if (isLoading || !dockedComponentId) {
return null; return null;
} }

View File

@ -1,7 +1,7 @@
import { render, screen, act } from '@testing-library/react'; import { render, screen, act } from '@testing-library/react';
import { store, EventBusSrv, EventBus } from '@grafana/data'; import { store, EventBusSrv, EventBus } from '@grafana/data';
import { config, getAppEvents, setAppEvents, locationService } from '@grafana/runtime'; import { getAppEvents, setAppEvents, locationService } from '@grafana/runtime';
import { getExtensionPointPluginMeta } from 'app/features/plugins/extensions/utils'; import { getExtensionPointPluginMeta } from 'app/features/plugins/extensions/utils';
import { OpenExtensionSidebarEvent, CloseExtensionSidebarEvent } from 'app/types/events'; import { OpenExtensionSidebarEvent, CloseExtensionSidebarEvent } from 'app/types/events';
@ -43,13 +43,6 @@ jest.mock('app/features/plugins/extensions/utils', () => ({
jest.mock('@grafana/runtime', () => ({ jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'), ...jest.requireActual('@grafana/runtime'),
config: {
...jest.requireActual('@grafana/runtime').config,
featureToggles: {
...jest.requireActual('@grafana/runtime').config.featureToggles,
extensionSidebar: true,
},
},
locationService: { locationService: {
getLocation: jest.fn().mockReturnValue({ pathname: '/test-path' }), getLocation: jest.fn().mockReturnValue({ pathname: '/test-path' }),
getLocationObservable: jest.fn(), getLocationObservable: jest.fn(),
@ -83,8 +76,6 @@ describe('ExtensionSidebarProvider', () => {
getExtensionPointPluginMetaMock.mockReturnValue(new Map([[mockPluginMeta.pluginId, mockPluginMeta]])); getExtensionPointPluginMetaMock.mockReturnValue(new Map([[mockPluginMeta.pluginId, mockPluginMeta]]));
jest.replaceProperty(config.featureToggles, 'extensionSidebar', true);
locationObservableMock = { locationObservableMock = {
subscribe: jest.fn((callback) => { subscribe: jest.fn((callback) => {
locationObservableMock.callback = callback; locationObservableMock.callback = callback;
@ -113,7 +104,6 @@ describe('ExtensionSidebarProvider', () => {
<div data-testid="docked-component-id">{context.dockedComponentId || 'undefined'}</div> <div data-testid="docked-component-id">{context.dockedComponentId || 'undefined'}</div>
<div data-testid="available-components-size">{context.availableComponents.size}</div> <div data-testid="available-components-size">{context.availableComponents.size}</div>
<div data-testid="plugin-ids">{Array.from(context.availableComponents.keys()).join(', ')}</div> <div data-testid="plugin-ids">{Array.from(context.availableComponents.keys()).join(', ')}</div>
<div data-testid="is-enabled">{context.isEnabled.toString()}</div>
</div> </div>
); );
}; };
@ -128,20 +118,6 @@ describe('ExtensionSidebarProvider', () => {
expect(screen.getByTestId('is-open')).toHaveTextContent('false'); expect(screen.getByTestId('is-open')).toHaveTextContent('false');
expect(screen.getByTestId('docked-component-id')).toHaveTextContent('undefined'); expect(screen.getByTestId('docked-component-id')).toHaveTextContent('undefined');
expect(screen.getByTestId('available-components-size')).toHaveTextContent('1'); expect(screen.getByTestId('available-components-size')).toHaveTextContent('1');
expect(screen.getByTestId('is-enabled')).toHaveTextContent('true');
});
it('should have empty available components when feature toggle is disabled', () => {
jest.replaceProperty(config.featureToggles, 'extensionSidebar', false);
render(
<ExtensionSidebarContextProvider>
<TestComponent />
</ExtensionSidebarContextProvider>
);
expect(screen.getByTestId('is-enabled')).toHaveTextContent('false');
expect(screen.getByTestId('available-components-size')).toHaveTextContent('0');
}); });
it('should load docked component from storage if available', () => { it('should load docked component from storage if available', () => {
@ -158,22 +134,6 @@ describe('ExtensionSidebarProvider', () => {
expect(screen.getByTestId('docked-component-id')).toHaveTextContent(componentId); expect(screen.getByTestId('docked-component-id')).toHaveTextContent(componentId);
}); });
it('should not load docked component from storage if feature toggle is disabled', () => {
jest.replaceProperty(config.featureToggles, 'extensionSidebar', false);
const componentId = getComponentIdFromComponentMeta(mockPluginMeta.pluginId, mockComponent);
(store.get as jest.Mock).mockReturnValue(componentId);
render(
<ExtensionSidebarContextProvider>
<TestComponent />
</ExtensionSidebarContextProvider>
);
expect(screen.getByTestId('is-open')).toHaveTextContent('false');
expect(screen.getByTestId('docked-component-id')).toHaveTextContent('undefined');
});
it('should update storage when docked component changes', () => { it('should update storage when docked component changes', () => {
const componentId = getComponentIdFromComponentMeta(mockPluginMeta.pluginId, mockComponent); const componentId = getComponentIdFromComponentMeta(mockPluginMeta.pluginId, mockComponent);
@ -260,18 +220,6 @@ describe('ExtensionSidebarProvider', () => {
expect(subscribeSpy).toHaveBeenCalledWith(CloseExtensionSidebarEvent, expect.any(Function)); expect(subscribeSpy).toHaveBeenCalledWith(CloseExtensionSidebarEvent, expect.any(Function));
}); });
it('should not subscribe to OpenExtensionSidebarEvent or CloseExtensionSidebarEvent when feature is disabled', () => {
jest.replaceProperty(config.featureToggles, 'extensionSidebar', false);
render(
<ExtensionSidebarContextProvider>
<TestComponent />
</ExtensionSidebarContextProvider>
);
expect(subscribeSpy).not.toHaveBeenCalled();
});
it('should set dockedComponentId and props when receiving a valid OpenExtensionSidebarEvent', () => { it('should set dockedComponentId and props when receiving a valid OpenExtensionSidebarEvent', () => {
const TestComponentWithProps = () => { const TestComponentWithProps = () => {
const context = useExtensionSidebarContext(); const context = useExtensionSidebarContext();

View File

@ -2,7 +2,7 @@ import { createContext, ReactNode, useCallback, useContext, useEffect, useState,
import { useLocalStorage } from 'react-use'; import { useLocalStorage } from 'react-use';
import { PluginExtensionPoints, store, type ExtensionInfo } from '@grafana/data'; import { PluginExtensionPoints, store, type ExtensionInfo } from '@grafana/data';
import { config, getAppEvents, reportInteraction, usePluginLinks, locationService } from '@grafana/runtime'; import { getAppEvents, reportInteraction, usePluginLinks, locationService } from '@grafana/runtime';
import { ExtensionPointPluginMeta, getExtensionPointPluginMeta } from 'app/features/plugins/extensions/utils'; import { ExtensionPointPluginMeta, getExtensionPointPluginMeta } from 'app/features/plugins/extensions/utils';
import { CloseExtensionSidebarEvent, OpenExtensionSidebarEvent } from 'app/types/events'; import { CloseExtensionSidebarEvent, OpenExtensionSidebarEvent } from 'app/types/events';
@ -18,10 +18,6 @@ const PERMITTED_EXTENSION_SIDEBAR_PLUGINS = [
]; ];
export type ExtensionSidebarContextType = { export type ExtensionSidebarContextType = {
/**
* Whether the extension sidebar is enabled.
*/
isEnabled: boolean;
/** /**
* Whether the extension sidebar is open. * Whether the extension sidebar is open.
*/ */
@ -51,7 +47,6 @@ export type ExtensionSidebarContextType = {
}; };
export const ExtensionSidebarContext = createContext<ExtensionSidebarContextType>({ export const ExtensionSidebarContext = createContext<ExtensionSidebarContextType>({
isEnabled: !!config.featureToggles.extensionSidebar,
isOpen: false, isOpen: false,
dockedComponentId: undefined, dockedComponentId: undefined,
setDockedComponentId: () => {}, setDockedComponentId: () => {},
@ -99,13 +94,11 @@ export const ExtensionSidebarContextProvider = ({ children }: ExtensionSidebarCo
}, },
}); });
const isEnabled = !!config.featureToggles.extensionSidebar;
// get all components for this extension point, but only for the permitted plugins // get all components for this extension point, but only for the permitted plugins
// if the extension sidebar is not enabled, we will return an empty map // if the extension sidebar is not enabled, we will return an empty map
const availableComponents = useMemo( const availableComponents = useMemo(
() => () =>
isEnabled new Map(
? new Map(
Array.from(getExtensionPointPluginMeta(PluginExtensionPoints.ExtensionSidebar).entries()).filter( Array.from(getExtensionPointPluginMeta(PluginExtensionPoints.ExtensionSidebar).entries()).filter(
([pluginId, pluginMeta]) => ([pluginId, pluginMeta]) =>
PERMITTED_EXTENSION_SIDEBAR_PLUGINS.includes(pluginId) && PERMITTED_EXTENSION_SIDEBAR_PLUGINS.includes(pluginId) &&
@ -115,15 +108,8 @@ export const ExtensionSidebarContextProvider = ({ children }: ExtensionSidebarCo
pluginMeta.addedComponents.some((component) => component.title === link.title) pluginMeta.addedComponents.some((component) => component.title === link.title)
) )
) )
) ),
: new Map< [links]
string,
{
readonly addedComponents: ExtensionInfo[];
readonly addedLinks: ExtensionInfo[];
}
>(),
[isEnabled, links]
); );
// check if the stored docked component is still available // check if the stored docked component is still available
@ -164,10 +150,6 @@ export const ExtensionSidebarContextProvider = ({ children }: ExtensionSidebarCo
); );
useEffect(() => { useEffect(() => {
if (!isEnabled) {
return;
}
// handler to open the extension sidebar from plugins. this is done with the `helpers.openSidebar` function // handler to open the extension sidebar from plugins. this is done with the `helpers.openSidebar` function
const openSidebarHandler = (event: OpenExtensionSidebarEvent) => { const openSidebarHandler = (event: OpenExtensionSidebarEvent) => {
if ( if (
@ -195,7 +177,7 @@ export const ExtensionSidebarContextProvider = ({ children }: ExtensionSidebarCo
openSubscription.unsubscribe(); openSubscription.unsubscribe();
closeSubscription.unsubscribe(); closeSubscription.unsubscribe();
}; };
}, [isEnabled, setDockedComponentWithProps, availableComponents]); }, [setDockedComponentWithProps, availableComponents]);
// update the stored docked component id when it changes // update the stored docked component id when it changes
useEffect(() => { useEffect(() => {
@ -226,8 +208,7 @@ export const ExtensionSidebarContextProvider = ({ children }: ExtensionSidebarCo
return ( return (
<ExtensionSidebarContext.Provider <ExtensionSidebarContext.Provider
value={{ value={{
isEnabled, isOpen: dockedComponentId !== undefined,
isOpen: isEnabled && dockedComponentId !== undefined,
dockedComponentId, dockedComponentId,
setDockedComponentId: (componentId) => setDockedComponentWithProps(componentId, undefined), setDockedComponentId: (componentId) => setDockedComponentWithProps(componentId, undefined),
availableComponents, availableComponents,

View File

@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event'; import userEvent from '@testing-library/user-event';
import { EventBusSrv, store } from '@grafana/data'; import { EventBusSrv, store } from '@grafana/data';
import { config, setAppEvents, usePluginLinks } from '@grafana/runtime'; import { setAppEvents, usePluginLinks } from '@grafana/runtime';
import { getExtensionPointPluginMeta } from 'app/features/plugins/extensions/utils'; import { getExtensionPointPluginMeta } from 'app/features/plugins/extensions/utils';
import { ExtensionSidebarContextProvider, useExtensionSidebarContext } from './ExtensionSidebarProvider'; import { ExtensionSidebarContextProvider, useExtensionSidebarContext } from './ExtensionSidebarProvider';
@ -26,13 +26,6 @@ jest.mock('@grafana/data', () => ({
jest.mock('@grafana/runtime', () => ({ jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'), ...jest.requireActual('@grafana/runtime'),
config: {
...jest.requireActual('@grafana/runtime').config,
featureToggles: {
...jest.requireActual('@grafana/runtime').config.featureToggles,
extensionSidebar: true,
},
},
usePluginLinks: jest.fn().mockImplementation(() => ({ usePluginLinks: jest.fn().mockImplementation(() => ({
links: [ links: [
{ {
@ -81,7 +74,6 @@ describe('ExtensionToolbarItem', () => {
(store.get as jest.Mock).mockClear(); (store.get as jest.Mock).mockClear();
(store.set as jest.Mock).mockClear(); (store.set as jest.Mock).mockClear();
(store.delete as jest.Mock).mockClear(); (store.delete as jest.Mock).mockClear();
jest.replaceProperty(config.featureToggles, 'extensionSidebar', true);
setAppEvents(new EventBusSrv()); setAppEvents(new EventBusSrv());
}); });
@ -89,12 +81,6 @@ describe('ExtensionToolbarItem', () => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
it('should not render when feature toggle is disabled', () => {
jest.replaceProperty(config.featureToggles, 'extensionSidebar', false);
setup();
expect(screen.queryByRole('button')).not.toBeInTheDocument();
});
it('should not render when no components are available', () => { it('should not render when no components are available', () => {
(getExtensionPointPluginMeta as jest.Mock).mockReturnValue(new Map()); (getExtensionPointPluginMeta as jest.Mock).mockReturnValue(new Map());
setup(); setup();

View File

@ -13,9 +13,9 @@ import { ExtensionToolbarItemButton } from './ExtensionToolbarItemButton';
type ComponentWithPluginId = ExtensionInfo & { pluginId: string }; type ComponentWithPluginId = ExtensionInfo & { pluginId: string };
export function ExtensionToolbarItem() { export function ExtensionToolbarItem() {
const { availableComponents, dockedComponentId, setDockedComponentId, isEnabled } = useExtensionSidebarContext(); const { availableComponents, dockedComponentId, setDockedComponentId } = useExtensionSidebarContext();
if (!isEnabled || availableComponents.size === 0) { if (availableComponents.size === 0) {
return null; return null;
} }

View File

@ -104,7 +104,7 @@ export const SingleTopBar = memo(function SingleTopBar({
</Dropdown> </Dropdown>
)} )}
<NavToolbarSeparator /> <NavToolbarSeparator />
{config.featureToggles.extensionSidebar && !isSmallScreen && <ExtensionToolbarItem />} {!isSmallScreen && <ExtensionToolbarItem />}
{!showToolbarLevel && actions} {!showToolbarLevel && actions}
{!contextSrv.user.isSignedIn && <SignInLink />} {!contextSrv.user.isSignedIn && <SignInLink />}
<InviteUserButton /> <InviteUserButton />