rename header action to plugin header action
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -2,4 +2,4 @@
|
||||
'@backstage/plugin-app-visualizer': minor
|
||||
---
|
||||
|
||||
Migrated to use `SubPageBlueprint` for tabbed navigation and added a copy-tree-as-JSON header action using `HeaderActionBlueprint`. The plugin now specifies a `title` and `icon`.
|
||||
Migrated to use `SubPageBlueprint` for tabbed navigation and added a copy-tree-as-JSON plugin header action using `PluginHeaderActionBlueprint`. The plugin now specifies a `title` and `icon`.
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
'@backstage/plugin-app': minor
|
||||
---
|
||||
|
||||
Added `SubPageBlueprint` for creating sub-page tabs, `HeaderActionBlueprint` and `HeaderActionsApi` for plugin-scoped header actions, and `PageLayout` as a swappable component. The `PageBlueprint` now supports sub-pages with tabbed navigation, page title, icon, and header actions. Plugins can now specify a `title` and `icon` in `createFrontendPlugin`.
|
||||
Added `SubPageBlueprint` for creating sub-page tabs, `PluginHeaderActionBlueprint` and `PluginHeaderActionsApi` for plugin-scoped header actions, and `PageLayout` as a swappable component. The `PageBlueprint` now supports sub-pages with tabbed navigation, page title, icon, and header actions. Plugins can now specify a `title` and `icon` in `createFrontendPlugin`.
|
||||
|
||||
@@ -29,9 +29,9 @@ To enable sub-pages on a page, you can either omit the `loader` param to use the
|
||||
|
||||
Sub-page extensions create tabbed content within a parent page. They are attached to a page extension's `pages` input and rendered as tabs in the page header. Each sub-page has a `path` (relative to the parent page), a `title` for the tab, and an optional `icon`. Content is lazy-loaded via a `loader` function.
|
||||
|
||||
### HeaderAction - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.HeaderActionBlueprint.html)
|
||||
### PluginHeaderAction - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.PluginHeaderActionBlueprint.html)
|
||||
|
||||
Header action extensions provide plugin-scoped actions that appear in the page header. They are automatically scoped to the plugin that provides them and will appear in the header of all pages belonging to that plugin. Actions are lazy-loaded via a `loader` function that returns a React element.
|
||||
Plugin header action extensions provide plugin-scoped actions that appear in the page header. They are automatically scoped to the plugin that provides them and will appear in the header of all pages belonging to that plugin. Actions are lazy-loaded via a `loader` function that returns a React element.
|
||||
|
||||
## Extension blueprints in `@backstage/frontend-plugin-api/alpha`
|
||||
|
||||
|
||||
@@ -394,7 +394,7 @@ describe('createApp', () => {
|
||||
<api:app/icons out=[core.api.factory] />
|
||||
<api:app/feature-flags out=[core.api.factory] />
|
||||
<api:app/plugin-wrapper out=[core.api.factory] />
|
||||
<api:app/header-actions out=[core.api.factory] />
|
||||
<api:app/plugin-header-actions out=[core.api.factory] />
|
||||
<api:app/translations out=[core.api.factory] />
|
||||
<api:app/components out=[core.api.factory] />
|
||||
]
|
||||
|
||||
@@ -1424,39 +1424,6 @@ export const googleAuthApiRef: ApiRef<
|
||||
SessionApi
|
||||
>;
|
||||
|
||||
// @public
|
||||
export const HeaderActionBlueprint: ExtensionBlueprint_2<{
|
||||
kind: 'header-action';
|
||||
params: (params: {
|
||||
loader: () => Promise<JSX.Element>;
|
||||
}) => ExtensionBlueprintParams_2<{
|
||||
loader: () => Promise<JSX.Element>;
|
||||
}>;
|
||||
output: ExtensionDataRef_2<
|
||||
() => Promise<JSX.Element>,
|
||||
'core.header-action.loader',
|
||||
{}
|
||||
>;
|
||||
inputs: {};
|
||||
config: {};
|
||||
configInput: {};
|
||||
dataRefs: {
|
||||
action: ConfigurableExtensionDataRef_2<
|
||||
() => Promise<JSX.Element>,
|
||||
'core.header-action.loader',
|
||||
{}
|
||||
>;
|
||||
};
|
||||
}>;
|
||||
|
||||
// @public
|
||||
export type HeaderActionsApi = {
|
||||
getHeaderActions(pluginId: string): ReactNode[];
|
||||
};
|
||||
|
||||
// @public
|
||||
export const headerActionsApiRef: ApiRef_2<HeaderActionsApi>;
|
||||
|
||||
// @public @deprecated
|
||||
export type IconComponent = ComponentType<{
|
||||
fontSize?: 'medium' | 'large' | 'small' | 'inherit';
|
||||
@@ -1869,6 +1836,29 @@ export type PendingOAuthRequest = {
|
||||
trigger(): Promise<void>;
|
||||
};
|
||||
|
||||
// @public
|
||||
export const PluginHeaderActionBlueprint: ExtensionBlueprint_2<{
|
||||
kind: 'plugin-header-action';
|
||||
params: (params: {
|
||||
loader: () => Promise<JSX.Element>;
|
||||
}) => ExtensionBlueprintParams_2<{
|
||||
loader: () => Promise<JSX.Element>;
|
||||
}>;
|
||||
output: ExtensionDataRef_2<JSX_2, 'core.reactElement', {}>;
|
||||
inputs: {};
|
||||
config: {};
|
||||
configInput: {};
|
||||
dataRefs: never;
|
||||
}>;
|
||||
|
||||
// @public
|
||||
export type PluginHeaderActionsApi = {
|
||||
getPluginHeaderActions(pluginId: string): ReactNode[];
|
||||
};
|
||||
|
||||
// @public
|
||||
export const pluginHeaderActionsApiRef: ApiRef_2<PluginHeaderActionsApi>;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface PluginOptions<
|
||||
TId extends string,
|
||||
|
||||
+6
-6
@@ -23,23 +23,23 @@ import { createApiRef } from '../system';
|
||||
* @remarks
|
||||
*
|
||||
* Header actions are provided via
|
||||
* {@link @backstage/frontend-plugin-api#HeaderActionBlueprint}
|
||||
* {@link @backstage/frontend-plugin-api#PluginHeaderActionBlueprint}
|
||||
* and automatically scoped to the providing plugin.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type HeaderActionsApi = {
|
||||
export type PluginHeaderActionsApi = {
|
||||
/**
|
||||
* Returns the header actions for a given plugin.
|
||||
*/
|
||||
getHeaderActions(pluginId: string): ReactNode[];
|
||||
getPluginHeaderActions(pluginId: string): ReactNode[];
|
||||
};
|
||||
|
||||
/**
|
||||
* The `ApiRef` of {@link HeaderActionsApi}.
|
||||
* The `ApiRef` of {@link PluginHeaderActionsApi}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const headerActionsApiRef = createApiRef<HeaderActionsApi>({
|
||||
id: 'core.header-actions',
|
||||
export const pluginHeaderActionsApiRef = createApiRef<PluginHeaderActionsApi>({
|
||||
id: 'core.plugin-header-actions',
|
||||
});
|
||||
@@ -49,4 +49,4 @@ export * from './RouteResolutionApi';
|
||||
export * from './StorageApi';
|
||||
export * from './AnalyticsApi';
|
||||
export * from './TranslationApi';
|
||||
export * from './HeaderActionsApi';
|
||||
export * from './PluginHeaderActionsApi';
|
||||
|
||||
@@ -25,11 +25,11 @@ import {
|
||||
} from '../wiring';
|
||||
import { ExtensionBoundary, PageLayout, PageTab } from '../components';
|
||||
import { useApi } from '../apis/system';
|
||||
import { headerActionsApiRef } from '../apis/definitions/HeaderActionsApi';
|
||||
import { pluginHeaderActionsApiRef } from '../apis/definitions/PluginHeaderActionsApi';
|
||||
|
||||
function useHeaderActions(pluginId: string): ReactNode {
|
||||
const headerActionsApi = useApi(headerActionsApiRef);
|
||||
const actions = headerActionsApi.getHeaderActions(pluginId);
|
||||
function usePluginHeaderActions(pluginId: string): ReactNode {
|
||||
const pluginHeaderActionsApi = useApi(pluginHeaderActionsApiRef);
|
||||
const actions = pluginHeaderActionsApi.getPluginHeaderActions(pluginId);
|
||||
if (actions.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -97,7 +97,7 @@ export const PageBlueprint = createExtensionBlueprint({
|
||||
if (params.loader) {
|
||||
const loader = params.loader;
|
||||
const PageContent = () => {
|
||||
const headerActions = useHeaderActions(pluginId);
|
||||
const headerActions = usePluginHeaderActions(pluginId);
|
||||
return (
|
||||
<PageLayout
|
||||
title={title}
|
||||
@@ -127,7 +127,7 @@ export const PageBlueprint = createExtensionBlueprint({
|
||||
|
||||
const PageContent = () => {
|
||||
const firstPagePath = inputs.pages[0]?.get(coreExtensionData.routePath);
|
||||
const headerActions = useHeaderActions(pluginId);
|
||||
const headerActions = usePluginHeaderActions(pluginId);
|
||||
|
||||
return (
|
||||
<PageLayout
|
||||
@@ -158,7 +158,7 @@ export const PageBlueprint = createExtensionBlueprint({
|
||||
yield coreExtensionData.reactElement(<PageContent />);
|
||||
} else {
|
||||
const PageContent = () => {
|
||||
const headerActions = useHeaderActions(pluginId);
|
||||
const headerActions = usePluginHeaderActions(pluginId);
|
||||
return (
|
||||
<PageLayout title={title} icon={icon} headerActions={headerActions} />
|
||||
);
|
||||
|
||||
+3
-3
@@ -32,9 +32,9 @@ import {
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const HeaderActionBlueprint = createExtensionBlueprint({
|
||||
kind: 'header-action',
|
||||
attachTo: { id: 'api:app/header-actions', input: 'actions' },
|
||||
export const PluginHeaderActionBlueprint = createExtensionBlueprint({
|
||||
kind: 'plugin-header-action',
|
||||
attachTo: { id: 'api:app/plugin-header-actions', input: 'actions' },
|
||||
output: [coreExtensionData.reactElement],
|
||||
defineParams(params: { loader: () => Promise<JSX.Element> }) {
|
||||
return createExtensionBlueprintParams(params);
|
||||
@@ -23,4 +23,4 @@ export { AppRootElementBlueprint } from './AppRootElementBlueprint';
|
||||
export { NavItemBlueprint } from './NavItemBlueprint';
|
||||
export { PageBlueprint } from './PageBlueprint';
|
||||
export { SubPageBlueprint } from './SubPageBlueprint';
|
||||
export { HeaderActionBlueprint } from './HeaderActionBlueprint';
|
||||
export { PluginHeaderActionBlueprint } from './PluginHeaderActionBlueprint';
|
||||
|
||||
@@ -20,23 +20,6 @@ const visualizerPlugin: OverridableFrontendPlugin<
|
||||
{},
|
||||
{},
|
||||
{
|
||||
'header-action:app-visualizer': OverridableExtensionDefinition<{
|
||||
kind: 'header-action';
|
||||
name: undefined;
|
||||
config: {};
|
||||
configInput: {};
|
||||
output: ExtensionDataRef<
|
||||
() => Promise<JSX.Element>,
|
||||
'core.header-action.loader',
|
||||
{}
|
||||
>;
|
||||
inputs: {};
|
||||
params: (params: {
|
||||
loader: () => Promise<JSX.Element>;
|
||||
}) => ExtensionBlueprintParams<{
|
||||
loader: () => Promise<JSX.Element>;
|
||||
}>;
|
||||
}>;
|
||||
'nav-item:app-visualizer': OverridableExtensionDefinition<{
|
||||
kind: 'nav-item';
|
||||
name: undefined;
|
||||
@@ -130,11 +113,24 @@ const visualizerPlugin: OverridableFrontendPlugin<
|
||||
path: string;
|
||||
title?: string;
|
||||
icon?: IconElement;
|
||||
loader?: () => Promise<JSX.Element /** @public */>;
|
||||
loader?: () => Promise<JSX.Element>;
|
||||
routeRef?: RouteRef;
|
||||
noHeader?: boolean;
|
||||
};
|
||||
}>;
|
||||
'plugin-header-action:app-visualizer': OverridableExtensionDefinition<{
|
||||
kind: 'plugin-header-action';
|
||||
name: undefined;
|
||||
config: {};
|
||||
configInput: {};
|
||||
output: ExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>;
|
||||
inputs: {};
|
||||
params: (params: {
|
||||
loader: () => Promise<JSX.Element>;
|
||||
}) => ExtensionBlueprintParams<{
|
||||
loader: () => Promise<JSX.Element>;
|
||||
}>;
|
||||
}>;
|
||||
'sub-page:app-visualizer/details': OverridableExtensionDefinition<{
|
||||
kind: 'sub-page';
|
||||
name: 'details';
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
createRouteRef,
|
||||
NavItemBlueprint,
|
||||
PageBlueprint,
|
||||
HeaderActionBlueprint,
|
||||
PluginHeaderActionBlueprint,
|
||||
SubPageBlueprint,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import { RiEyeLine } from '@remixicon/react';
|
||||
@@ -75,7 +75,7 @@ const appVisualizerTextPage = SubPageBlueprint.make({
|
||||
},
|
||||
});
|
||||
|
||||
const copyTreeAsJson = HeaderActionBlueprint.make({
|
||||
const copyTreeAsJson = PluginHeaderActionBlueprint.make({
|
||||
params: defineParams =>
|
||||
defineParams({
|
||||
loader: () =>
|
||||
|
||||
+24
-28
@@ -469,34 +469,6 @@ const appPlugin: OverridableFrontendPlugin<
|
||||
params: ApiFactory<TApi, TImpl, TDeps>,
|
||||
) => ExtensionBlueprintParams<AnyApiFactory>;
|
||||
}>;
|
||||
'api:app/header-actions': OverridableExtensionDefinition<{
|
||||
config: {};
|
||||
configInput: {};
|
||||
output: ExtensionDataRef<AnyApiFactory, 'core.api.factory', {}>;
|
||||
inputs: {
|
||||
actions: ExtensionInput<
|
||||
ConfigurableExtensionDataRef<
|
||||
() => Promise<JSX.Element>,
|
||||
'core.header-action.loader',
|
||||
{}
|
||||
>,
|
||||
{
|
||||
singleton: false;
|
||||
optional: false;
|
||||
internal: false;
|
||||
}
|
||||
>;
|
||||
};
|
||||
kind: 'api';
|
||||
name: 'header-actions';
|
||||
params: <
|
||||
TApi,
|
||||
TImpl extends TApi,
|
||||
TDeps extends { [name in string]: unknown },
|
||||
>(
|
||||
params: ApiFactory<TApi, TImpl, TDeps>,
|
||||
) => ExtensionBlueprintParams<AnyApiFactory>;
|
||||
}>;
|
||||
'api:app/icons': OverridableExtensionDefinition<{
|
||||
config: {};
|
||||
configInput: {};
|
||||
@@ -617,6 +589,30 @@ const appPlugin: OverridableFrontendPlugin<
|
||||
params: ApiFactory<TApi, TImpl, TDeps>,
|
||||
) => ExtensionBlueprintParams<AnyApiFactory>;
|
||||
}>;
|
||||
'api:app/plugin-header-actions': OverridableExtensionDefinition<{
|
||||
config: {};
|
||||
configInput: {};
|
||||
output: ExtensionDataRef<AnyApiFactory, 'core.api.factory', {}>;
|
||||
inputs: {
|
||||
actions: ExtensionInput<
|
||||
ConfigurableExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>,
|
||||
{
|
||||
singleton: false;
|
||||
optional: false;
|
||||
internal: false;
|
||||
}
|
||||
>;
|
||||
};
|
||||
kind: 'api';
|
||||
name: 'plugin-header-actions';
|
||||
params: <
|
||||
TApi,
|
||||
TImpl extends TApi,
|
||||
TDeps extends { [name in string]: unknown },
|
||||
>(
|
||||
params: ApiFactory<TApi, TImpl, TDeps>,
|
||||
) => ExtensionBlueprintParams<AnyApiFactory>;
|
||||
}>;
|
||||
'api:app/plugin-wrapper': OverridableExtensionDefinition<{
|
||||
config: {};
|
||||
configInput: {};
|
||||
|
||||
+10
-10
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { DefaultHeaderActionsApi } from './DefaultHeaderActionsApi';
|
||||
import { DefaultPluginHeaderActionsApi } from './DefaultPluginHeaderActionsApi';
|
||||
|
||||
describe('DefaultHeaderActionsApi', () => {
|
||||
describe('DefaultPluginHeaderActionsApi', () => {
|
||||
it('should return actions for a specific plugin', () => {
|
||||
const api = DefaultHeaderActionsApi.fromActions([
|
||||
const api = DefaultPluginHeaderActionsApi.fromActions([
|
||||
{
|
||||
element: <button>Action A</button>,
|
||||
pluginId: 'plugin-a',
|
||||
@@ -30,28 +30,28 @@ describe('DefaultHeaderActionsApi', () => {
|
||||
},
|
||||
]);
|
||||
|
||||
expect(api.getHeaderActions('plugin-a')).toHaveLength(1);
|
||||
expect(api.getHeaderActions('plugin-b')).toHaveLength(1);
|
||||
expect(api.getPluginHeaderActions('plugin-a')).toHaveLength(1);
|
||||
expect(api.getPluginHeaderActions('plugin-b')).toHaveLength(1);
|
||||
|
||||
render(<>{api.getHeaderActions('plugin-a')}</>);
|
||||
render(<>{api.getPluginHeaderActions('plugin-a')}</>);
|
||||
expect(
|
||||
screen.getByRole('button', { name: 'Action A' }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should return an empty array for unknown plugins', () => {
|
||||
const api = DefaultHeaderActionsApi.fromActions([
|
||||
const api = DefaultPluginHeaderActionsApi.fromActions([
|
||||
{
|
||||
element: <span>Action</span>,
|
||||
pluginId: 'plugin-a',
|
||||
},
|
||||
]);
|
||||
|
||||
expect(api.getHeaderActions('unknown-plugin')).toEqual([]);
|
||||
expect(api.getPluginHeaderActions('unknown-plugin')).toEqual([]);
|
||||
});
|
||||
|
||||
it('should group multiple actions by plugin', () => {
|
||||
const api = DefaultHeaderActionsApi.fromActions([
|
||||
const api = DefaultPluginHeaderActionsApi.fromActions([
|
||||
{
|
||||
element: <button>First</button>,
|
||||
pluginId: 'plugin-a',
|
||||
@@ -62,7 +62,7 @@ describe('DefaultHeaderActionsApi', () => {
|
||||
},
|
||||
]);
|
||||
|
||||
const actions = api.getHeaderActions('plugin-a');
|
||||
const actions = api.getPluginHeaderActions('plugin-a');
|
||||
expect(actions).toHaveLength(2);
|
||||
|
||||
render(<>{actions}</>);
|
||||
+8
-6
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { ReactNode } from 'react';
|
||||
import { type HeaderActionsApi } from '@backstage/frontend-plugin-api';
|
||||
import { type PluginHeaderActionsApi } from '@backstage/frontend-plugin-api';
|
||||
|
||||
type ActionInput = {
|
||||
element: JSX.Element;
|
||||
@@ -23,18 +23,20 @@ type ActionInput = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Default implementation of HeaderActionsApi.
|
||||
* Default implementation of PluginHeaderActionsApi.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export class DefaultHeaderActionsApi implements HeaderActionsApi {
|
||||
export class DefaultPluginHeaderActionsApi implements PluginHeaderActionsApi {
|
||||
constructor(private readonly actionsByPlugin: Map<string, ReactNode[]>) {}
|
||||
|
||||
getHeaderActions(pluginId: string): ReactNode[] {
|
||||
getPluginHeaderActions(pluginId: string): ReactNode[] {
|
||||
return this.actionsByPlugin.get(pluginId) ?? [];
|
||||
}
|
||||
|
||||
static fromActions(actions: Array<ActionInput>): DefaultHeaderActionsApi {
|
||||
static fromActions(
|
||||
actions: Array<ActionInput>,
|
||||
): DefaultPluginHeaderActionsApi {
|
||||
const actionsByPlugin = new Map<string, ReactNode[]>();
|
||||
|
||||
for (const action of actions) {
|
||||
@@ -47,6 +49,6 @@ export class DefaultHeaderActionsApi implements HeaderActionsApi {
|
||||
pluginActions.push(action.element);
|
||||
}
|
||||
|
||||
return new DefaultHeaderActionsApi(actionsByPlugin);
|
||||
return new DefaultPluginHeaderActionsApi(actionsByPlugin);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -14,4 +14,4 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { DefaultHeaderActionsApi } from './DefaultHeaderActionsApi';
|
||||
export { DefaultPluginHeaderActionsApi } from './DefaultPluginHeaderActionsApi';
|
||||
+6
-6
@@ -16,27 +16,27 @@
|
||||
|
||||
import {
|
||||
coreExtensionData,
|
||||
headerActionsApiRef,
|
||||
pluginHeaderActionsApiRef,
|
||||
createExtensionInput,
|
||||
ApiBlueprint,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import { DefaultHeaderActionsApi } from '../apis/HeaderActionsApi';
|
||||
import { DefaultPluginHeaderActionsApi } from '../apis/PluginHeaderActionsApi';
|
||||
|
||||
/**
|
||||
* Contains the plugin-scoped header actions installed into the app.
|
||||
*/
|
||||
export const HeaderActionsApi = ApiBlueprint.makeWithOverrides({
|
||||
name: 'header-actions',
|
||||
export const PluginHeaderActionsApi = ApiBlueprint.makeWithOverrides({
|
||||
name: 'plugin-header-actions',
|
||||
inputs: {
|
||||
actions: createExtensionInput([coreExtensionData.reactElement]),
|
||||
},
|
||||
factory: (originalFactory, { inputs }) => {
|
||||
return originalFactory(defineParams =>
|
||||
defineParams({
|
||||
api: headerActionsApiRef,
|
||||
api: pluginHeaderActionsApiRef,
|
||||
deps: {},
|
||||
factory: () => {
|
||||
return DefaultHeaderActionsApi.fromActions(
|
||||
return DefaultPluginHeaderActionsApi.fromActions(
|
||||
inputs.actions.map(actionInput => ({
|
||||
element: actionInput.get(coreExtensionData.reactElement),
|
||||
pluginId: actionInput.node.spec.plugin.pluginId,
|
||||
@@ -38,4 +38,4 @@ export {
|
||||
PageLayout,
|
||||
} from './components';
|
||||
export { PluginWrapperApi } from './PluginWrapperApi';
|
||||
export { HeaderActionsApi } from './HeaderActionsApi';
|
||||
export { PluginHeaderActionsApi } from './PluginHeaderActionsApi';
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
IconsApi,
|
||||
FeatureFlagsApi,
|
||||
PluginWrapperApi,
|
||||
HeaderActionsApi,
|
||||
PluginHeaderActionsApi,
|
||||
TranslationsApi,
|
||||
oauthRequestDialogAppRootElement,
|
||||
alertDisplayAppRootElement,
|
||||
@@ -62,7 +62,7 @@ export const appPlugin = createFrontendPlugin({
|
||||
IconsApi,
|
||||
FeatureFlagsApi,
|
||||
PluginWrapperApi,
|
||||
HeaderActionsApi,
|
||||
PluginHeaderActionsApi,
|
||||
TranslationsApi,
|
||||
DefaultSignInPage,
|
||||
oauthRequestDialogAppRootElement,
|
||||
|
||||
Reference in New Issue
Block a user