feature: extract getLocationById method, wrap location fetching in useAsync

This commit is contained in:
Nikita Nek Dudnik
2020-06-05 11:36:52 +02:00
parent b717971ec1
commit e1477fa635
5 changed files with 59 additions and 42 deletions
+18 -8
View File
@@ -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;
}
}
+2
View File
@@ -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;
+11 -3
View File
@@ -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);
};