add Maintainer column to grid

closes #950
This commit is contained in:
Collin M. Barrett 2019-09-06 20:35:28 -05:00
parent 994106430f
commit 852e532aa4
8 changed files with 88 additions and 10 deletions

View file

@ -7,12 +7,14 @@ import { useSearchColumnFilter, useTablePageSizer } from '../../hooks';
import { Language } from '../../interfaces/Language';
import { License } from '../../interfaces/License';
import { List } from '../../interfaces/List';
import { Maintainer } from '../../interfaces/Maintainer';
import { Software } from '../../interfaces/Software';
import { Tag as TagInterface } from '../../interfaces/Tag';
import { nameof } from '../../utils';
import { Description } from '../Description';
import { LanguageCloud } from '../languageCloud';
import { ListInfoButton } from '../ListInfoButton';
import { MaintainerCloud } from '../maintainerCloud';
import { SoftwareCloud, SoftwareIcon } from '../softwareCloud';
import { TagCloud } from '../tagCloud';
import { arraySorter } from './arraySorter';
@ -22,12 +24,13 @@ interface Props {
lists: List[];
languages: Language[];
licenses: License[];
maintainers: Maintainer[];
software: Software[];
tags: TagInterface[];
};
export const ListsTable = (props: RouteComponentProps & Props) => {
const { lists, languages, licenses, software, tags, ...routeComponentProps } = props;
const { lists, languages, licenses, maintainers, software, tags, ...routeComponentProps } = props;
const tablePageSize = useTablePageSizer();
const searchNameColumn = useSearchColumnFilter<List>(nameof<List>("name"));
const searchDescriptionColumn = useSearchColumnFilter<List>(nameof<List>("description"));
@ -152,6 +155,28 @@ export const ListsTable = (props: RouteComponentProps & Props) => {
tagIds
? <TagCloud tags={tags.filter((t: TagInterface) => tagIds.includes(t.id))} />
: null} />}
{tablePageSize.isNarrowWindow
? null
: <Table.Column<List>
title="Maintainers"
dataIndex={nameof<List>("maintainerIds")}
sorter={(a, b) => arraySorter(a.maintainerIds, b.maintainerIds, maintainers)}
width={191}
className={styles.nogrow}
filters={maintainers.map(t => ({
text: <>
<Tag title={t.name}>{t.name}</Tag>
({visibleLists.filter(l => l.maintainerIds && l.maintainerIds.includes(t.id)).length})
</>,
value: t.id.toString()
}))}
onFilter={(value, record) => record.maintainerIds
? record.maintainerIds.includes(+value)
: false}
render={(maintainerIds: number[]) =>
maintainerIds
? <MaintainerCloud maintainers={maintainers.filter((t: Maintainer) => maintainerIds.includes(t.id))} />
: null} />}
</Table>
);
};

View file

@ -1,7 +1,7 @@
import React from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { useLanguages, useLicenses, useLists, useSoftware, useSyntaxes, useTags } from '../../hooks';
import { useLanguages, useLicenses, useLists, useMaintainers, useSoftware, useSyntaxes, useTags } from '../../hooks';
import { ListDrawer } from './ListDrawer';
import { ListsTable } from './ListsTable';
@ -9,6 +9,7 @@ export const ListsTableHoc = (props: RouteComponentProps) => {
const lists = useLists();
const languages = useLanguages();
const licenses = useLicenses();
const maintainers = useMaintainers();
const software = useSoftware();
const syntaxes = useSyntaxes();
const tags = useTags();
@ -18,6 +19,7 @@ export const ListsTableHoc = (props: RouteComponentProps) => {
lists={lists}
languages={languages}
licenses={licenses}
maintainers={maintainers}
software={software}
tags={tags}
{...props} />

View file

@ -0,0 +1,7 @@
.grow {
/* allow for 2nd row's tags' bottom border to not be chopped in AllListsTable */
max-height: none !important;
/* leave vertical gap between rows of tags */
line-height: 28px;
}

View file

@ -0,0 +1,26 @@
import { Tag } from 'antd';
import React from 'react';
import { Maintainer } from '../../interfaces/Maintainer';
import styles from './MaintainerCloud.module.css';
interface Props {
maintainers: Maintainer[];
};
export const MaintainerCloud = (props: Props) =>
props.maintainers && props.maintainers.length
? <div className={styles.grow}>
{props.maintainers.map((m: Maintainer, i: number) =>
m.homeUrl
? <Tag key={i}>
<a href={m.homeUrl}
title={`View ${m.name}'s homepage.`}
target="_blank"
rel="noopener noreferrer">
{m.name}
</a>
</Tag>
: <Tag key={i}>{m.name}</Tag>)}
</div>
: null;

View file

@ -0,0 +1,3 @@
import { MaintainerCloud } from './MaintainerCloud';
export { MaintainerCloud };

View file

@ -1,6 +1,7 @@
import { useLanguages } from './useLanguages';
import { useLicenses } from './useLicenses';
import { useLists } from './useLists';
import { useMaintainers } from './useMaintainers';
import { useSearchColumnFilter } from './useSearchColumnFilter';
import { useSoftware } from './useSoftware';
import { useSyntaxes } from './useSyntaxes';
@ -8,12 +9,13 @@ import { useTablePageSizer } from './useTablePageSizer';
import { useTags } from './useTags';
export {
useLanguages,
useLicenses,
useLists,
useSearchColumnFilter,
useSoftware,
useSyntaxes,
useTablePageSizer,
useTags
useLanguages,
useLicenses,
useLists,
useMaintainers,
useSearchColumnFilter,
useSoftware,
useSyntaxes,
useTablePageSizer,
useTags
};

View file

@ -0,0 +1,5 @@
import { Maintainer } from '../interfaces/Maintainer';
import { useApiData } from './useApiData';
export const useMaintainers = () => (useApiData<Maintainer[]>("/api/v1/maintainers") || [])
.sort((a: Maintainer, b: Maintainer) => a.name.localeCompare(b.name));

View file

@ -0,0 +1,8 @@
export interface Maintainer {
id: number;
emailAddress: string;
filterListIds: number[];
homeUrl: string;
name: string;
twitterHandle: string;
};