diff --git a/plugins/catalog/src/components/CatalogFilter/CatalogFilter.tsx b/plugins/catalog/src/components/CatalogFilter/CatalogFilter.tsx index 5335b33ffa..0abb5f817a 100644 --- a/plugins/catalog/src/components/CatalogFilter/CatalogFilter.tsx +++ b/plugins/catalog/src/components/CatalogFilter/CatalogFilter.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import React from 'react'; +import React, { FC } from 'react'; import { Card, List, @@ -27,11 +27,12 @@ import { } from '@material-ui/core'; import type { IconComponent } from '@backstage/core'; import { EntityFilterType } from '../../data/filters'; + export type CatalogFilterItem = { id: EntityFilterType; label: string; icon?: IconComponent; - count?: number | React.FC; + count?: number | FC; }; export type CatalogFilterGroup = { @@ -71,7 +72,7 @@ const useStyles = makeStyles(theme => ({ }, })); -export const CatalogFilter: React.FC = ({ +export const CatalogFilter: FC = ({ groups, selectedId, onSelectedChange, diff --git a/plugins/catalog/src/components/CatalogFilter/OwnedCount.tsx b/plugins/catalog/src/components/CatalogFilter/OwnedCount.tsx new file mode 100644 index 0000000000..a48019c48a --- /dev/null +++ b/plugins/catalog/src/components/CatalogFilter/OwnedCount.tsx @@ -0,0 +1,23 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { FC } from 'react'; +import { useStarredEntities } from '../../hooks/useStarredEntites'; + +export const StarredCount: FC<{}> = () => { + const { starredEntities } = useStarredEntities(); + return {starredEntities.size}; +}; diff --git a/plugins/catalog/src/components/CatalogFilter/StarredCount.tsx b/plugins/catalog/src/components/CatalogFilter/StarredCount.tsx index 5e79682783..a48019c48a 100644 --- a/plugins/catalog/src/components/CatalogFilter/StarredCount.tsx +++ b/plugins/catalog/src/components/CatalogFilter/StarredCount.tsx @@ -14,10 +14,10 @@ * limitations under the License. */ -import React from 'react'; +import React, { FC } from 'react'; import { useStarredEntities } from '../../hooks/useStarredEntites'; -export const StarredCount: React.FC<{}> = () => { +export const StarredCount: FC<{}> = () => { const { starredEntities } = useStarredEntities(); return {starredEntities.size}; }; diff --git a/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx index 3ba63188c1..87e25f8f82 100644 --- a/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx @@ -21,7 +21,6 @@ import { DismissableBanner, HeaderTabs, SupportButton, - useApi, } from '@backstage/core'; import CatalogLayout from './CatalogLayout'; import { rootRoute as scaffolderRootRoute } from '@backstage/plugin-scaffolder'; @@ -30,18 +29,13 @@ import Edit from '@material-ui/icons/Edit'; import GitHub from '@material-ui/icons/GitHub'; import Star from '@material-ui/icons/Star'; import StarOutline from '@material-ui/icons/StarBorder'; -import React, { FC, useCallback, useState } from 'react'; +import React, { FC, useCallback } from 'react'; import { Link as RouterLink } from 'react-router-dom'; -import { catalogApiRef } from '../..'; -import { defaultFilter, entityFilters, filterGroups } from '../../data/filters'; -import { findLocationForEntityMeta } from '../../data/utils'; -import { useStarredEntities } from '../../hooks/useStarredEntites'; -import { - CatalogFilter, - CatalogFilterItem, -} from '../CatalogFilter/CatalogFilter'; +import { CatalogFilter } from '../CatalogFilter/CatalogFilter'; import { CatalogTable } from '../CatalogTable/CatalogTable'; -import useStaleWhileRevalidate from 'swr'; +import { useEntitiesStore } from '../../hooks/useEntitiesStore'; +import { findLocationForEntityMeta } from '../../data/utils'; +import { filterGroups } from '../../data/filters'; const useStyles = makeStyles(theme => ({ contentWrapper: { @@ -57,26 +51,18 @@ const useStyles = makeStyles(theme => ({ })); export const CatalogPage: FC<{}> = () => { - const catalogApi = useApi(catalogApiRef); - const { toggleStarredEntity, isStarredEntity } = useStarredEntities(); - - const [selectedFilter, setSelectedFilter] = useState( - defaultFilter, - ); - - 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 { + filteredEntities: data, + selectedFilter, + setSelectedFilter, + error, + toggleStarredEntity, + isStarredEntity, + } = useEntitiesStore(); const onFilterSelected = useCallback( selected => setSelectedFilter(selected), - [], + [setSelectedFilter], ); const styles = useStyles(); diff --git a/plugins/catalog/src/data/filters.ts b/plugins/catalog/src/data/filters.ts index 71efa923c6..c20f6b6b14 100644 --- a/plugins/catalog/src/data/filters.ts +++ b/plugins/catalog/src/data/filters.ts @@ -63,14 +63,22 @@ export const filterGroups: CatalogFilterGroup[] = [ type EntityFilter = (entity: Entity, options: EntityFilterOptions) => boolean; -type EntityFilterOptions = { +type EntityFilterOptions = Partial<{ isStarred: boolean; + userId: string; +}>; + +type Owned = { + owner: string; }; export const entityFilters: Record = { - [EntityFilterType.OWNED]: () => false, + [EntityFilterType.OWNED]: (e, { userId }) => { + const owner = (e.spec! as Owned).owner; + return owner === userId; + }, [EntityFilterType.ALL]: () => true, - [EntityFilterType.STARRED]: (_, { isStarred }) => isStarred, + [EntityFilterType.STARRED]: (_, { isStarred }) => isStarred ?? false, }; export const defaultFilter: CatalogFilterItem = filterGroups[0].items[0]; diff --git a/plugins/catalog/src/hooks/useEntitiesStore.ts b/plugins/catalog/src/hooks/useEntitiesStore.ts new file mode 100644 index 0000000000..21ba283dfe --- /dev/null +++ b/plugins/catalog/src/hooks/useEntitiesStore.ts @@ -0,0 +1,82 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { useState, useEffect } from 'react'; +import { CatalogFilterItem } from '../components/CatalogFilter/CatalogFilter'; +import { + defaultFilter, + EntityFilterType, + entityFilters, +} from '../data/filters'; +import { useApi } from '@backstage/core'; +import { catalogApiRef } from '..'; +import { useStarredEntities } from './useStarredEntites'; +import { Entity } from '@backstage/catalog-model'; +import useStaleWhileRevalidate from 'swr'; + +export const useEntitiesStore = () => { + const [selectedFilter, setSelectedFilter] = useState( + defaultFilter, + ); + const catalogApi = useApi(catalogApiRef); + const { toggleStarredEntity, isStarredEntity } = useStarredEntities(); + const { data: entities, error } = useStaleWhileRevalidate( + ['catalog/all', entityFilters[selectedFilter.id]], + async () => catalogApi.getEntities(), + ); + const useUser = () => { + const [user] = useState('tools@example.com'); + return user; + }; + const userId = useUser(); + + const [filteredEntities, setFilteredEntities] = useState([]); + const [entitiesByFilter] = useState>( + // Create an empty result for every filter by default + Object.keys(EntityFilterType).reduce( + (res, key) => ({ ...res, [key]: [] }), + {}, + ), + ); + useEffect(() => { + // const dataByFilter = Object.keys(EntityFilterType).reduce( + + // ,{}); + + const data = + entities?.filter((e: Entity) => + entityFilters[selectedFilter.id](e, { + isStarred: isStarredEntity(e), + userId, + }), + ) ?? []; + setFilteredEntities(data); + }, [ + entities, + selectedFilter.id, + isStarredEntity, + userId, + setFilteredEntities, + ]); + return { + filteredEntities, + selectedFilter, + setSelectedFilter, + error, + toggleStarredEntity, + isStarredEntity, + entitiesByFilter, + }; +};