Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ui v2: restyle metadata table #729

Merged
merged 8 commits into from
Dec 4, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/packages/core/src/Table/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ExpandableRow, ExpandableTable, StatusRow } from "./expandable-table";
import MetadataTable from "./metadata-table";
import { MetadataTable } from "./metadata-table";
import { Row, Table } from "./table";
import TreeTable from "./tree-table";

Expand Down
140 changes: 106 additions & 34 deletions frontend/packages/core/src/Table/metadata-table.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import React from "react";
import * as React from "react";
import { useForm } from "react-hook-form";
import styled from "@emotion/styled";
import { DevTool } from "@hookform/devtools";
import { yupResolver } from "@hookform/resolvers/yup";
import { Table, TableBody, TableCell, TableContainer, TableRow } from "@material-ui/core";
import type { Size } from "@material-ui/core/TableCell";
import type { Size } from "@material-ui/core";
import {
Table as MuiTable,
TableBody,
TableCell as MuiTableCell,
TableContainer as MuiTableContainer,
TableRow,
} from "@material-ui/core";
import _ from "lodash";
import styled from "styled-components";
import type { Schema } from "yup";
import { object } from "yup";

import { useWizardContext } from "../Contexts";
import TextField from "../Input/text-field";
import { TextField } from "../Input/text-field";

