feature: extract getLocationById method, wrap location fetching in useAsync
This commit is contained in:
@@ -31,6 +31,22 @@ export class CatalogClient implements CatalogApi {
|
||||
this.apiOrigin = apiOrigin;
|
||||
this.basePath = basePath;
|
||||
}
|
||||
async getLocationById(id: String): Promise<Location | undefined> {
|
||||
const response = await fetch(
|
||||
`${this.apiOrigin}${this.basePath}/locations/${id}`,
|
||||
);
|
||||
if (response.ok) {
|
||||
const location = await response.json();
|
||||
if (location) return location.data;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
async getEntitiesByLocationId(id: string): Promise<Entity[]> {
|
||||
const response = await fetch(
|
||||
`${this.apiOrigin}${this.basePath}/entities?backstage.io/managed-by-location=${id}`,
|
||||
);
|
||||
return await response.json();
|
||||
}
|
||||
async getEntities(): Promise<DescriptorEnvelope[]> {
|
||||
const response = await fetch(`${this.apiOrigin}${this.basePath}/entities`);
|
||||
return await response.json();
|
||||
@@ -50,14 +66,8 @@ export class CatalogClient implements CatalogApi {
|
||||
const locationId = findLocationIdInEntity(entity);
|
||||
if (!locationId) return undefined;
|
||||
|
||||
const response = await fetch(
|
||||
`${this.apiOrigin}${this.basePath}/locations/${locationId}`,
|
||||
);
|
||||
if (response.ok) {
|
||||
const location = await response.json();
|
||||
if (location) return location.data;
|
||||
}
|
||||
const location = this.getLocationById(locationId);
|
||||
|
||||
return undefined;
|
||||
return location;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ export const catalogApiRef = createApiRef<CatalogApi>({
|
||||
});
|
||||
|
||||
export interface CatalogApi {
|
||||
getLocationById(id: String): Promise<Location | undefined>;
|
||||
getEntities(): Promise<Entity[]>;
|
||||
getEntityByName(name: string): Promise<Entity>;
|
||||
getEntitiesByLocationId(id: string): Promise<Entity[]>;
|
||||
getLocationByEntity(entity: Entity): Promise<Location | undefined>;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { FC, useCallback, useState, useEffect } from 'react';
|
||||
import React, { FC, useCallback, useState } from 'react';
|
||||
import {
|
||||
Content,
|
||||
ContentHeader,
|
||||
@@ -47,13 +47,12 @@ const useStyles = makeStyles(theme => ({
|
||||
}));
|
||||
|
||||
import { catalogApiRef } from '../..';
|
||||
import { envelopeToComponent } from '../../data/utils';
|
||||
import { envelopeToComponent, findLocationForEntity } from '../../data/utils';
|
||||
import { Component } from '../../data/component';
|
||||
|
||||
const CatalogPage: FC<{}> = () => {
|
||||
const catalogApi = useApi(catalogApiRef);
|
||||
const { value, error, loading } = useAsync(() => catalogApi.getEntities());
|
||||
const [locations, setLocations] = useState<Location[]>([]);
|
||||
const [selectedFilter, setSelectedFilter] = useState<CatalogFilterItem>(
|
||||
defaultFilter,
|
||||
);
|
||||
@@ -65,7 +64,7 @@ const CatalogPage: FC<{}> = () => {
|
||||
);
|
||||
const styles = useStyles();
|
||||
|
||||
useEffect(() => {
|
||||
const { value: locations = [] } = useAsync(async () => {
|
||||
const getLocationDataForEntities = async (entities: Entity[]) => {
|
||||
return Promise.all(
|
||||
entities.map(entity => catalogApi.getLocationByEntity(entity)),
|
||||
@@ -76,12 +75,14 @@ const CatalogPage: FC<{}> = () => {
|
||||
getLocationDataForEntities(value)
|
||||
.then(
|
||||
(location): Location[] =>
|
||||
location.filter(l => !!l) as Array<Location>,
|
||||
location.filter(loc => !!loc) as Array<Location>,
|
||||
)
|
||||
.then(location => {
|
||||
if (isMounted()) setLocations(location);
|
||||
if (isMounted()) return [location];
|
||||
return [];
|
||||
});
|
||||
}
|
||||
return [];
|
||||
}, [value, catalogApi, isMounted]);
|
||||
|
||||
const actions = [
|
||||
@@ -97,15 +98,6 @@ const CatalogPage: FC<{}> = () => {
|
||||
}),
|
||||
];
|
||||
|
||||
const findLocationForEntity = (
|
||||
entity: Entity,
|
||||
l: Location[],
|
||||
): Location | undefined => {
|
||||
const entityLocationId =
|
||||
entity.metadata.annotations?.['backstage.io/managed-by-location'];
|
||||
return l.find(location => location.id === entityLocationId);
|
||||
};
|
||||
|
||||
return (
|
||||
<Page theme={pageTheme.home}>
|
||||
<Header title="Service Catalog" subtitle="Keep track of your software">
|
||||
@@ -142,22 +134,24 @@ const CatalogPage: FC<{}> = () => {
|
||||
onSelectedChange={onFilterSelected}
|
||||
/>
|
||||
</div>
|
||||
<CatalogTable
|
||||
titlePreamble={selectedFilter.label}
|
||||
components={
|
||||
(value &&
|
||||
value.map(val =>
|
||||
envelopeToComponent(
|
||||
val,
|
||||
findLocationForEntity(val, locations),
|
||||
),
|
||||
)) ||
|
||||
[]
|
||||
}
|
||||
loading={loading}
|
||||
error={error}
|
||||
actions={actions}
|
||||
/>
|
||||
{locations && (
|
||||
<CatalogTable
|
||||
titlePreamble={selectedFilter.label}
|
||||
components={
|
||||
(value &&
|
||||
value.map(val =>
|
||||
envelopeToComponent(
|
||||
val,
|
||||
findLocationForEntity(val, locations) ?? undefined,
|
||||
),
|
||||
)) ||
|
||||
[]
|
||||
}
|
||||
loading={loading}
|
||||
error={error}
|
||||
actions={actions}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Content>
|
||||
</Page>
|
||||
|
||||
@@ -25,6 +25,9 @@ import {
|
||||
useTheme,
|
||||
} from '@material-ui/core';
|
||||
import { Component } from '../../data/component';
|
||||
import { useAsync } from 'react-use';
|
||||
import { useApi, Progress } from '@backstage/core';
|
||||
import { catalogApiRef } from '../../api/types';
|
||||
|
||||
type ComponentRemovalDialogProps = {
|
||||
onConfirm: () => any;
|
||||
|
||||
@@ -16,14 +16,22 @@
|
||||
import { Component } from './component';
|
||||
import { Entity, Location } from '@backstage/catalog-model';
|
||||
|
||||
export function envelopeToComponent(
|
||||
export const envelopeToComponent = (
|
||||
envelope: Entity,
|
||||
location?: Location,
|
||||
): Component {
|
||||
): Component => {
|
||||
return {
|
||||
name: envelope.metadata?.name ?? '',
|
||||
kind: envelope.kind ?? 'unknown',
|
||||
description: envelope.metadata?.annotations?.description ?? 'placeholder',
|
||||
location,
|
||||
};
|
||||
}
|
||||
};
|
||||
export const findLocationForEntity = (
|
||||
entity: Entity,
|
||||
l: Location[],
|
||||
): Location | undefined => {
|
||||
const entityLocationId =
|
||||
entity.metadata.annotations?.['backstage.io/managed-by-location'];
|
||||
return l.find(location => location.id === entityLocationId);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user