feat(catalog): extract useEntitiesStore

This commit is contained in:
Nikita Nek Dudnik
2020-06-15 12:50:35 +02:00
parent 4cc2e67e43
commit bb09898b51
6 changed files with 136 additions and 36 deletions
@@ -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>(theme => ({
},
}));
export const CatalogFilter: React.FC<CatalogFilterProps> = ({
export const CatalogFilter: FC<CatalogFilterProps> = ({
groups,
selectedId,
onSelectedChange,
@@ -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 <span>{starredEntities.size}</span>;
};
@@ -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 <span>{starredEntities.size}</span>;
};
@@ -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<CatalogFilterItem>(
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();
+11 -3
View File
@@ -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<string, EntityFilter> = {
[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];
@@ -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<CatalogFilterItem>(
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<Entity[]>([]);
const [entitiesByFilter] = useState<Record<string, Entity[]>>(
// 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,
};
};