interface RowData {
input?: {
Expand All @@ -26,66 +32,126 @@ interface IdentifiableRowData extends RowData {
id: string;
}

const TableContainer = styled(MuiTableContainer)({
borderWidth: "0",
border: "0",
padding: "16px 32px",
});

const Table = styled(MuiTable)({
border: "1px solid rgba(13, 16, 48, 0.12)",
borderRadius: "4px",
borderCollapse: "unset",
});

const BORDERS = {
first: {
borderBottom: "",
key: {
borderTopLeftRadius: "3px",
},
value: {
borderTopRightRadius: "3px",
},
},
middle: {
borderBottom: "",
key: {},
value: {},
},
last: {
borderBottom: "0",
key: {
borderBottomLeftRadius: "3px",
},
value: {
borderBottomRightRadius: "3px",
},
},
};

const TableCell = styled(MuiTableCell)(
{
color: "#0D1030",
fontSize: "14px",
fontWeight: "normal",
},
props => ({
borderBottom: BORDERS[props["data-position"]].borderBottom,
...BORDERS[props["data-position"]].value,
})
);

const KeyCellContainer = styled(TableCell)(
{
width: "45%",
background: "rgba(13, 16, 48, 0.03)",
fontWeight: 500,
},
props => ({
borderBottom: BORDERS[props["data-position"]].borderBottom,
...BORDERS[props["data-position"]].key,
})
);

type RowPosition = "first" | "middle" | "last";

interface KeyCellProps {
data: IdentifiableRowData;
size: Size;
isLast?: boolean;
dschaller marked this conversation as resolved.
Show resolved Hide resolved
position: RowPosition;
}

const StyledKeyCell = styled(TableCell)`
width: 50%;
`;

const KeyCell: React.FC<KeyCellProps> = ({ data, size }) => {
const KeyCell: React.FC<KeyCellProps> = ({ data, size, position }) => {
let { name } = data;
if (data.value instanceof Array && data.value.length > 1) {
name = `${data.name}s`;
}
return (
<StyledKeyCell size={size}>
<strong>{name}</strong>
</StyledKeyCell>
<KeyCellContainer size={size} data-position={position}>
{name}
</KeyCellContainer>
);
};

interface ViewOnlyRowProps {
data: IdentifiableRowData;
size: Size;
}
interface ImmutableRowProps extends KeyCellProps {}

const ViewOnlyRow: React.FC<ViewOnlyRowProps> = ({ data, size }) => {
const ImmutableRow: React.FC<ImmutableRowProps> = ({ data, size, position }) => {
let { value } = data;
if (data.value instanceof Array && data.value.length > 1) {
value = data.value.join(", ");
}
return (
<TableRow key={data.id}>
<KeyCell data={data} size={size} />
<TableCell size={size}>{value}</TableCell>
<KeyCell data={data} size={size} position={position} />
<TableCell size={size} data-position={position}>
{value}
</TableCell>
</TableRow>
);
};

interface EditableRowProps {
data: IdentifiableRowData;
interface MutableRowProps extends ImmutableRowProps {
onUpdate: (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => void;
onReturn: () => void;
validation: any;
size: Size;
}

const EditableRow: React.FC<EditableRowProps> = ({
const MutableRow: React.FC<MutableRowProps> = ({
data,
onUpdate,
onReturn,
validation,
size,
position,
}) => {
const error = validation.errors?.[data.name];

return (
<TableRow key={data.id}>
<KeyCell data={data} size={size} />
<TableCell size={size}>
<KeyCell data={data} size={size} position={position} />
<TableCell size={size} data-position={position}>
<TextField
id={data.id}
name={data.name}
Expand All @@ -103,18 +169,17 @@ const EditableRow: React.FC<EditableRowProps> = ({
);
};

interface MetadataTableProps {
export interface MetadataTableProps {
data: RowData[];
onUpdate?: (id: string, value: unknown) => void;
variant?: Size;
dschaller marked this conversation as resolved.
Show resolved Hide resolved
}

const MetadataTable: React.FC<MetadataTableProps> = ({
export const MetadataTable: React.FC<MetadataTableProps> = ({
data,
onUpdate,
children,
variant,
...props
}) => {
const displayVariant = variant || "medium";
const { onSubmit, setOnSubmit } = useWizardContext();
Expand Down Expand Up @@ -145,22 +210,29 @@ const MetadataTable: React.FC<MetadataTableProps> = ({
}, []);

return (
<TableContainer {...props}>
<TableContainer>
{process.env.REACT_APP_DEBUG_FORMS && onUpdate !== undefined && <DevTool control={control} />}
<Table {...props}>
<Table>
<TableBody>
{rows.map((row: IdentifiableRowData) => {
{rows.map((row: IdentifiableRowData, idx: number) => {
let position = "middle" as RowPosition;
if (idx === 0) {
position = "first";
} else if (idx === rows.length - 1) {
position = "last";
}
dschaller marked this conversation as resolved.
Show resolved Hide resolved
return row.input !== undefined && onUpdate ? (
<EditableRow
<MutableRow
data={row}
onUpdate={e => onUpdate(e.target.id, e.target.value)}
onReturn={onSubmit}
key={row.id}
validation={validation}
size={displayVariant}
position={position}
/>
) : (
<ViewOnlyRow data={row} key={row.id} size={displayVariant} />
<ImmutableRow data={row} key={row.id} size={displayVariant} position={position} />
);
})}
{children}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import * as React from "react";
import type { Meta } from "@storybook/react";

import { WizardContext } from "../../Contexts";
import type { MetadataTableProps } from "../metadata-table";
import { MetadataTable } from "../metadata-table";

export default {
title: "Core/Table/Metadata Table",
decorators: [
story => (
<WizardContext.Provider
value={() => {
return {
onSubmit: () => {},
setOnSubmit: () => {},
setIsLoading: () => {},
displayWarnings: () => {},
onBack: () => {},
};
}}
>
{story()}
</WizardContext.Provider>
),
],
component: MetadataTable,
} as Meta;

const Template = (props: MetadataTableProps) => (
danielhochman marked this conversation as resolved.
Show resolved Hide resolved
<div style={{ display: "flex", maxWidth: "800px" }}>
<MetadataTable {...props} />
</div>
);

export const Primary = Template.bind({});
Primary.args = {
data: [
{ name: "Instance ID", value: "i-01cb1d09a5a1801e9" },
{ name: "Region", value: "us-east-1" },
{ name: "State", value: "RUNNING" },
{ name: "Instance Type", value: "c5.large" },
{ name: "Public IP Address", value: "54.234.102.49" },
{ name: "Private IP Address", value: "10.46.191.123" },
{ name: "Availability Zone", value: "us-east-1d" },
],
};
2 changes: 1 addition & 1 deletion frontend/packages/core/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { BaseWorkflowProps, WorkflowConfiguration } from "./AppProvider/workflow
import CheckboxPanel from "./Input/checkbox";
import { RadioGroup } from "./Input/radio-group";
import Select from "./Input/select";
import TextField from "./Input/text-field";
import { TextField } from "./Input/text-field";
import ClutchApp from "./AppProvider";
import { Button, ButtonGroup, ButtonProps, ClipboardButton } from "./button";
import Confirmation from "./confirmation";
Expand Down