+
setMenuOpen(!menuOpen)}
+ onClick={onOpen}
data-testid="menu-button"
+ className={classes.button}
>
-
+
+
+
+
+
);
};
+
export default ComponentContextMenu;
diff --git a/plugins/catalog/src/components/ComponentMetadataCard/ComponentMetadataCard.test.tsx b/plugins/catalog/src/components/ComponentMetadataCard/ComponentMetadataCard.test.tsx
index 62e3d52c29..5b6e7dfe07 100644
--- a/plugins/catalog/src/components/ComponentMetadataCard/ComponentMetadataCard.test.tsx
+++ b/plugins/catalog/src/components/ComponentMetadataCard/ComponentMetadataCard.test.tsx
@@ -23,6 +23,7 @@ describe('ComponentMetadataCard component', () => {
const testComponent: Component = {
name: 'test',
kind: 'Component',
+ metadata: { name: 'test' },
description: 'Placeholder',
};
const rendered = await render(
diff --git a/plugins/catalog/src/components/ComponentRemovalDialog/ComponentRemovalDialog.tsx b/plugins/catalog/src/components/ComponentRemovalDialog/ComponentRemovalDialog.tsx
index 7dde95c8f0..1318edcca0 100644
--- a/plugins/catalog/src/components/ComponentRemovalDialog/ComponentRemovalDialog.tsx
+++ b/plugins/catalog/src/components/ComponentRemovalDialog/ComponentRemovalDialog.tsx
@@ -13,7 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import React, { FC } from 'react';
+
+import { Entity, LOCATION_ANNOTATION } from '@backstage/catalog-model';
+import { Progress, useApi } from '@backstage/core';
import {
Button,
Dialog,
@@ -21,14 +23,16 @@ import {
DialogContent,
DialogContentText,
DialogTitle,
+ Typography,
useMediaQuery,
useTheme,
} from '@material-ui/core';
-import { Component } from '../../data/component';
+import Alert from '@material-ui/lab/Alert';
+import React, { FC } from 'react';
import { useAsync } from 'react-use';
-import { useApi } from '@backstage/core';
+import { AsyncState } from 'react-use/lib/useAsync';
import { catalogApiRef } from '../../api/types';
-import { Entity } from '@backstage/catalog-model';
+import { Component } from '../../data/component';
type ComponentRemovalDialogProps = {
onConfirm: () => any;
@@ -36,44 +40,79 @@ type ComponentRemovalDialogProps = {
onClose: () => any;
component: Component;
};
+
+function useColocatedEntities(component: Component): AsyncState
{
+ const catalogApi = useApi(catalogApiRef);
+ return useAsync(async () => {
+ const myLocation = component.metadata.annotations?.[LOCATION_ANNOTATION];
+ return myLocation
+ ? await catalogApi.getEntities({ [LOCATION_ANNOTATION]: myLocation })
+ : [];
+ }, [catalogApi, component]);
+}
+
const ComponentRemovalDialog: FC = ({
onConfirm,
onCancel,
onClose,
component,
}) => {
- const catalogApi = useApi(catalogApiRef);
- const { value } = useAsync(async () => {
- let colocatedEntities: Array = [];
- const locationId = component.location?.id;
- if (locationId) {
- colocatedEntities = await catalogApi.getEntitiesByLocationId(locationId);
- }
- return colocatedEntities;
- });
+ const { value: entities, loading, error } = useColocatedEntities(component);
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));
- const infoMessage = `This action will unregister ${
- value ? value.map(e => e.metadata.name).join(', ') : ''
- } from location with target ${component.location?.target}. To undo,
- just re-register the component in Backstage.`;
+
return (
);
};
+
export default ComponentRemovalDialog;
diff --git a/plugins/catalog/src/data/component.ts b/plugins/catalog/src/data/component.ts
index 73b349391b..86749c6faa 100644
--- a/plugins/catalog/src/data/component.ts
+++ b/plugins/catalog/src/data/component.ts
@@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import { EntityMeta } from '@backstage/catalog-model';
import { ReactNode } from 'react';
-import { Location } from '@backstage/catalog-model';
export type Component = {
name: string;
kind: string;
+ metadata: EntityMeta;
description: ReactNode;
- location?: Location;
};
diff --git a/plugins/catalog/src/data/utils.tsx b/plugins/catalog/src/data/utils.tsx
index 93d28f5ca2..3e8e0458d6 100644
--- a/plugins/catalog/src/data/utils.tsx
+++ b/plugins/catalog/src/data/utils.tsx
@@ -13,23 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import React from 'react';
-import { Component } from './component';
import {
Entity,
- Location,
+ LocationSpec,
LOCATION_ANNOTATION,
+ EntityMeta,
} from '@backstage/catalog-model';
-import Edit from '@material-ui/icons/Edit';
import IconButton from '@material-ui/core/IconButton';
import { styled } from '@material-ui/core/styles';
+import Edit from '@material-ui/icons/Edit';
+import React from 'react';
+import { Component } from './component';
const DescriptionWrapper = styled('span')({
display: 'flex',
alignItems: 'center',
});
-const createEditLink = (location: Location): string => {
+const createEditLink = (location: LocationSpec): string => {
switch (location.type) {
case 'github':
return location.target.replace('/blob/', '/edit/');
@@ -38,13 +39,12 @@ const createEditLink = (location: Location): string => {
}
};
-export function entityToComponent(
- envelope: Entity,
- location?: Location,
-): Component {
+export function entityToComponent(envelope: Entity): Component {
+ const location = findLocationForEntityMeta(envelope.metadata);
return {
name: envelope.metadata?.name ?? '',
kind: envelope.kind ?? 'unknown',
+ metadata: envelope.metadata,
description: (
{envelope.metadata?.annotations?.description ?? 'placeholder'}
@@ -57,18 +57,28 @@ export function entityToComponent(
) : null}
),
- location,
};
}
-export function findLocationForEntity(
- entity: Entity,
- locations: Location[],
-): Location | undefined {
- for (const loc of locations) {
- if (loc.id === entity.metadata.annotations?.[LOCATION_ANNOTATION]) {
- return loc;
- }
+export function findLocationForEntityMeta(
+ meta: EntityMeta,
+): LocationSpec | undefined {
+ if (!meta) {
+ return undefined;
}
- return undefined;
+
+ const annotation = meta.annotations?.[LOCATION_ANNOTATION];
+ if (!annotation) {
+ return undefined;
+ }
+
+ const separatorIndex = annotation.indexOf(':');
+ if (separatorIndex === -1) {
+ return undefined;
+ }
+
+ return {
+ type: annotation.substring(0, separatorIndex),
+ target: annotation.substring(separatorIndex + 1),
+ };
}
diff --git a/plugins/register-component/src/components/RegisterComponentPage/RegisterComponentPage.test.tsx b/plugins/register-component/src/components/RegisterComponentPage/RegisterComponentPage.test.tsx
index ca463550d1..48130124b7 100644
--- a/plugins/register-component/src/components/RegisterComponentPage/RegisterComponentPage.test.tsx
+++ b/plugins/register-component/src/components/RegisterComponentPage/RegisterComponentPage.test.tsx
@@ -31,7 +31,6 @@ const catalogApi: jest.Mocked = {
getEntityByName: jest.fn(),
getLocationByEntity: jest.fn(),
getLocationById: jest.fn(),
- getEntitiesByLocationId: jest.fn(),
};
const setup = () => ({