2018-03-01 15:47:30 +02:00
|
|
|
import React, { Fragment } from 'react';
|
2018-01-30 18:04:03 +02:00
|
|
|
import { Margin, Padding } from 'styled-components-spacing';
|
2017-12-06 20:16:11 +02:00
|
|
|
import PropTypes from 'prop-types';
|
2018-03-28 15:51:34 +03:00
|
|
|
import styled, { withTheme } from 'styled-components';
|
2018-01-30 18:04:03 +02:00
|
|
|
import { Row, Col } from 'joyent-react-styled-flexboxgrid';
|
2017-09-27 17:24:40 +03:00
|
|
|
import { Field } from 'redux-form';
|
2017-11-09 13:27:32 +02:00
|
|
|
import remcalc from 'remcalc';
|
|
|
|
import titleCase from 'title-case';
|
2017-12-06 20:16:11 +02:00
|
|
|
import Flex, { FlexItem } from 'styled-flex-component';
|
2018-04-12 12:53:00 +03:00
|
|
|
import is from 'styled-is';
|
2018-01-19 19:37:31 +02:00
|
|
|
|
2018-02-05 17:12:47 +02:00
|
|
|
import Message, {
|
|
|
|
Title as MessageTitle,
|
|
|
|
Description as MessageDescription
|
|
|
|
} from '../message';
|
2017-09-20 12:30:53 +03:00
|
|
|
|
2018-04-12 12:53:00 +03:00
|
|
|
import {
|
|
|
|
default as BaseCard,
|
2018-02-05 17:12:47 +02:00
|
|
|
Outlet as CardOutlet,
|
|
|
|
Header as CardHeader,
|
|
|
|
HeaderMeta as CardHeaderMeta
|
|
|
|
} from '../card';
|
|
|
|
|
|
|
|
import { FormGroup, Input, Textarea, FormLabel, FormMeta } from '../form';
|
|
|
|
import { Delete as DeleteIcon, Arrow as ArrowIcon } from '../icons';
|
|
|
|
import { H4 } from '../text/headings';
|
|
|
|
import Button from '../button';
|
|
|
|
import Divider from '../divider';
|
2017-09-20 12:30:53 +03:00
|
|
|
|
2018-01-04 17:52:56 +02:00
|
|
|
const CollapsedKeyValue = styled.div`
|
2017-11-09 13:27:32 +02:00
|
|
|
word-break: break-all;
|
|
|
|
line-height: 1.5;
|
|
|
|
white-space: nowrap;
|
|
|
|
overflow: hidden;
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
display: block;
|
|
|
|
`;
|
2017-09-20 12:30:53 +03:00
|
|
|
|
2018-04-12 12:53:00 +03:00
|
|
|
const Card = styled(BaseCard)`
|
|
|
|
${is('borderless')`
|
|
|
|
border: none;
|
|
|
|
box-shadow: none;
|
|
|
|
`};
|
|
|
|
`;
|
|
|
|
|
2018-03-28 15:51:34 +03:00
|
|
|
const Header = styled(CardHeader)`
|
|
|
|
border-top: 0;
|
|
|
|
border-left: 0;
|
|
|
|
border-right: 0;
|
|
|
|
`;
|
|
|
|
|
|
|
|
const MarginalButton = styled(Button)`
|
|
|
|
margin-right: ${remcalc(6)};
|
|
|
|
`;
|
|
|
|
|
2018-01-12 17:25:26 +02:00
|
|
|
const PaddingMaxWidth = styled(Padding)`
|
|
|
|
word-wrap: break-word;
|
|
|
|
overflow-wrap: break-word;
|
|
|
|
width: 100%;
|
|
|
|
box-sizing: border-box;
|
|
|
|
`;
|
|
|
|
|
2018-01-31 14:44:06 +02:00
|
|
|
const Meta = styled(CardHeaderMeta)`
|
2018-01-31 17:08:17 +02:00
|
|
|
height: ${remcalc(47)};
|
2018-02-01 17:33:58 +02:00
|
|
|
max-width: 98%;
|
2018-01-31 17:08:17 +02:00
|
|
|
`;
|
2018-01-31 14:44:06 +02:00
|
|
|
|
2018-02-26 17:54:25 +02:00
|
|
|
const Bold = styled.span`
|
2018-02-28 00:40:51 +02:00
|
|
|
font-weight: ${props => props.theme.font.weight.semibold};
|
2018-02-26 17:54:25 +02:00
|
|
|
`;
|
|
|
|
|
2018-02-05 17:12:47 +02:00
|
|
|
const TextareaKeyValue = ({
|
|
|
|
type,
|
|
|
|
submitting,
|
|
|
|
onlyName,
|
|
|
|
onlyValue,
|
|
|
|
editor
|
|
|
|
}) => (
|
2018-01-19 19:37:31 +02:00
|
|
|
<Fragment>
|
|
|
|
{!onlyValue ? (
|
|
|
|
<Row>
|
|
|
|
<Col xs={12}>
|
|
|
|
<FormGroup name="name" field={Field} fluid>
|
|
|
|
<FormLabel>{titleCase(type)} key</FormLabel>
|
2018-01-30 18:04:03 +02:00
|
|
|
<Margin top={0.5}>
|
|
|
|
<Input onBlur={null} type="text" disabled={submitting} />
|
2018-02-23 19:57:13 +02:00
|
|
|
<Row>
|
|
|
|
<Col sm={7}>
|
|
|
|
<FormMeta />
|
|
|
|
</Col>
|
|
|
|
</Row>
|
2018-01-30 18:04:03 +02:00
|
|
|
</Margin>
|
2018-01-19 19:37:31 +02:00
|
|
|
</FormGroup>
|
|
|
|
<Divider height={remcalc(12)} transparent />
|
|
|
|
</Col>
|
|
|
|
</Row>
|
|
|
|
) : null}
|
|
|
|
{!onlyName ? (
|
|
|
|
<Row>
|
|
|
|
<Col xs={12}>
|
|
|
|
<FormGroup name="value" field={Field} fluid>
|
|
|
|
<FormLabel>{titleCase(type)} value</FormLabel>
|
2018-01-30 18:04:03 +02:00
|
|
|
<Margin top={0.5}>
|
2018-03-01 15:47:30 +02:00
|
|
|
<Textarea
|
|
|
|
monospace
|
2018-02-01 17:33:58 +02:00
|
|
|
name="name"
|
2018-03-01 15:47:30 +02:00
|
|
|
resize="vertical"
|
|
|
|
disabled={submitting}
|
2018-02-01 17:33:58 +02:00
|
|
|
fluid
|
|
|
|
/>
|
2018-01-30 18:04:03 +02:00
|
|
|
</Margin>
|
2018-02-23 19:57:13 +02:00
|
|
|
<Row>
|
|
|
|
<Col sm={7}>
|
|
|
|
<FormMeta />
|
|
|
|
</Col>
|
|
|
|
</Row>
|
2018-01-19 19:37:31 +02:00
|
|
|
</FormGroup>
|
|
|
|
<Divider height={remcalc(12)} transparent />
|
|
|
|
</Col>
|
|
|
|
</Row>
|
|
|
|
) : null}
|
|
|
|
</Fragment>
|
2017-12-06 20:16:11 +02:00
|
|
|
);
|
2017-11-09 13:27:32 +02:00
|
|
|
|
2018-02-22 02:01:07 +02:00
|
|
|
const InputKeyValue = ({
|
|
|
|
type,
|
|
|
|
submitting,
|
|
|
|
typeLabel,
|
|
|
|
onlyName,
|
|
|
|
onlyValue
|
|
|
|
}) => (
|
2018-02-01 17:33:58 +02:00
|
|
|
<Flex wrap justifyStart contentStretch>
|
2018-01-19 19:37:31 +02:00
|
|
|
{!onlyValue ? (
|
|
|
|
<FlexItem basis="auto">
|
|
|
|
<FormGroup name="name" field={Field} fluid>
|
2018-02-22 02:01:07 +02:00
|
|
|
<FormLabel>
|
|
|
|
{titleCase(type)} {typeLabel}
|
|
|
|
</FormLabel>
|
2018-04-12 12:53:00 +03:00
|
|
|
<Margin right={3} top={0.5}>
|
2018-01-30 18:04:03 +02:00
|
|
|
<Input onBlur={null} type="text" disabled={submitting} />
|
2018-02-23 19:57:13 +02:00
|
|
|
<Row>
|
|
|
|
<Col sm={7}>
|
|
|
|
<FormMeta />
|
|
|
|
</Col>
|
|
|
|
</Row>
|
2018-01-30 18:04:03 +02:00
|
|
|
</Margin>
|
2018-01-19 19:37:31 +02:00
|
|
|
</FormGroup>
|
|
|
|
</FlexItem>
|
|
|
|
) : null}
|
|
|
|
{!onlyName ? (
|
|
|
|
<Fragment>
|
|
|
|
<FlexItem basis="auto">
|
|
|
|
<FormGroup name="value" field={Field} fluid>
|
|
|
|
<FormLabel>{titleCase(type)} value</FormLabel>
|
2018-01-30 18:04:03 +02:00
|
|
|
<Margin top={0.5}>
|
2018-02-23 19:57:13 +02:00
|
|
|
<Input onBlur={null} type="text" disabled={submitting} />
|
|
|
|
<Row>
|
|
|
|
<Col sm={7}>
|
|
|
|
<FormMeta />
|
|
|
|
</Col>
|
|
|
|
</Row>
|
2018-01-30 18:04:03 +02:00
|
|
|
</Margin>
|
2018-01-19 19:37:31 +02:00
|
|
|
</FormGroup>
|
|
|
|
</FlexItem>
|
|
|
|
</Fragment>
|
|
|
|
) : null}
|
2018-01-05 17:42:09 +02:00
|
|
|
</Flex>
|
|
|
|
);
|
|
|
|
|
2017-12-21 21:20:22 +02:00
|
|
|
export const KeyValue = ({
|
2018-02-01 17:33:58 +02:00
|
|
|
disabled = false,
|
2017-12-21 21:20:22 +02:00
|
|
|
input = 'input',
|
|
|
|
type = 'metadata',
|
2018-02-22 02:01:07 +02:00
|
|
|
typeLabel = 'key',
|
2017-12-21 21:20:22 +02:00
|
|
|
method = 'add',
|
2018-01-04 12:56:10 +02:00
|
|
|
initialValues = {},
|
2017-12-21 21:20:22 +02:00
|
|
|
error = null,
|
|
|
|
expanded = true,
|
|
|
|
submitting = false,
|
|
|
|
pristine = true,
|
2018-02-23 19:57:13 +02:00
|
|
|
invalid = false,
|
2017-12-21 21:20:22 +02:00
|
|
|
removing = false,
|
2018-04-12 12:53:00 +03:00
|
|
|
onToggleExpanded,
|
2017-12-21 21:20:22 +02:00
|
|
|
onCancel = () => null,
|
|
|
|
onRemove = () => null,
|
2018-01-05 17:42:09 +02:00
|
|
|
theme = {},
|
2018-02-05 17:12:47 +02:00
|
|
|
editor = null,
|
2018-01-05 17:42:09 +02:00
|
|
|
onlyName = false,
|
2018-01-19 19:37:31 +02:00
|
|
|
onlyValue = false,
|
2018-01-12 17:25:26 +02:00
|
|
|
noRemove = false,
|
2018-04-12 12:53:00 +03:00
|
|
|
borderless = false,
|
|
|
|
customHeader,
|
|
|
|
headless = false
|
2017-12-21 21:20:22 +02:00
|
|
|
}) => {
|
|
|
|
const handleHeaderClick = method === 'edit' && onToggleExpanded;
|
2018-04-12 12:53:00 +03:00
|
|
|
|
2017-12-21 21:20:22 +02:00
|
|
|
return (
|
2018-04-12 12:53:00 +03:00
|
|
|
<Card
|
|
|
|
collapsed={!expanded}
|
|
|
|
actionable={Boolean(handleHeaderClick)}
|
|
|
|
borderless={borderless}
|
|
|
|
headless={headless}
|
|
|
|
shadow
|
|
|
|
>
|
|
|
|
{headless ? null : (
|
|
|
|
<Header
|
|
|
|
secondary={false}
|
|
|
|
transparent={false}
|
|
|
|
actionable={Boolean(handleHeaderClick)}
|
|
|
|
onClick={handleHeaderClick}
|
|
|
|
>
|
|
|
|
<PaddingMaxWidth left={borderless ? 0 : 3} right={borderless ? 0 : 3}>
|
2018-05-09 12:51:10 +03:00
|
|
|
<Flex alignCenter justifyBetween>
|
2018-04-12 12:53:00 +03:00
|
|
|
<Meta>
|
|
|
|
{method === 'add' || method === 'create' ? (
|
|
|
|
<H4>{`${titleCase(method)} ${type}`}</H4>
|
|
|
|
) : (
|
|
|
|
<CollapsedKeyValue>
|
|
|
|
{customHeader ? customHeader : null}
|
|
|
|
{initialValues.name ? (
|
|
|
|
<Fragment>
|
|
|
|
{expanded ? (
|
|
|
|
<span>{`${initialValues.name}${': '}`}</span>
|
|
|
|
) : (
|
|
|
|
<Bold>{`${initialValues.name}${': '}`}</Bold>
|
|
|
|
)}
|
|
|
|
<span>{initialValues.value}</span>
|
|
|
|
</Fragment>
|
|
|
|
) : null}
|
|
|
|
</CollapsedKeyValue>
|
|
|
|
)}
|
|
|
|
</Meta>
|
|
|
|
{handleHeaderClick ? (
|
|
|
|
<ArrowIcon
|
|
|
|
onClick={onToggleExpanded}
|
|
|
|
direction={expanded ? 'up' : 'down'}
|
|
|
|
/>
|
|
|
|
) : null}
|
|
|
|
</Flex>
|
|
|
|
</PaddingMaxWidth>
|
|
|
|
</Header>
|
|
|
|
)}
|
2017-12-21 02:12:42 +02:00
|
|
|
{expanded ? (
|
|
|
|
<CardOutlet>
|
2018-04-12 12:53:00 +03:00
|
|
|
<Padding
|
|
|
|
top={headless ? 0 : 3}
|
|
|
|
bottom={borderless ? 0 : 3}
|
|
|
|
horizontal={borderless ? 0 : 3}
|
|
|
|
>
|
2017-12-21 02:12:42 +02:00
|
|
|
{error && !submitting ? (
|
|
|
|
<Row>
|
|
|
|
<Col xs={12}>
|
2018-04-12 12:53:00 +03:00
|
|
|
<Margin bottom={5}>
|
2018-01-30 18:04:03 +02:00
|
|
|
<Message error>
|
|
|
|
<MessageTitle>Ooops!</MessageTitle>
|
|
|
|
<MessageDescription>{error}</MessageDescription>
|
|
|
|
</Message>
|
|
|
|
</Margin>
|
2017-12-21 02:12:42 +02:00
|
|
|
</Col>
|
|
|
|
</Row>
|
|
|
|
) : null}
|
|
|
|
{input === 'input' ? (
|
2018-01-19 19:37:31 +02:00
|
|
|
<InputKeyValue
|
|
|
|
onBlur={null}
|
|
|
|
type={type}
|
2018-02-22 02:01:07 +02:00
|
|
|
typeLabel={typeLabel}
|
2018-04-12 12:53:00 +03:00
|
|
|
submitting={disabled || submitting}
|
2018-01-19 19:37:31 +02:00
|
|
|
onlyName={onlyName}
|
|
|
|
onlyValue={onlyValue}
|
|
|
|
/>
|
2018-01-12 17:25:26 +02:00
|
|
|
) : null}
|
|
|
|
{input === 'textarea' ? (
|
2018-01-19 19:37:31 +02:00
|
|
|
<TextareaKeyValue
|
|
|
|
type={type}
|
2018-04-12 12:53:00 +03:00
|
|
|
submitting={disabled || submitting}
|
2018-01-19 19:37:31 +02:00
|
|
|
onlyName={onlyName}
|
|
|
|
onlyValue={onlyValue}
|
2018-02-05 17:12:47 +02:00
|
|
|
editor={editor}
|
2018-01-19 19:37:31 +02:00
|
|
|
/>
|
2018-01-12 17:25:26 +02:00
|
|
|
) : null}
|
2018-02-01 17:33:58 +02:00
|
|
|
{input !== 'textarea' && input !== 'input'
|
|
|
|
? input(submitting)
|
|
|
|
: null}
|
2018-04-12 12:53:00 +03:00
|
|
|
<Margin top={2}>
|
2018-02-01 12:38:12 +02:00
|
|
|
<Row between="xs" middle="xs">
|
|
|
|
<Col xs={method === 'add' ? 12 : 7}>
|
2018-03-28 15:51:34 +03:00
|
|
|
<MarginalButton
|
2018-01-05 17:42:09 +02:00
|
|
|
type="button"
|
2018-02-01 12:38:12 +02:00
|
|
|
onClick={onCancel}
|
2018-04-12 12:53:00 +03:00
|
|
|
disabled={disabled || submitting}
|
2018-01-05 17:42:09 +02:00
|
|
|
secondary
|
2018-02-01 17:33:58 +02:00
|
|
|
>
|
2018-02-01 12:38:12 +02:00
|
|
|
<span>Cancel</span>
|
2018-03-28 15:51:34 +03:00
|
|
|
</MarginalButton>
|
2018-02-01 12:38:12 +02:00
|
|
|
<Button
|
|
|
|
type="submit"
|
2018-02-23 19:57:13 +02:00
|
|
|
disabled={pristine || invalid}
|
2018-02-01 12:38:12 +02:00
|
|
|
loading={submitting && !removing}
|
2018-02-01 17:33:58 +02:00
|
|
|
>
|
2018-02-01 12:38:12 +02:00
|
|
|
<span>{method === 'add' ? 'Create' : 'Save'}</span>
|
2018-01-05 17:42:09 +02:00
|
|
|
</Button>
|
|
|
|
</Col>
|
2018-02-01 12:38:12 +02:00
|
|
|
{!noRemove && (
|
|
|
|
<Col xs={method === 'add' ? false : 5}>
|
|
|
|
<Button
|
|
|
|
type="button"
|
|
|
|
onClick={onRemove}
|
2018-04-12 12:53:00 +03:00
|
|
|
disabled={disabled || submitting}
|
2018-02-01 12:38:12 +02:00
|
|
|
loading={removing}
|
|
|
|
secondary
|
|
|
|
right
|
|
|
|
icon
|
|
|
|
error
|
2018-02-01 17:33:58 +02:00
|
|
|
>
|
2018-03-28 15:51:34 +03:00
|
|
|
<Margin right={2}>
|
|
|
|
<DeleteIcon
|
2018-04-12 12:53:00 +03:00
|
|
|
disabled={disabled || submitting}
|
|
|
|
fill={disabled || submitting ? undefined : theme.red}
|
2018-03-28 15:51:34 +03:00
|
|
|
/>
|
|
|
|
</Margin>
|
2018-02-01 12:38:12 +02:00
|
|
|
<span>Remove</span>
|
|
|
|
</Button>
|
|
|
|
</Col>
|
|
|
|
)}
|
|
|
|
</Row>
|
|
|
|
</Margin>
|
2017-12-21 02:12:42 +02:00
|
|
|
</Padding>
|
|
|
|
</CardOutlet>
|
|
|
|
) : null}
|
2017-12-21 21:20:22 +02:00
|
|
|
</Card>
|
|
|
|
);
|
|
|
|
};
|
2017-11-09 13:27:32 +02:00
|
|
|
|
2017-12-06 20:16:11 +02:00
|
|
|
KeyValue.propTypes = {
|
|
|
|
input: PropTypes.oneOf(['input', 'textarea']).isRequired,
|
|
|
|
type: PropTypes.string.isRequired,
|
|
|
|
method: PropTypes.oneOf(['add', 'edit']).isRequired,
|
2018-01-04 12:56:10 +02:00
|
|
|
initialValues: PropTypes.shape({
|
|
|
|
name: PropTypes.string,
|
|
|
|
value: PropTypes.string
|
|
|
|
}).isRequired,
|
2017-12-06 20:16:11 +02:00
|
|
|
removing: PropTypes.bool.isRequired,
|
|
|
|
expanded: PropTypes.bool.isRequired,
|
|
|
|
onToggleExpanded: PropTypes.func,
|
|
|
|
onCancel: PropTypes.func,
|
|
|
|
onRemove: PropTypes.func
|
2017-11-09 13:27:32 +02:00
|
|
|
};
|
2017-09-27 17:24:40 +03:00
|
|
|
|
2017-12-21 21:20:22 +02:00
|
|
|
export default withTheme(({ handleSubmit, ...rest }) => (
|
|
|
|
<form onSubmit={handleSubmit}>
|
|
|
|
<KeyValue {...rest} />
|
|
|
|
</form>
|
|
|
|
));
|