feat: code clean up

Signed-off-by: Kamil Wolny <mrwolny@gmail.com>
This commit is contained in:
Kamil Wolny
2022-07-29 14:46:04 +01:00
parent 8d1b0bd6e8
commit 655149ec0d
7 changed files with 114 additions and 121 deletions
@@ -41,7 +41,6 @@ export const GitHubIssues = ({
itemsPerRepo = 40,
}: Props) => {
const [isLoading, setIsLoading] = React.useState(true);
const [activeFilter, setActiveFilter] = React.useState<Array<string>>([]);
const [issuesByRepository, setIssuesByRepository] =
React.useState<Record<string, RepoIssues>>();
@@ -49,62 +48,6 @@ export const GitHubIssues = ({
const { repositories } = useEntityGitHubRepositories();
const getIssues = useGetIssuesByRepoFromGitHub();
const filters = React.useMemo(
() =>
issuesByRepository
? Object.keys(issuesByRepository)
.filter(repo => issuesByRepository[repo].issues.totalCount > 0)
.map(repo => ({
label: `${repo} (${issuesByRepository[repo].issues.totalCount})`,
value: repo,
}))
: [],
[issuesByRepository],
);
const totalIssuesInGitHub = React.useMemo(
() =>
issuesByRepository
? Object.values(issuesByRepository).reduce(
(acc, { issues: { totalCount } }) => acc + totalCount,
0,
)
: 0,
[issuesByRepository],
);
const filteredRepos = React.useMemo(
() =>
issuesByRepository && activeFilter.length
? activeFilter.reduce(
(acc, val) => ({
[val]: issuesByRepository[val],
...acc,
}),
{},
)
: issuesByRepository,
[issuesByRepository, activeFilter],
);
const issues = React.useMemo(
() =>
filteredRepos
? Object.values(filteredRepos)
.map(({ issues: { edges } }) => edges)
.flat()
.sort((a, b) => {
if (a.node.updatedAt > b.node.updatedAt) {
return -1;
} else if (b.node.updatedAt > a.node.updatedAt) {
return 1;
}
return 0;
})
: [],
[filteredRepos],
);
const fetchGitHubIssues = React.useCallback(async () => {
setIsLoading(true);
const issuesByRepo = await getIssues(repositories, itemsPerRepo);
@@ -139,11 +82,8 @@ export const GitHubIssues = ({
{isLoading && <Progress />}
<IssueList
issuesByRepository={issuesByRepository}
itemsPerPage={itemsPerPage}
issues={issues}
totalIssuesInGitHub={totalIssuesInGitHub}
setActiveFilter={setActiveFilter}
filters={filters}
/>
</InfoCard>
);
@@ -16,7 +16,13 @@
import React, { FunctionComponent } from 'react';
import { DateTime } from 'luxon';
import { Box, Paper, Typography, CardActionArea } from '@material-ui/core';
import {
Box,
Paper,
Typography,
CardActionArea,
Link,
} from '@material-ui/core';
import Assignees from './Assignees';
import { CommentsCount } from './CommentsCount';
@@ -58,9 +64,12 @@ export const IssueCard: FunctionComponent<Props> = (props: Props) => {
<CardActionArea href={url} target="_blank">
<Box padding={1}>
<Box display="flex" justifyContent="space-between">
<Typography color="primary" variant="body2" component="h2">
<Link
href={`https://github.com/${repositoryName}/issues`}
target="_blank"
>
{repositoryName}
</Typography>
</Link>
<Assignees name={assigneeName} avatar={assigneeAvatar} />
</Box>
<Box>
@@ -14,9 +14,8 @@
* limitations under the License.
*/
import React from 'react';
import { Select } from '@backstage/core-components';
import { SelectedItems } from '@backstage/core-components';
import { makeStyles, Box } from '@material-ui/core';
import { Select, SelectedItems } from '@backstage/core-components';
import { makeStyles, Box, Typography } from '@material-ui/core';
export type FilterItem = {
label: string;
@@ -26,6 +25,7 @@ export type FilterItem = {
type Props = {
items: Array<FilterItem>;
totalIssuesInGitHub: number;
placeholder: string;
onChange: (active: Array<string>) => void;
};
@@ -33,9 +33,9 @@ const useStyles = makeStyles(theme => ({
filters: {
margin: theme.spacing(0, 0, 2, 0),
'& > div': {
width: '600px',
maxWidth: '800px',
'& > div': {
maxWidth: '600px',
maxWidth: '800px',
},
},
},
@@ -47,18 +47,22 @@ const checkSelectedItems: (
return onChange(active as Array<string>);
};
export const Filters = ({ items, totalIssuesInGitHub, onChange }: Props) => {
export const Filters = ({ items, onChange, placeholder }: Props) => {
const css = useStyles();
return (
<Box className={css.filters}>
<Select
placeholder={`All repositories (${totalIssuesInGitHub})`}
placeholder={placeholder}
label=""
items={items}
multiple
onChange={checkSelectedItems(onChange)}
/>
<Typography variant="caption">
*Repositories with more Issues in GitHub than available to view in
Backstage. To view them go to GitHub.
</Typography>
</Box>
);
};
@@ -19,29 +19,86 @@ import { Box } from '@material-ui/core';
import { Pagination } from '@material-ui/lab';
import { IssueCard } from '../IssueCard';
import { Issue } from '../../../hooks/useGetIssuesByRepoFromGitHub';
import { Filters, FilterItem } from './Filters';
import { RepoIssues } from '../../../hooks/useGetIssuesByRepoFromGitHub';
import { Filters } from './Filters';
export type PluginMode = 'page' | 'card';
export type Props = {
itemsPerPage?: number;
issues: Array<{
node: Issue;
}>;
filters: Array<FilterItem>;
totalIssuesInGitHub: number;
setActiveFilter: (active: Array<string>) => void;
issuesByRepository?: Record<string, RepoIssues>;
};
export const IssueList = ({
itemsPerPage = 10,
issues,
filters,
setActiveFilter,
totalIssuesInGitHub,
}: Props) => {
const getIssuesCountForFilterLabel = (
totalIssues: number,
issuesAvailable: number,
) =>
`(${totalIssues} ${totalIssues === 1 ? 'Issue' : `Issues`})${
issuesAvailable < totalIssues ? '*' : ''
}`;
export const IssueList = ({ itemsPerPage = 10, issuesByRepository }: Props) => {
const [currentPage, setCurrentPage] = React.useState(1);
const [activeFilter, setActiveFilter] = React.useState<Array<string>>([]);
const filters = React.useMemo(
() =>
issuesByRepository
? Object.keys(issuesByRepository)
.filter(repo => issuesByRepository[repo].issues.totalCount > 0)
.map(repo => ({
label: `${repo} ${getIssuesCountForFilterLabel(
issuesByRepository[repo].issues.totalCount,
issuesByRepository[repo].issues.edges.length,
)}`,
value: repo,
}))
: [],
[issuesByRepository],
);
const totalIssuesInGitHub = React.useMemo(
() =>
issuesByRepository
? Object.values(issuesByRepository).reduce(
(acc, { issues: { totalCount } }) => acc + totalCount,
0,
)
: 0,
[issuesByRepository],
);
const filteredRepos = React.useMemo(
() =>
issuesByRepository && activeFilter.length
? activeFilter.reduce(
(acc, val) => ({
[val]: issuesByRepository[val],
...acc,
}),
{},
)
: issuesByRepository,
[issuesByRepository, activeFilter],
);
const issues = React.useMemo(
() =>
filteredRepos
? Object.values(filteredRepos)
.map(({ issues: { edges } }) => edges)
.flat()
.sort((a, b) => {
if (a.node.updatedAt > b.node.updatedAt) {
return -1;
} else if (b.node.updatedAt > a.node.updatedAt) {
return 1;
}
return 0;
})
: [],
[filteredRepos],
);
const displayIssues = issues.slice(
(currentPage - 1) * itemsPerPage,
@@ -50,11 +107,17 @@ export const IssueList = ({
return (
<Box>
<Filters
items={filters}
onChange={setActiveFilter}
totalIssuesInGitHub={totalIssuesInGitHub}
/>
{issues.length > 0 && (
<Filters
placeholder={`All repositories ${getIssuesCountForFilterLabel(
totalIssuesInGitHub,
issues.length,
)}`}
items={filters}
onChange={setActiveFilter}
totalIssuesInGitHub={totalIssuesInGitHub}
/>
)}
{displayIssues.length > 0 ? (
displayIssues.map(
@@ -88,7 +151,7 @@ export const IssueList = ({
),
)
) : (
<h1>No issues 🚀</h1>
<h1>Hurray! No Issues 🚀</h1>
)}
{issues.length / itemsPerPage > 1 ? (
<Pagination
@@ -27,14 +27,14 @@ describe('useGetIssuesBeRepoFromGitHub', () => {
const Helper = () => {
const getIssues = useGetIssuesByRepoFromGitHub();
getIssues(['mrwolny/yo-yo', 'mrwolny/yoyo'], 10);
getIssues(['mrwolny/yo-yo', 'mrwolny/yoyo', 'mrwolny/yo.yo'], 10);
return <div />;
};
render(<Helper />);
expect(mockGraphQLQuery).toHaveBeenCalled();
expect(mockGraphQLQuery).toHaveBeenCalledTimes(1);
expect(mockGraphQLQuery).toHaveBeenCalledWith(
'\n' +
' \n' +
@@ -46,7 +46,6 @@ describe('useGetIssuesBeRepoFromGitHub', () => {
' ) {\n' +
' totalCount\n' +
' edges {\n' +
' cursor\n' +
' node {\n' +
' assignees(first: 10) {\n' +
' edges {\n' +
@@ -64,7 +63,6 @@ describe('useGetIssuesBeRepoFromGitHub', () => {
' repository {\n' +
' nameWithOwner\n' +
' }\n' +
' body\n' +
' title\n' +
' url\n' +
' participants {\n' +
@@ -90,6 +88,10 @@ describe('useGetIssuesBeRepoFromGitHub', () => {
' yoyox: repository(name: "yoyo", owner: "mrwolny") {\n' +
' ...issues\n' +
' }\n' +
' ,\n' +
' yoyoxx: repository(name: "yo.yo", owner: "mrwolny") {\n' +
' ...issues\n' +
' }\n' +
' \n' +
' } \n' +
' ',
@@ -36,13 +36,11 @@ type IssueAuthor = {
};
export type Issue = {
cursor: string;
assignees: EdgesWithNodes<Assignee>;
author: IssueAuthor;
repository: {
nameWithOwner: string;
};
body: string;
title: string;
url: string;
participants: {
@@ -80,7 +78,6 @@ const createQuery = (
) {
totalCount
edges {
cursor
node {
assignees(first: 10) {
edges {
@@ -98,7 +95,6 @@ const createQuery = (
repository {
nameWithOwner
}
body
title
url
participants {
@@ -1,21 +0,0 @@
/*
* Copyright 2022 The Backstage Authors
*
* 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 { Issue } from './useGetIssuesByRepoFromGitHub';
export type GitHubIssues = {
getIssues: (repo?: string) => Array<Issue>;
getIssuesTotalCountByRepo: () => Record<string, { totalCount: number }>;
};