Skip to content

Commit

Permalink
Merge da01366 into 9c7c3e3
Browse files Browse the repository at this point in the history
  • Loading branch information
joshri committed Jan 28, 2022
2 parents 9c7c3e3 + da01366 commit 12da0df
Show file tree
Hide file tree
Showing 9 changed files with 672 additions and 41 deletions.
9 changes: 6 additions & 3 deletions ui/components/CommitsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,23 @@ function CommitsTable({
fields={[
{
label: "SHA",
displayLabel: "SHA",
value: (row: Commit) => (
<Link newTab href={row.url}>
{row.hash}
</Link>
),
},
{
label: "Date",
label: "date",
displayLabel: "Date",
value: (row: Commit) => timestamp(row.date),
},
{ label: "Message", value: "message" },
{ label: "Author", value: "author" },
{ label: "message", displayLabel: "Message", value: "message" },
{ label: "Author", displayLabel: "Author", value: "author" },
]}
rows={commits.commits}
disablePagination
/>
</div>
);
Expand Down
9 changes: 5 additions & 4 deletions ui/components/ConditionsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@ function ConditionsTable({ className, conditions }: Props) {
return (
<DataTable
fields={[
{ label: "Type", value: "type" },
{ label: "Status", value: "status" },
{ label: "Reason", value: "reason" },
{ label: "Message", value: "message" },
{ label: "type", displayLabel: "Type", value: "type" },
{ label: "status", displayLabel: "Status", value: "status" },
{ label: "reason", displayLabel: "Reason", value: "reason" },
{ label: "message", displayLabel: "Message", value: "message" },
]}
rows={conditions}
sortFields={[""]}
className={className}
widths={["10%", "10%", "25%", "55%"]}
disablePagination
/>
);
}
Expand Down
169 changes: 150 additions & 19 deletions ui/components/DataTable.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import {
FormControl,
MenuItem,
Select,
Table,
TableBody,
TableCell,
Expand All @@ -22,6 +25,7 @@ export interface Props {
/** A list of objects with two fields: `label`, which is a string representing the column header, and `value`, which can be a string, or a function that extracts the data needed to fill the table cell. */
fields: {
label: string;
displayLabel: string;
value: string | ((k: any) => string | JSX.Element);
}[];
/** A list of data that will be iterated through to create the columns described in `fields`. */
Expand All @@ -30,6 +34,10 @@ export interface Props {
sortFields: string[];
/** an optional list of string widths for each field/column. */
widths?: string[];
/** removes bottom pagination bar. */
disablePagination?: boolean;
/** array of options for rows per page. Defaults to [25, 50, 75, 100]. */
paginationOptions?: number[];
}

const EmptyRow = styled(TableRow)<{ colSpan: number }>`
Expand Down Expand Up @@ -64,31 +72,37 @@ function UnstyledDataTable({
rows,
sortFields,
widths,
disablePagination,
paginationOptions = [25, 50, 75, 100],
}: Props) {
const [sort, setSort] = React.useState(sortFields[0]);
const [reverseSort, setReverseSort] = React.useState(false);
const [pagination, setPagination] = React.useState({
start: 0,
length: paginationOptions[0],
});
const sorted = _.sortBy(rows, sort);

if (reverseSort) {
sorted.reverse();
}

type labelProps = { label: string };
function SortableLabel({ label }: labelProps) {
type labelProps = { label: string; displayLabel: string };
function SortableLabel({ label, displayLabel }: labelProps) {
return (
<Flex align start>
<TableButton
color="inherit"
variant="text"
onClick={() => {
setReverseSort(sort === label.toLowerCase() ? !reverseSort : false);
setSort(label.toLowerCase());
setReverseSort(sort === label ? !reverseSort : false);
setSort(label);
}}
>
<h2>{label}</h2>
<h2>{displayLabel}</h2>
</TableButton>
<Spacer padding="xxs" />
{sort === label.toLowerCase() ? (
{sort === label ? (
<Icon
type={IconType.ArrowUpwardIcon}
size="base"
Expand All @@ -101,15 +115,30 @@ function UnstyledDataTable({
);
}

const r = _.map(sorted, (r, i) => (
<TableRow key={i}>
{_.map(fields, (f, i) => (
<TableCell style={widths && { width: widths[i] }} key={f.label}>
<Text>{typeof f.value === "function" ? f.value(r) : r[f.value]}</Text>
</TableCell>
))}
</TableRow>
));
const r = [];
for (
let i = pagination.start;
i < pagination.start + pagination.length;
i++
) {
if (sorted[i]) {
r.push(
<TableRow key={i}>
{_.map(fields, (f, index) => (
<TableCell style={widths && { width: widths[index] }} key={f.label}>
<Text>
{typeof f.value === "function"
? f.value(sorted[i])
: sorted[i][f.value]}
</Text>
</TableCell>
))}
</TableRow>
);
} else {
break;
}
}

return (
<div className={className}>
Expand All @@ -119,18 +148,21 @@ function UnstyledDataTable({
<TableRow>
{_.map(fields, (f, i) => (
<TableCell style={widths && { width: widths[i] }} key={f.label}>
{sortFields.includes(f.label.toLowerCase()) ? (
<SortableLabel label={f.label} />
{sortFields.includes(f.label) ? (
<SortableLabel
label={f.label}
displayLabel={f.displayLabel}
/>
) : (
<h2 className="thead">{f.label}</h2>
<h2 className="thead">{f.displayLabel}</h2>
)}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{r.length > 0 ? (
r
r.map((row) => row)
) : (
<EmptyRow colSpan={fields.length}>
<TableCell colSpan={fields.length}>
Expand All @@ -141,6 +173,98 @@ function UnstyledDataTable({
</TableBody>
</Table>
</TableContainer>
{/* pagination row */}
<Spacer padding="xs" />
{!disablePagination && (
<Flex wide align end>
<FormControl>
<Flex align>
<label htmlFor="pagination">Rows Per Page: </label>
<Spacer padding="xxs" />
<Select
id="pagination"
variant="outlined"
defaultValue={paginationOptions[0]}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
const newValue = parseInt(e.target.value);
setPagination({ start: 0, length: newValue });
}}
>
{paginationOptions.map((option, index) => {
return (
<MenuItem key={index} value={option}>
{option}
</MenuItem>
);
})}
</Select>
</Flex>
</FormControl>
<Spacer padding="base" />
<Text>
{pagination.start === 0 ? 1 : pagination.start} -{" "}
{pagination.start + r.length} out of {rows.length}
</Text>
<Spacer padding="base" />
<Flex>
<Button
color="inherit"
variant="text"
aria-label="skip to first page"
disabled={pagination.start === 0}
onClick={() => setPagination({ ...pagination, start: 0 })}
>
<Icon type={IconType.SkipPreviousIcon} size="medium" />
</Button>
<Button
color="inherit"
variant="text"
aria-label="back one page"
disabled={pagination.start === 0}
onClick={() =>
setPagination({
...pagination,
start: pagination.start - pagination.length,
})
}
>
<Icon type={IconType.NavigateBeforeIcon} size="medium" />
</Button>
<Button
color="inherit"
variant="text"
aria-label="forward one page"
disabled={pagination.start + pagination.length >= rows.length}
onClick={() =>
setPagination({
...pagination,
start: pagination.start + pagination.length,
})
}
>
<Icon type={IconType.NavigateNextIcon} size="medium" />
</Button>
<Button
color="inherit"
variant="text"
aria-label="skip to last page"
disabled={pagination.start + pagination.length >= rows.length}
onClick={() => {
let newStart;
if (rows.length % pagination.length !== 0)
newStart = rows.length - (rows.length % pagination.length);
else newStart = rows.length - pagination.length;
setPagination({
...pagination,
start: newStart,
});
}}
>
<Icon type={IconType.SkipNextIcon} size="medium" />
</Button>
</Flex>
</Flex>
)}
</div>
);
}
Expand All @@ -153,6 +277,13 @@ export const DataTable = styled(UnstyledDataTable)`
color: ${(props) => props.theme.colors.neutral30};
font-weight: 800;
}
.MuiTableRow-root {
transition: background 0.5s ease-in-out;
}
.MuiTableRow-root:not(.MuiTableRow-head):hover {
background: ${(props) => props.theme.colors.neutral10};
transition: background 0.5s ease-in-out;
}
`;

export default DataTable;
23 changes: 19 additions & 4 deletions ui/components/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ import DeleteIcon from "@material-ui/icons/Delete";
import ErrorIcon from "@material-ui/icons/Error";
import HourglassFullIcon from "@material-ui/icons/HourglassFull";
import LaunchIcon from "@material-ui/icons/Launch";
import NavigateBeforeIcon from "@material-ui/icons/NavigateBefore";
import NavigateNextIcon from "@material-ui/icons/NavigateNext";
import SaveAltIcon from "@material-ui/icons/SaveAlt";
import SkipNextIcon from "@material-ui/icons/SkipNext";
import SkipPreviousIcon from "@material-ui/icons/SkipPrevious";
import * as React from "react";
import styled from "styled-components";
import { colors, spacing } from "../typedefs/styled";
Expand All @@ -21,11 +24,14 @@ export enum IconType {
AddIcon,
ArrowUpwardIcon,
DeleteIcon,
NavigateNextIcon,
SaveAltIcon,
ErrorIcon,
CheckCircleIcon,
HourglassFullIcon,
NavigateNextIcon,
NavigateBeforeIcon,
SkipNextIcon,
SkipPreviousIcon,
}

type Props = {
Expand Down Expand Up @@ -56,9 +62,6 @@ function getIcon(i: IconType) {
case IconType.DeleteIcon:
return DeleteIcon;

case IconType.NavigateNextIcon:
return NavigateNextIcon;

case IconType.SaveAltIcon:
return SaveAltIcon;

Expand All @@ -71,6 +74,18 @@ function getIcon(i: IconType) {
case IconType.ErrorIcon:
return ErrorIcon;

case IconType.NavigateNextIcon:
return NavigateNextIcon;

case IconType.NavigateBeforeIcon:
return NavigateBeforeIcon;

case IconType.SkipNextIcon:
return SkipNextIcon;

case IconType.SkipPreviousIcon:
return SkipPreviousIcon;

default:
break;
}
Expand Down
Loading

0 comments on commit 12da0df

Please sign in to comment.