diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 106f6c713a..c6457aa8a8 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -30,12 +30,12 @@ "@material-ui/core": "^4.9.1", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", - "node-cache": "^5.1.1", "react": "^16.13.1", "react-dom": "^16.13.1", "react-router": "^5.2.0", "react-router-dom": "^5.2.0", - "react-use": "^14.2.0" + "react-use": "^14.2.0", + "swr": "^0.2.2" }, "devDependencies": { "@backstage/cli": "^0.1.1-alpha.7", diff --git a/plugins/catalog/src/api/CatalogClient.ts b/plugins/catalog/src/api/CatalogClient.ts index d8add18f68..3804315ace 100644 --- a/plugins/catalog/src/api/CatalogClient.ts +++ b/plugins/catalog/src/api/CatalogClient.ts @@ -19,14 +19,9 @@ import { Location, LOCATION_ANNOTATION, } from '@backstage/catalog-model'; -import Cache from 'node-cache'; import { CatalogApi, EntityCompoundName } from './types'; export class CatalogClient implements CatalogApi { - // TODO(blam): This cache is just temporary until we have GraphQL. - // And client side caching using things like React Apollo or Relay. - // There's a lot of loading states that cause flickering around the app which aren't needed. - private cache: Cache; private apiOrigin: string; private basePath: string; @@ -39,7 +34,6 @@ export class CatalogClient implements CatalogApi { }) { this.apiOrigin = apiOrigin; this.basePath = basePath; - this.cache = new Cache({ stdTTL: 10 }); } private async getRequired(path: string): Promise { @@ -79,11 +73,6 @@ export class CatalogClient implements CatalogApi { async getEntities( filter?: Record, ): Promise { - const cachedValue = this.cache.get( - `get:${JSON.stringify(filter)}`, - ); - if (cachedValue) return cachedValue; - let path = `/entities`; if (filter) { const params = new URLSearchParams(); diff --git a/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx index 570648f26b..4d3321efc9 100644 --- a/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx @@ -35,7 +35,6 @@ import Star from '@material-ui/icons/Star'; import StarOutline from '@material-ui/icons/StarBorder'; import React, { FC, useCallback, useState } from 'react'; import { Link as RouterLink } from 'react-router-dom'; -import { useAsync } from 'react-use'; import { catalogApiRef } from '../..'; import { defaultFilter, entityFilters, filterGroups } from '../../data/filters'; import { findLocationForEntityMeta } from '../../data/utils'; @@ -45,6 +44,7 @@ import { CatalogFilterItem, } from '../CatalogFilter/CatalogFilter'; import { CatalogTable } from '../CatalogTable/CatalogTable'; +import useStaleWhileRevalidate from 'swr'; const useStyles = makeStyles(theme => ({ contentWrapper: { @@ -61,20 +61,21 @@ const useStyles = makeStyles(theme => ({ export const CatalogPage: FC<{}> = () => { const catalogApi = useApi(catalogApiRef); - const { - starredEntities, - toggleStarredEntity, - isStarredEntity, - } = useStarredEntities(); + const { toggleStarredEntity, isStarredEntity } = useStarredEntities(); + const [selectedFilter, setSelectedFilter] = useState( defaultFilter, ); - const { value, error, loading } = useAsync(async () => { - const filter = entityFilters[selectedFilter.id]; - const all = await catalogApi.getEntities(); - return all.filter(e => filter(e, { isStarred: isStarredEntity(e) })); - }, [selectedFilter.id, starredEntities.size]); + const { data: entities, error } = useStaleWhileRevalidate( + ['catalog/all', entityFilters[selectedFilter.id]], + async () => catalogApi.getEntities(), + ); + + const data = + entities?.filter(e => + entityFilters[selectedFilter.id](e, { isStarred: isStarredEntity(e) }), + ) ?? []; const onFilterSelected = useCallback( selected => setSelectedFilter(selected), @@ -195,8 +196,8 @@ export const CatalogPage: FC<{}> = () => { diff --git a/yarn.lock b/yarn.lock index 73d9ccfad1..364f228c51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6221,11 +6221,6 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" -clone@2.x: - version "2.1.2" - resolved "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= - clone@^1.0.2: version "1.0.4" resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" @@ -13264,13 +13259,6 @@ nocache@2.1.0: resolved "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz#120c9ffec43b5729b1d5de88cd71aa75a0ba491f" integrity sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q== -node-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/node-cache/-/node-cache-5.1.1.tgz#5fcc887176b23bdcd19cd1461b9544d2d501e786" - integrity sha512-bJ9nH25Z51HG2QIu66K4dMVyMs6o8bNQpviDnXzG+O/gfNxPU9IpIig0j4pzlO707GcGZ6QA4rWhlRxjJsjnZw== - dependencies: - clone "2.x" - node-cleanup@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz#7ac19abd297e09a7f72a71545d951b517e4dde2c" @@ -17700,6 +17688,13 @@ svgo@^1.0.0, svgo@^1.2.2: unquote "~1.1.1" util.promisify "~1.0.0" +swr@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/swr/-/swr-0.2.2.tgz#6e1b3e5c0e545c4fdb36ae3aa38cd94d0f9a88b7" + integrity sha512-D/z+PTUchZhoUA0tNC8TNJivf7Hc61WPxbUdXPi+VxRloddWYNP1ZicaEgyAph42ZnKl1L7twcZr4q6d0UMXcg== + dependencies: + fast-deep-equal "2.0.1" + symbol-observable@^1.1.0, symbol-observable@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"