feat(instances): CI - Responsive behavior for tags #1121

This commit is contained in:
Fábio Moreira 2018-05-30 14:30:11 +01:00 committed by Sérgio Ramos
parent c268d88a4d
commit 2f9d135319
2 changed files with 259 additions and 267 deletions

View File

@ -10,7 +10,7 @@ import { reset } from 'redux-form';
import { destroy } from 'redux-form'; import { destroy } from 'redux-form';
import get from 'lodash.get'; import get from 'lodash.get';
import remcalc from 'remcalc'; import remcalc from 'remcalc';
import styled from 'styled-components'; import styled, { withTheme } from 'styled-components';
import Step, { import Step, {
Header as StepHeader, Header as StepHeader,
@ -55,114 +55,122 @@ const Tag = ({ name, value, onRemoveClick }) => (
</Margin> </Margin>
); );
const TagsContainer = ({ const TagsContainer = withTheme(
handleValidate, ({
handleGetValue, handleValidate,
preview = [], handleGetValue,
tags = [], preview = [],
addOpen = true, tags = [],
shouldAsyncValidate, addOpen = true,
handleAddTag, shouldAsyncValidate,
handleAsyncValidate, handleAddTag,
handleChangeAddOpen, handleAsyncValidate,
handleRemoveTag, handleChangeAddOpen,
handleCancelEdit, handleRemoveTag,
...props handleCancelEdit,
}) => ( theme = {},
<Step name="tags" getValue={handleGetValue} {...props}> ...props
<StepHeader icon={<TagsIcon />}>Tags</StepHeader> }) => {
<StepDescription href="https://docs.joyent.com/public-cloud/tags-metadata/tags"> const mobile = theme.screen === 'mobile';
Tags can be used to identify your instances, group multiple instances return (
together, define firewall and affinity rules, and more. <Step name="tags" getValue={handleGetValue} {...props}>
</StepDescription> <StepHeader icon={<TagsIcon />}>Tags</StepHeader>
<StepPreview> <StepDescription href="https://docs.joyent.com/public-cloud/tags-metadata/tags">
<Margin top="3"> Tags can be used to identify your instances, group multiple instances
<TagCount total={preview.length} /> together, define firewall and affinity rules, and more.
<TagList> </StepDescription>
{preview.map(({ name, value }, index) => ( <StepPreview>
<Tag name={name} value={value} /> <Margin top="3">
))} <TagCount total={preview.length} />
</TagList> <TagList>
</Margin> {preview.map(({ name, value }, index) => (
</StepPreview> <Tag name={name} value={value} />
<StepOutlet> ))}
{({ next }) => ( </TagList>
<Fragment> </Margin>
{tags.length ? ( </StepPreview>
<Margin top="5"> <StepOutlet>
<TagCount total={tags.length} /> {({ next }) => (
<TagList>
{tags.map(({ name, value }, index) => (
<Tag
name={name}
value={value}
onRemoveClick={() => handleRemoveTag(index)}
id={`tag-${index}`}
/>
))}
</TagList>
</Margin>
) : null}
{addOpen ? (
<Fragment> <Fragment>
<Margin top="2"> {tags.length ? (
<ReduxForm <Margin top="5">
form={IR_TAG_F_ADD} <TagCount total={tags.length} />
destroyOnUnmount={false} <TagList>
forceUnregisterOnUnmount={true} {tags.map(({ name, value }, index) => (
shouldAsyncValidate={shouldAsyncValidate} <Tag
asyncValidate={handleValidate} name={name}
onSubmit={handleAddTag} value={value}
> onRemoveClick={() => handleRemoveTag(index)}
{props => ( id={`tag-${index}`}
<Fragment>
<KeyValue
{...props}
method="add"
input="input"
type="tag"
id="tag"
expanded
borderless
onCancel={() => handleChangeAddOpen(false)}
/> />
</Fragment> ))}
)} </TagList>
</ReduxForm> </Margin>
</Margin> ) : null}
</Fragment> {addOpen ? (
) : ( <Fragment>
<Margin top="5"> <Margin top="2">
<Flex> <ReduxForm
<FlexItem> form={IR_TAG_F_ADD}
<Margin right="1"> destroyOnUnmount={false}
<Button forceUnregisterOnUnmount={true}
id="add-tag-button" shouldAsyncValidate={shouldAsyncValidate}
type="button" asyncValidate={handleValidate}
onClick={() => handleChangeAddOpen(true)} onSubmit={handleAddTag}
secondary
> >
Add Tag {props => (
</Button> <Fragment>
<KeyValue
{...props}
method="add"
input="input"
type="tag"
id="tag"
expanded
borderless
onCancel={() => handleChangeAddOpen(false)}
/>
</Fragment>
)}
</ReduxForm>
</Margin> </Margin>
</FlexItem> </Fragment>
<FlexItem> ) : (
<Button <Margin top="5">
id="next-button-tags" <Flex column={mobile}>
type="button" <FlexItem>
component={Link} <Margin right={mobile ? '0' : '1'}>
to={next} <Button
> id="add-tag-button"
Next type="button"
</Button> onClick={() => handleChangeAddOpen(true)}
</FlexItem> secondary
</Flex> fluid={mobile}
</Margin> >
Add Tag
</Button>
</Margin>
</FlexItem>
<FlexItem>
<Button
id="next-button-tags"
type="button"
component={Link}
to={next}
fluid={mobile}
>
Next
</Button>
</FlexItem>
</Flex>
</Margin>
)}
</Fragment>
)} )}
</Fragment> </StepOutlet>
)} </Step>
</StepOutlet> );
</Step> }
); );
export default compose( export default compose(

View File

@ -1,7 +1,7 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import { Margin, Padding } from 'styled-components-spacing'; import { Margin, Padding } from 'styled-components-spacing';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import styled from 'styled-components'; import styled, { withTheme } from 'styled-components';
import { Row, Col as BaseCol } from 'joyent-react-styled-flexboxgrid'; import { Row, Col as BaseCol } from 'joyent-react-styled-flexboxgrid';
import { Field } from 'redux-form'; import { Field } from 'redux-form';
import remcalc from 'remcalc'; import remcalc from 'remcalc';
@ -198,169 +198,152 @@ const InputKeyValue = ({
</Flex> </Flex>
); );
export const KeyValue = ({ export const KeyValue = withTheme(
id = null, ({
disabled = false, id = null,
input = 'input', disabled = false,
type = 'metadata', input = 'input',
typeLabel = 'key', type = 'metadata',
method = 'add', typeLabel = 'key',
initialValues = {}, method = 'add',
error = null, initialValues = {},
expanded = true, error = null,
submitting = false, expanded = true,
pristine = true, submitting = false,
invalid = false, pristine = true,
removing = false, invalid = false,
onToggleExpanded, removing = false,
onCancel = () => null, onToggleExpanded,
onRemove = () => null, onCancel = () => null,
editor = null, onRemove = () => null,
onlyName = false, editor = null,
onlyValue = false, onlyName = false,
noRemove = false, onlyValue = false,
borderless = false, noRemove = false,
shadow = true, borderless = false,
customHeader, shadow = true,
headless = false, customHeader,
noActions = false headless = false,
}) => { noActions = false,
const handleHeaderClick = method === 'edit' && onToggleExpanded; theme = {}
const mobile = theme.screen === 'mobile'; }) => {
const handleHeaderClick = method === 'edit' && onToggleExpanded;
const mobile = theme.screen === 'mobile';
return ( return (
<Card <Card
collapsed={!expanded} collapsed={!expanded}
actionable={Boolean(handleHeaderClick)} actionable={Boolean(handleHeaderClick)}
borderless={borderless} borderless={borderless}
headless={headless} headless={headless}
shadow={shadow} shadow={shadow}
> >
{headless ? null : ( {headless ? null : (
<Header <Header
secondary={false} secondary={false}
transparent={false} transparent={false}
actionable={Boolean(handleHeaderClick)} actionable={Boolean(handleHeaderClick)}
onClick={handleHeaderClick} onClick={handleHeaderClick}
>
<PaddingMaxWidth
left={borderless ? '0' : '3'}
right={borderless ? '0' : '3'}
> >
<Flex alignCenter justifyBetween> <PaddingMaxWidth
<Meta> left={borderless ? '0' : '3'}
{method === 'add' || method === 'create' ? ( right={borderless ? '0' : '3'}
<H4>{`${titleCase(method)} ${type}`}</H4> >
) : ( <Flex alignCenter justifyBetween>
<CollapsedKeyValue> <Meta>
{customHeader ? customHeader : null} {method === 'add' || method === 'create' ? (
{initialValues.name ? ( <H4>{`${titleCase(method)} ${type}`}</H4>
<Fragment> ) : (
{expanded ? ( <CollapsedKeyValue>
<span>{`${initialValues.name}${': '}`}</span> {customHeader ? customHeader : null}
) : ( {initialValues.name ? (
<Bold>{`${initialValues.name}${': '}`}</Bold> <Fragment>
)} {expanded ? (
<span>{initialValues.value}</span> <span>{`${initialValues.name}${': '}`}</span>
</Fragment> ) : (
) : null} <Bold>{`${initialValues.name}${': '}`}</Bold>
</CollapsedKeyValue> )}
)} <span>{initialValues.value}</span>
</Meta> </Fragment>
{handleHeaderClick ? ( ) : null}
<ArrowIcon </CollapsedKeyValue>
onClick={onToggleExpanded} )}
direction={expanded ? 'up' : 'down'} </Meta>
{handleHeaderClick ? (
<ArrowIcon
onClick={onToggleExpanded}
direction={expanded ? 'up' : 'down'}
/>
) : null}
</Flex>
</PaddingMaxWidth>
</Header>
)}
{expanded ? (
<CardOutlet>
<Padding
top={headless ? '0' : '3'}
bottom={borderless ? '0' : '3'}
horizontal={borderless ? '0' : '3'}
>
{error && !submitting ? (
<Row>
<Col xs="12">
<Margin bottom="5">
<Message error>
<MessageTitle>Ooops!</MessageTitle>
<MessageDescription>{error}</MessageDescription>
</Message>
</Margin>
</Col>
</Row>
) : null}
{input === 'input' ? (
<InputKeyValue
id={id}
onBlur={null}
type={type}
typeLabel={typeLabel}
submitting={disabled || submitting}
onlyName={onlyName}
onlyValue={onlyValue}
fluid={mobile}
/> />
) : null} ) : null}
</Flex> {input === 'textarea' ? (
</PaddingMaxWidth> <TextareaKeyValue
</Header> id={id}
)} type={type}
{expanded ? ( submitting={disabled || submitting}
<CardOutlet> onlyName={onlyName}
<Padding onlyValue={onlyValue}
top={headless ? '0' : '3'} editor={editor}
bottom={borderless ? '0' : '3'} />
horizontal={borderless ? '0' : '3'} ) : null}
> {input !== 'textarea' && input !== 'input'
{error && !submitting ? ( ? input(submitting)
<Row> : null}
<Col xs="12"> <Margin top={mobile ? '3' : '2'}>
<Margin bottom="5"> <Row between="xs" middle="xs">
<Message error> <Col xs={method === 'add' ? '12' : '7'} mobile={mobile}>
<MessageTitle>Ooops!</MessageTitle> <Margin top={mobile ? '1' : '0'} inline>
<MessageDescription>{error}</MessageDescription> <MarginalButton
</Message> id={id ? 'kv-cancel-button-' + id : null}
</Margin> type="button"
</Col> onClick={onCancel}
</Row> disabled={disabled || submitting}
) : null} secondary
{input === 'input' ? ( fluid={mobile}
<InputKeyValue >
id={id} <span>Cancel</span>
onBlur={null} </MarginalButton>
type={type} </Margin>
typeLabel={typeLabel}
submitting={disabled || submitting}
onlyName={onlyName}
onlyValue={onlyValue}
fluid={mobile}
/>
) : null}
{input === 'textarea' ? (
<TextareaKeyValue
id={id}
type={type}
submitting={disabled || submitting}
onlyName={onlyName}
onlyValue={onlyValue}
editor={editor}
/>
) : null}
{input !== 'textarea' && input !== 'input'
? input(submitting)
: null}
<Margin top={mobile ? '3' : '2'}>
<Row between="xs" middle="xs">
<Col xs={method === 'add' ? '12' : '7'} mobile={mobile}>
<Margin top={mobile ? '1' : '0'} inline>
<MarginalButton
id={id ? 'kv-cancel-button-' + id : null}
type="button"
onClick={onCancel}
disabled={disabled || submitting}
secondary
fluid={mobile}
>
<span>Cancel</span>
</MarginalButton>
</Margin>
<Button
id={id ? 'kv-submit-button-' + id : null}
type="submit"
disabled={pristine || invalid}
loading={submitting && !removing}
fluid={mobile}
>
<span>{method === 'add' ? 'Create' : 'Save'}</span>
</Button>
</Col>
{!noRemove && (
<Col xs={method === 'add' ? false : '5'}>
<Button
type="button"
onClick={onCancel}
disabled={disabled || submitting}
secondary
>
<span>Cancel</span>
</MarginalButton>
<Button <Button
id={id ? 'kv-submit-button-' + id : null} id={id ? 'kv-submit-button-' + id : null}
type="submit" type="submit"
disabled={pristine || invalid} disabled={pristine || invalid}
loading={submitting && !removing} loading={submitting && !removing}
fluid={mobile}
> >
<span>{method === 'add' ? 'Create' : 'Save'}</span> <span>{method === 'add' ? 'Create' : 'Save'}</span>
</Button> </Button>
@ -378,7 +361,7 @@ export const KeyValue = ({
error error
id={id ? 'kv-remove-button-' + id : null} id={id ? 'kv-remove-button-' + id : null}
> >
<Margin right="2"> <Margin right={2}>
<DeleteIcon <DeleteIcon
disabled={disabled || submitting} disabled={disabled || submitting}
fill={disabled || submitting ? undefined : 'red'} fill={disabled || submitting ? undefined : 'red'}
@ -390,13 +373,14 @@ export const KeyValue = ({
)} )}
</Row> </Row>
</Margin> </Margin>
)} )}
</Padding> </Padding>
</CardOutlet> </CardOutlet>
) : null} ) : null}
</Card> </Card>
); );
}; }
);
KeyValue.propTypes = { KeyValue.propTypes = {
input: PropTypes.oneOf(['input', 'textarea']).isRequired, input: PropTypes.oneOf(['input', 'textarea']).isRequired,