detach the badges plugin from the catalog plugin
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-search-backend': patch
|
||||
'@backstage/plugin-search-backend-node': patch
|
||||
---
|
||||
|
||||
Bump to use the in-repo latest `backend-common`, and the correct version of `express-promise-router`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-badges': patch
|
||||
---
|
||||
|
||||
Get the current entity using `useEntity` from `@backstage/plugin-catalog-react`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog': patch
|
||||
---
|
||||
|
||||
Temporarily add `UNSTABLE_extraContextMenuItems` to the entity layout, so that we could detach the catalog plugin from the dependency on the badges plugin
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Update the create-app template to use the correct latest version of `express-promise-router`.
|
||||
|
||||
To apply the same change in your own repository, update all of your repo's dependencies on `express-promise-router` to `"^4.1.0"`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Make the backend plugin template use the correct latest version of `express-promise-router`
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
ProvidedApisCard,
|
||||
ProvidingComponentsCard,
|
||||
} from '@backstage/plugin-api-docs';
|
||||
import { EntityBadgesDialog } from '@backstage/plugin-badges';
|
||||
import {
|
||||
AboutCard,
|
||||
EntityHasComponentsCard,
|
||||
@@ -104,7 +105,8 @@ import {
|
||||
RecentTravisCIBuildsWidget,
|
||||
Router as TravisCIRouter,
|
||||
} from '@roadiehq/backstage-plugin-travis-ci';
|
||||
import React, { ReactNode } from 'react';
|
||||
import React, { ReactNode, useMemo, useState } from 'react';
|
||||
import BadgeIcon from '@material-ui/icons/CallToAction';
|
||||
|
||||
export const CICDSwitcher = ({ entity }: { entity: Entity }) => {
|
||||
// This component is just an example of how you can implement your company's logic in entity page.
|
||||
@@ -178,6 +180,32 @@ export const ErrorsSwitcher = ({ entity }: { entity: Entity }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const EntityPageLayoutWrapper = (props: { children?: React.ReactNode }) => {
|
||||
const [badgesDialogOpen, setBadgesDialogOpen] = useState(false);
|
||||
|
||||
const extraMenuItems = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
title: 'Badges',
|
||||
Icon: BadgeIcon,
|
||||
onClick: () => setBadgesDialogOpen(true),
|
||||
},
|
||||
];
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<EntityPageLayout UNSTABLE_extraContextMenuItems={extraMenuItems}>
|
||||
{props.children}
|
||||
</EntityPageLayout>
|
||||
<EntityBadgesDialog
|
||||
open={badgesDialogOpen}
|
||||
onClose={() => setBadgesDialogOpen(false)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const ComponentOverviewContent = ({ entity }: { entity: Entity }) => (
|
||||
<Grid container spacing={3} alignItems="stretch">
|
||||
<Grid item md={6}>
|
||||
@@ -233,7 +261,7 @@ const ComponentApisContent = ({ entity }: { entity: Entity }) => (
|
||||
);
|
||||
|
||||
const ServiceEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
<EntityPageLayout>
|
||||
<EntityPageLayoutWrapper>
|
||||
<EntityPageLayout.Content
|
||||
path="/"
|
||||
title="Overview"
|
||||
@@ -284,11 +312,11 @@ const ServiceEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
title="TODOs"
|
||||
element={<EntityTodoContent />}
|
||||
/>
|
||||
</EntityPageLayout>
|
||||
</EntityPageLayoutWrapper>
|
||||
);
|
||||
|
||||
const WebsiteEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
<EntityPageLayout>
|
||||
<EntityPageLayoutWrapper>
|
||||
<EntityPageLayout.Content
|
||||
path="/"
|
||||
title="Overview"
|
||||
@@ -334,11 +362,11 @@ const WebsiteEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
title="TODOs"
|
||||
element={<EntityTodoContent />}
|
||||
/>
|
||||
</EntityPageLayout>
|
||||
</EntityPageLayoutWrapper>
|
||||
);
|
||||
|
||||
const DefaultEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
<EntityPageLayout>
|
||||
<EntityPageLayoutWrapper>
|
||||
<EntityPageLayout.Content
|
||||
path="/*"
|
||||
title="Overview"
|
||||
@@ -354,7 +382,7 @@ const DefaultEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
title="TODOs"
|
||||
element={<EntityTodoContent />}
|
||||
/>
|
||||
</EntityPageLayout>
|
||||
</EntityPageLayoutWrapper>
|
||||
);
|
||||
|
||||
export const ComponentEntityPage = ({ entity }: { entity: Entity }) => {
|
||||
@@ -393,7 +421,7 @@ const ApiDefinitionContent = ({ entity }: { entity: ApiEntity }) => (
|
||||
);
|
||||
|
||||
const ApiEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
<EntityPageLayout>
|
||||
<EntityPageLayoutWrapper>
|
||||
<EntityPageLayout.Content
|
||||
path="/*"
|
||||
title="Overview"
|
||||
@@ -404,7 +432,7 @@ const ApiEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
title="Definition"
|
||||
element={<ApiDefinitionContent entity={entity as ApiEntity} />}
|
||||
/>
|
||||
</EntityPageLayout>
|
||||
</EntityPageLayoutWrapper>
|
||||
);
|
||||
|
||||
const UserOverviewContent = ({ entity }: { entity: UserEntity }) => (
|
||||
@@ -419,13 +447,13 @@ const UserOverviewContent = ({ entity }: { entity: UserEntity }) => (
|
||||
);
|
||||
|
||||
const UserEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
<EntityPageLayout>
|
||||
<EntityPageLayoutWrapper>
|
||||
<EntityPageLayout.Content
|
||||
path="/*"
|
||||
title="Overview"
|
||||
element={<UserOverviewContent entity={entity as UserEntity} />}
|
||||
/>
|
||||
</EntityPageLayout>
|
||||
</EntityPageLayoutWrapper>
|
||||
);
|
||||
|
||||
const GroupOverviewContent = ({ entity }: { entity: GroupEntity }) => (
|
||||
@@ -443,13 +471,13 @@ const GroupOverviewContent = ({ entity }: { entity: GroupEntity }) => (
|
||||
);
|
||||
|
||||
const GroupEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
<EntityPageLayout>
|
||||
<EntityPageLayoutWrapper>
|
||||
<EntityPageLayout.Content
|
||||
path="/*"
|
||||
title="Overview"
|
||||
element={<GroupOverviewContent entity={entity as GroupEntity} />}
|
||||
/>
|
||||
</EntityPageLayout>
|
||||
</EntityPageLayoutWrapper>
|
||||
);
|
||||
|
||||
const SystemOverviewContent = ({ entity }: { entity: SystemEntity }) => (
|
||||
@@ -467,13 +495,13 @@ const SystemOverviewContent = ({ entity }: { entity: SystemEntity }) => (
|
||||
);
|
||||
|
||||
const SystemEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
<EntityPageLayout>
|
||||
<EntityPageLayoutWrapper>
|
||||
<EntityPageLayout.Content
|
||||
path="/*"
|
||||
title="Overview"
|
||||
element={<SystemOverviewContent entity={entity as SystemEntity} />}
|
||||
/>
|
||||
</EntityPageLayout>
|
||||
</EntityPageLayoutWrapper>
|
||||
);
|
||||
|
||||
const DomainOverviewContent = ({ entity }: { entity: DomainEntity }) => (
|
||||
@@ -488,13 +516,13 @@ const DomainOverviewContent = ({ entity }: { entity: DomainEntity }) => (
|
||||
);
|
||||
|
||||
const DomainEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
<EntityPageLayout>
|
||||
<EntityPageLayoutWrapper>
|
||||
<EntityPageLayout.Content
|
||||
path="/*"
|
||||
title="Overview"
|
||||
element={<DomainOverviewContent entity={entity as DomainEntity} />}
|
||||
/>
|
||||
</EntityPageLayout>
|
||||
</EntityPageLayoutWrapper>
|
||||
);
|
||||
|
||||
export const EntityPage = () => {
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"@backstage/config": "^{{version '@backstage/config'}}",
|
||||
"@types/express": "^4.17.6",
|
||||
"express": "^4.17.1",
|
||||
"express-promise-router": "^3.0.3",
|
||||
"express-promise-router": "^4.1.0",
|
||||
"winston": "^3.2.1",
|
||||
"cross-fetch": "^3.0.6",
|
||||
"yn": "^4.0.0"
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"@octokit/rest": "^18.0.12",
|
||||
"dockerode": "^3.2.1",
|
||||
"express": "^4.17.1",
|
||||
"express-promise-router": "^3.0.3",
|
||||
"express-promise-router": "^4.1.0",
|
||||
"knex": "^0.21.6",
|
||||
{{#if dbTypePG}}
|
||||
"pg": "^8.3.0",
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
import { renderWithEffects } from '@backstage/test-utils';
|
||||
import { BadgesApi, badgesApiRef } from '../api';
|
||||
import { EntityBadgesDialog } from './EntityBadgesDialog';
|
||||
import { EntityProvider } from '@backstage/plugin-catalog-react';
|
||||
|
||||
describe('EntityBadgesDialog', () => {
|
||||
it('should render', async () => {
|
||||
@@ -50,7 +51,9 @@ describe('EntityBadgesDialog', () => {
|
||||
{} as ErrorApi,
|
||||
)}
|
||||
>
|
||||
<EntityBadgesDialog open entity={mockEntity} />
|
||||
<EntityProvider entity={mockEntity}>
|
||||
<EntityBadgesDialog open />
|
||||
</EntityProvider>
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import {
|
||||
CodeSnippet,
|
||||
Progress,
|
||||
ResponseErrorPanel,
|
||||
useApi,
|
||||
} from '@backstage/core';
|
||||
import { useEntity } from '@backstage/plugin-catalog-react';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@@ -39,43 +39,44 @@ import { badgesApiRef } from '../api';
|
||||
type Props = {
|
||||
open: boolean;
|
||||
onClose?: () => any;
|
||||
entity: Entity;
|
||||
};
|
||||
|
||||
export const EntityBadgesDialog = ({ open, onClose, entity }: Props) => {
|
||||
export const EntityBadgesDialog = ({ open, onClose }: Props) => {
|
||||
const theme = useTheme();
|
||||
const { entity } = useEntity();
|
||||
const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));
|
||||
const badgesApi = useApi(badgesApiRef);
|
||||
|
||||
const { value: badges, loading, error } = useAsync(async () => {
|
||||
if (open) {
|
||||
if (open && entity) {
|
||||
return await badgesApi.getEntityBadgeSpecs(entity);
|
||||
}
|
||||
|
||||
return [];
|
||||
}, [badgesApi, entity, open]);
|
||||
|
||||
const content = (badges || []).map(
|
||||
({ badge: { description }, id, url, markdown }) => (
|
||||
<DialogContentText>
|
||||
<Box m={4} />
|
||||
<img alt={description || id} src={url} />
|
||||
<CodeSnippet language="markdown" text={markdown} showCopyCodeButton />
|
||||
</DialogContentText>
|
||||
<Box marginTop={4} key={id}>
|
||||
<DialogContentText component="div">
|
||||
<img alt={description || id} src={url} />
|
||||
<CodeSnippet language="markdown" text={markdown} showCopyCodeButton />
|
||||
</DialogContentText>
|
||||
</Box>
|
||||
),
|
||||
);
|
||||
|
||||
return (
|
||||
<Dialog fullScreen={fullScreen} open={open} onClose={onClose}>
|
||||
<DialogTitle>Entity Badges</DialogTitle>
|
||||
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
Embed badges in other web sites that link back to this entity. Copy
|
||||
the relevant snippet of Markdown code to use the badge.
|
||||
</DialogContentText>
|
||||
|
||||
{loading && <Progress />}
|
||||
{error && <ResponseErrorPanel error={error} />}
|
||||
|
||||
{content}
|
||||
</DialogContent>
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
"@backstage/core": "^0.7.2",
|
||||
"@backstage/integration": "^0.5.1",
|
||||
"@backstage/integration-react": "^0.1.1",
|
||||
"@backstage/plugin-badges": "^0.1.1",
|
||||
"@backstage/plugin-catalog-react": "^0.1.2",
|
||||
"@backstage/theme": "^0.2.4",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
|
||||
@@ -14,22 +14,53 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import SearchIcon from '@material-ui/icons/Search';
|
||||
import { fireEvent, screen } from '@testing-library/react';
|
||||
import * as React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { EntityContextMenu } from './EntityContextMenu';
|
||||
|
||||
describe('ComponentContextMenu', () => {
|
||||
it('should call onUnregisterEntity on button click', async () => {
|
||||
await act(async () => {
|
||||
const mockCallback = jest.fn();
|
||||
const menu = render(
|
||||
<EntityContextMenu onUnregisterEntity={mockCallback} />,
|
||||
);
|
||||
const button = await menu.findByTestId('menu-button');
|
||||
fireEvent.click(button);
|
||||
const unregister = await menu.findByText('Unregister entity');
|
||||
expect(unregister).toBeInTheDocument();
|
||||
});
|
||||
const mockCallback = jest.fn();
|
||||
|
||||
await renderInTestApp(
|
||||
<EntityContextMenu onUnregisterEntity={mockCallback} />,
|
||||
);
|
||||
|
||||
const button = await screen.findByTestId('menu-button');
|
||||
expect(button).toBeInTheDocument();
|
||||
fireEvent.click(button);
|
||||
|
||||
const unregister = await screen.findByText('Unregister entity');
|
||||
expect(unregister).toBeInTheDocument();
|
||||
fireEvent.click(unregister);
|
||||
|
||||
expect(mockCallback).toBeCalled();
|
||||
});
|
||||
|
||||
it('supports extra items', async () => {
|
||||
const extra = {
|
||||
title: 'HELLO',
|
||||
Icon: SearchIcon,
|
||||
onClick: jest.fn(),
|
||||
};
|
||||
|
||||
await renderInTestApp(
|
||||
<EntityContextMenu
|
||||
onUnregisterEntity={jest.fn()}
|
||||
UNSTABLE_extraContextMenuItems={[extra]}
|
||||
/>,
|
||||
);
|
||||
|
||||
const button = await screen.findByTestId('menu-button');
|
||||
expect(button).toBeInTheDocument();
|
||||
fireEvent.click(button);
|
||||
|
||||
const item = await screen.findByText('HELLO');
|
||||
expect(item).toBeInTheDocument();
|
||||
fireEvent.click(item);
|
||||
|
||||
expect(extra.onClick).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,17 +14,18 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { IconComponent } from '@backstage/core';
|
||||
import {
|
||||
Divider,
|
||||
IconButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
MenuItem,
|
||||
MenuList,
|
||||
Popover,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Cancel from '@material-ui/icons/Cancel';
|
||||
import BadgeIcon from '@material-ui/icons/CallToAction';
|
||||
import MoreVert from '@material-ui/icons/MoreVert';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
@@ -35,13 +36,21 @@ const useStyles = makeStyles({
|
||||
},
|
||||
});
|
||||
|
||||
// NOTE(freben): Intentionally not exported at this point, since it's part of
|
||||
// the unstable extra context menu items concept below
|
||||
type ExtraContextMenuItem = {
|
||||
title: string;
|
||||
Icon: IconComponent;
|
||||
onClick: () => void;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
onShowBadgesDialog?: () => void;
|
||||
UNSTABLE_extraContextMenuItems?: ExtraContextMenuItem[];
|
||||
onUnregisterEntity: () => void;
|
||||
};
|
||||
|
||||
export const EntityContextMenu = ({
|
||||
onShowBadgesDialog,
|
||||
UNSTABLE_extraContextMenuItems,
|
||||
onUnregisterEntity,
|
||||
}: Props) => {
|
||||
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement>();
|
||||
@@ -55,6 +64,24 @@ export const EntityContextMenu = ({
|
||||
setAnchorEl(undefined);
|
||||
};
|
||||
|
||||
const extraItems = UNSTABLE_extraContextMenuItems && [
|
||||
...UNSTABLE_extraContextMenuItems.map(item => (
|
||||
<MenuItem
|
||||
key={item.title}
|
||||
onClick={() => {
|
||||
onClose();
|
||||
item.onClick();
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<item.Icon fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={item.title} />
|
||||
</MenuItem>
|
||||
)),
|
||||
<Divider key="the divider is here!" />,
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<IconButton
|
||||
@@ -75,19 +102,7 @@ export const EntityContextMenu = ({
|
||||
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
|
||||
>
|
||||
<MenuList>
|
||||
{onShowBadgesDialog && (
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
onClose();
|
||||
onShowBadgesDialog();
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<BadgeIcon fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">Badges</Typography>
|
||||
</MenuItem>
|
||||
)}
|
||||
{extraItems}
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
onClose();
|
||||
@@ -97,7 +112,7 @@ export const EntityContextMenu = ({
|
||||
<ListItemIcon>
|
||||
<Cancel fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">Unregister entity</Typography>
|
||||
<ListItemText primary="Unregister entity" />
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
</Popover>
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
Content,
|
||||
Header,
|
||||
HeaderLabel,
|
||||
IconComponent,
|
||||
Page,
|
||||
Progress,
|
||||
TabbedLayout,
|
||||
@@ -29,12 +30,7 @@ import {
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import { Box } from '@material-ui/core';
|
||||
import { Alert } from '@material-ui/lab';
|
||||
import {
|
||||
default as React,
|
||||
PropsWithChildren,
|
||||
useContext,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { default as React, useContext, useState } from 'react';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { EntityContextMenu } from '../EntityContextMenu/EntityContextMenu';
|
||||
import { FavouriteEntity } from '../FavouriteEntity/FavouriteEntity';
|
||||
@@ -79,6 +75,19 @@ const headerProps = (
|
||||
};
|
||||
};
|
||||
|
||||
// NOTE(freben): Intentionally not exported at this point, since it's part of
|
||||
// the unstable extra context menu items concept below
|
||||
type ExtraContextMenuItem = {
|
||||
title: string;
|
||||
Icon: IconComponent;
|
||||
onClick: () => void;
|
||||
};
|
||||
|
||||
type EntityLayoutProps = {
|
||||
UNSTABLE_extraContextMenuItems?: ExtraContextMenuItem[];
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* EntityLayout is a compound component, which allows you to define a layout for
|
||||
* entities using a sub-navigation mechanism.
|
||||
@@ -94,7 +103,10 @@ const headerProps = (
|
||||
* </EntityLayout>
|
||||
* ```
|
||||
*/
|
||||
export const EntityLayout = ({ children }: PropsWithChildren<{}>) => {
|
||||
export const EntityLayout = ({
|
||||
UNSTABLE_extraContextMenuItems,
|
||||
children,
|
||||
}: EntityLayoutProps) => {
|
||||
const { kind, namespace, name } = useEntityCompoundName();
|
||||
const { entity, loading, error } = useContext(EntityContext);
|
||||
|
||||
@@ -132,7 +144,10 @@ export const EntityLayout = ({ children }: PropsWithChildren<{}>) => {
|
||||
label="Lifecycle"
|
||||
value={entity.spec?.lifecycle || 'unknown'}
|
||||
/>
|
||||
<EntityContextMenu onUnregisterEntity={showRemovalDialog} />
|
||||
<EntityContextMenu
|
||||
UNSTABLE_extraContextMenuItems={UNSTABLE_extraContextMenuItems}
|
||||
onUnregisterEntity={showRemovalDialog}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Header>
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
Progress,
|
||||
ResponseErrorPanel,
|
||||
WarningPanel,
|
||||
IconComponent,
|
||||
} from '@backstage/core';
|
||||
import {
|
||||
EntityContext,
|
||||
@@ -35,12 +36,11 @@ import {
|
||||
useEntityCompoundName,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import { Box } from '@material-ui/core';
|
||||
import React, { PropsWithChildren, useContext, useState } from 'react';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { EntityContextMenu } from '../EntityContextMenu/EntityContextMenu';
|
||||
import { FavouriteEntity } from '../FavouriteEntity/FavouriteEntity';
|
||||
import { UnregisterEntityDialog } from '../UnregisterEntityDialog/UnregisterEntityDialog';
|
||||
import { EntityBadgesDialog } from '@backstage/plugin-badges';
|
||||
import { Tabbed } from './Tabbed';
|
||||
|
||||
const EntityPageTitle = ({
|
||||
@@ -99,7 +99,23 @@ const headerProps = (
|
||||
};
|
||||
};
|
||||
|
||||
export const EntityPageLayout = ({ children }: PropsWithChildren<{}>) => {
|
||||
// NOTE(freben): Intentionally not exported at this point, since it's part of
|
||||
// the unstable extra context menu items concept below
|
||||
type ExtraContextMenuItem = {
|
||||
title: string;
|
||||
Icon: IconComponent;
|
||||
onClick: () => void;
|
||||
};
|
||||
|
||||
type EntityPageLayoutProps = {
|
||||
UNSTABLE_extraContextMenuItems?: ExtraContextMenuItem[];
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
export const EntityPageLayout = ({
|
||||
children,
|
||||
UNSTABLE_extraContextMenuItems,
|
||||
}: EntityPageLayoutProps) => {
|
||||
const { kind, namespace, name } = useEntityCompoundName();
|
||||
const { entity, loading, error } = useContext(EntityContext);
|
||||
const { headerTitle, headerType } = headerProps(
|
||||
@@ -109,7 +125,6 @@ export const EntityPageLayout = ({ children }: PropsWithChildren<{}>) => {
|
||||
entity!,
|
||||
);
|
||||
|
||||
const [badgesDialogOpen, setBadgesDialogOpen] = useState(false);
|
||||
const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
const cleanUpAfterRemoval = async () => {
|
||||
@@ -131,7 +146,7 @@ export const EntityPageLayout = ({ children }: PropsWithChildren<{}>) => {
|
||||
<>
|
||||
<EntityLabels entity={entity} />
|
||||
<EntityContextMenu
|
||||
onShowBadgesDialog={() => setBadgesDialogOpen(true)}
|
||||
UNSTABLE_extraContextMenuItems={UNSTABLE_extraContextMenuItems}
|
||||
onUnregisterEntity={showRemovalDialog}
|
||||
/>
|
||||
</>
|
||||
@@ -164,14 +179,6 @@ export const EntityPageLayout = ({ children }: PropsWithChildren<{}>) => {
|
||||
</Content>
|
||||
)}
|
||||
|
||||
{entity && (
|
||||
<EntityBadgesDialog
|
||||
open={badgesDialogOpen}
|
||||
entity={entity}
|
||||
onClose={() => setBadgesDialogOpen(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<UnregisterEntityDialog
|
||||
open={confirmationDialogOpen}
|
||||
entity={entity!}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"winston": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/backend-common": "0.5.6",
|
||||
"@backstage/backend-common": "^0.6.0",
|
||||
"@backstage/cli": "^0.6.0"
|
||||
},
|
||||
"files": [
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.5.3",
|
||||
"@backstage/backend-common": "^0.6.0",
|
||||
"@backstage/search-common": "^0.1.1",
|
||||
"@types/express": "^4.17.6",
|
||||
"express": "^4.17.1",
|
||||
"express-promise-router": "^3.0.3",
|
||||
"express-promise-router": "^4.1.0",
|
||||
"winston": "^3.2.1",
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
|
||||
@@ -1980,7 +1980,6 @@
|
||||
"@backstage/core" "^0.7.2"
|
||||
"@backstage/integration" "^0.5.1"
|
||||
"@backstage/integration-react" "^0.1.1"
|
||||
"@backstage/plugin-badges" "^0.1.1"
|
||||
"@backstage/plugin-catalog-react" "^0.1.2"
|
||||
"@backstage/theme" "^0.2.4"
|
||||
"@material-ui/core" "^4.11.0"
|
||||
@@ -2005,7 +2004,6 @@
|
||||
"@backstage/core" "^0.7.2"
|
||||
"@backstage/integration" "^0.5.1"
|
||||
"@backstage/integration-react" "^0.1.1"
|
||||
"@backstage/plugin-badges" "^0.1.1"
|
||||
"@backstage/plugin-catalog-react" "^0.1.2"
|
||||
"@backstage/theme" "^0.2.4"
|
||||
"@material-ui/core" "^4.11.0"
|
||||
|
||||
Reference in New Issue
Block a user