feat(instances): CI - metadata resposive

This commit is contained in:
Fábio Moreira 2018-05-30 14:47:36 +01:00 committed by Sérgio Ramos
parent 2f9d135319
commit cad1431e79
3 changed files with 396 additions and 383 deletions

View File

@ -1,6 +1,8 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import { Margin } from 'styled-components-spacing'; import { Margin } from 'styled-components-spacing';
import Flex, { FlexItem } from 'styled-flex-component'; import Flex, { FlexItem } from 'styled-flex-component';
import { withTheme } from 'styled-components';
import { compose } from 'react-apollo'; import { compose } from 'react-apollo';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import ReduxForm from 'declarative-redux-form'; import ReduxForm from 'declarative-redux-form';
@ -41,97 +43,105 @@ const Metadata = ({
shouldAsyncValidate, shouldAsyncValidate,
handleAsyncValidate, handleAsyncValidate,
handleChangeAddOpen, handleChangeAddOpen,
theme = {},
...props ...props
}) => ( }) => {
<Step name="metadata" getValue={handleGetValue} {...props}> const mobile = theme.screen === 'mobile';
<StepHeader icon={<MetadataIcon />}>Metadata</StepHeader>
<StepDescription href="https://docs.joyent.com/public-cloud/tags-metadata"> return (
Metadata can be used to pass data to the instance. It can also be used to <Step name="metadata" getValue={handleGetValue} {...props}>
inject a custom boot script. Unlike tags, metadata is only viewable inside <StepHeader icon={<MetadataIcon />}>Metadata</StepHeader>
the instance. <StepDescription href="https://docs.joyent.com/public-cloud/tags-metadata">
</StepDescription> Metadata can be used to pass data to the instance. It can also be used
<StepPreview> to inject a custom boot script. Unlike tags, metadata is only viewable
<Margin top="3"> inside the instance.
<Preview metadata={preview} disabled /> </StepDescription>
</Margin> <StepPreview>
</StepPreview> <Margin top="3">
<StepOutlet> <Preview metadata={preview} disabled />
{({ next }) => (
<Margin top="5">
{metadata.length ? (
<Fragment>
<Preview
metadata={metadata}
handleCancelEdit={handleCancelEdit}
handleRemoveMetadata={handleRemoveMetadata}
handleToggleExpanded={handleToggleExpanded}
handleUpdateMetadata={handleUpdateMetadata}
handleAddMetadata={handleAddMetadata}
shouldAsyncValidate={shouldAsyncValidate}
handleAsyncValidate={handleAsyncValidate}
handleChangeAddOpen={handleChangeAddOpen}
addOpen={addOpen}
/>
</Fragment>
) : null}
<ReduxForm
form={IR_MD_F_ADD}
destroyOnUnmount={false}
forceUnregisterOnUnmount={true}
onSubmit={handleAddMetadata}
shouldAsyncValidate={shouldAsyncValidate}
asyncValidate={handleAsyncValidate}
>
{props =>
addOpen ? (
<Fragment>
<KeyValue
{...props}
method="add"
input="textarea"
type="metadata"
id="metadata"
onCancel={() => handleChangeAddOpen(false)}
editor={Editor}
expanded
shadow={false}
/>
</Fragment>
) : (
<Margin top="5">
<Flex>
<FlexItem>
<Margin right="1">
<Button
id="button-add-metadata"
type="button"
onClick={() => handleChangeAddOpen(true)}
secondary
>
Add Metadata
</Button>
</Margin>
</FlexItem>
<FlexItem>
<Button
id="next-button-metadata"
type="button"
component={Link}
to={next}
>
Next
</Button>
</FlexItem>
</Flex>
</Margin>
)
}
</ReduxForm>
</Margin> </Margin>
)} </StepPreview>
</StepOutlet> <StepOutlet>
</Step> {({ next }) => (
); <Margin top="5">
{metadata.length ? (
<Fragment>
<Preview
metadata={metadata}
handleCancelEdit={handleCancelEdit}
handleRemoveMetadata={handleRemoveMetadata}
handleToggleExpanded={handleToggleExpanded}
handleUpdateMetadata={handleUpdateMetadata}
handleAddMetadata={handleAddMetadata}
shouldAsyncValidate={shouldAsyncValidate}
handleAsyncValidate={handleAsyncValidate}
handleChangeAddOpen={handleChangeAddOpen}
addOpen={addOpen}
/>
</Fragment>
) : null}
<ReduxForm
form={IR_MD_F_ADD}
destroyOnUnmount={false}
forceUnregisterOnUnmount={true}
onSubmit={handleAddMetadata}
shouldAsyncValidate={shouldAsyncValidate}
asyncValidate={handleAsyncValidate}
>
{props =>
addOpen ? (
<Fragment>
<KeyValue
{...props}
method="add"
input="textarea"
type="metadata"
id="metadata"
onCancel={() => handleChangeAddOpen(false)}
editor={Editor}
expanded
shadow={false}
/>
</Fragment>
) : (
<Margin top="5">
<Flex column={mobile}>
<FlexItem>
<Margin right={mobile ? '0' : '1'}>
<Button
id="button-add-metadata"
type="button"
onClick={() => handleChangeAddOpen(true)}
secondary
>
Add Metadata
</Button>
</Margin>
</FlexItem>
<FlexItem>
<Margin top={mobile ? 1 : 0}>
<Button
id="next-button-metadata"
type="button"
component={Link}
to={next}
fluid={mobile}
>
Next
</Button>
</Margin>
</FlexItem>
</Flex>
</Margin>
)
}
</ReduxForm>
</Margin>
)}
</StepOutlet>
</Step>
);
};
export default compose( export default compose(
connect(({ values }, ownProps) => { connect(({ values }, ownProps) => {
@ -203,4 +213,4 @@ export default compose(
]); ]);
} }
})) }))
)(Metadata); )(withTheme(({ ...rest }) => <Metadata {...rest} />));

View File

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

View File

@ -83,7 +83,8 @@ const TextareaKeyValue = ({
submitting, submitting,
onlyName, onlyName,
onlyValue, onlyValue,
editor editor,
mobile
}) => ( }) => (
<Fragment> <Fragment>
{onlyValue ? null : ( {onlyValue ? null : (
@ -97,7 +98,12 @@ const TextareaKeyValue = ({
> >
<FormLabel>{titleCase(type)} key</FormLabel> <FormLabel>{titleCase(type)} key</FormLabel>
<Margin top="0.5"> <Margin top="0.5">
<Input onBlur={null} type="text" disabled={submitting} /> <Input
onBlur={null}
type="text"
disabled={submitting}
fluid={mobile}
/>
<Row> <Row>
<Col sm="7"> <Col sm="7">
<FormMeta /> <FormMeta />
@ -105,6 +111,7 @@ const TextareaKeyValue = ({
</Row> </Row>
</Margin> </Margin>
</FormGroup> </FormGroup>
<Divider height={remcalc(12)} transparent />
</Col> </Col>
</Row> </Row>
)} )}
@ -133,6 +140,7 @@ const TextareaKeyValue = ({
</Col> </Col>
</Row> </Row>
</FormGroup> </FormGroup>
<Divider height={remcalc(12)} transparent />
</Col> </Col>
</Row> </Row>
)} )}
@ -149,7 +157,7 @@ const InputKeyValue = ({
fluid = false fluid = false
}) => ( }) => (
<Flex wrap justifyStart contentStretch column={fluid}> <Flex wrap justifyStart contentStretch column={fluid}>
{!onlyValue ? ( {onlyValue ? null : (
<FlexItem basis="auto"> <FlexItem basis="auto">
<FormGroup <FormGroup
id={id ? 'kv-input-name-' + id : null} id={id ? 'kv-input-name-' + id : null}
@ -170,7 +178,7 @@ const InputKeyValue = ({
</Margin> </Margin>
</FormGroup> </FormGroup>
</FlexItem> </FlexItem>
) : null} )}
{onlyName ? null : ( {onlyName ? null : (
<Fragment> <Fragment>
<FlexItem basis="auto"> <FlexItem basis="auto">
@ -198,189 +206,186 @@ const InputKeyValue = ({
</Flex> </Flex>
); );
export const KeyValue = withTheme( export const KeyValue = ({
({ id = null,
id = null, disabled = false,
disabled = false, input = 'input',
input = 'input', type = 'metadata',
type = 'metadata', typeLabel = 'key',
typeLabel = 'key', method = 'add',
method = 'add', initialValues = {},
initialValues = {}, error = null,
error = null, expanded = true,
expanded = true, submitting = false,
submitting = false, pristine = true,
pristine = true, invalid = false,
invalid = false, removing = false,
removing = false, onToggleExpanded,
onToggleExpanded, onCancel = () => null,
onCancel = () => null, onRemove = () => null,
onRemove = () => null, theme = {},
editor = null, editor = null,
onlyName = false, onlyName = false,
onlyValue = false, onlyValue = false,
noRemove = false, noRemove = false,
borderless = false, borderless = false,
shadow = true, shadow = true,
customHeader, customHeader,
headless = false, headless = false
noActions = false, }) => {
theme = {} const handleHeaderClick = method === 'edit' && onToggleExpanded;
}) => { 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'}
> >
<PaddingMaxWidth <Flex alignCenter justifyBetween>
left={borderless ? '0' : '3'} <Meta>
right={borderless ? '0' : '3'} {method === 'add' || method === 'create' ? (
> <H4>{`${titleCase(method)} ${type}`}</H4>
<Flex alignCenter justifyBetween> ) : (
<Meta> <CollapsedKeyValue>
{method === 'add' || method === 'create' ? ( {customHeader ? customHeader : null}
<H4>{`${titleCase(method)} ${type}`}</H4> {initialValues.name ? (
) : ( <Fragment>
<CollapsedKeyValue> {expanded ? (
{customHeader ? customHeader : null} <span>{`${initialValues.name}${': '}`}</span>
{initialValues.name ? ( ) : (
<Fragment> <Bold>{`${initialValues.name}${': '}`}</Bold>
{expanded ? ( )}
<span>{`${initialValues.name}${': '}`}</span> <span>{initialValues.value}</span>
) : ( </Fragment>
<Bold>{`${initialValues.name}${': '}`}</Bold> ) : null}
)} </CollapsedKeyValue>
<span>{initialValues.value}</span> )}
</Fragment> </Meta>
) : null} {handleHeaderClick ? (
</CollapsedKeyValue> <ArrowIcon
)} onClick={onToggleExpanded}
</Meta> direction={expanded ? 'up' : 'down'}
{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}
{input === 'textarea' ? ( </Flex>
<TextareaKeyValue </PaddingMaxWidth>
id={id} </Header>
type={type} )}
submitting={disabled || submitting} {expanded ? (
onlyName={onlyName} <CardOutlet>
onlyValue={onlyValue} <Padding
editor={editor} top={headless ? '0' : '3'}
/> bottom={borderless ? '0' : '3'}
) : null} horizontal={borderless ? '0' : '3'}
{input !== 'textarea' && input !== 'input' >
? input(submitting) {error && !submitting ? (
: null} <Row>
<Margin top={mobile ? '3' : '2'}> <Col xs="12">
<Row between="xs" middle="xs"> <Margin bottom="5">
<Col xs={method === 'add' ? '12' : '7'} mobile={mobile}> <Message error>
<Margin top={mobile ? '1' : '0'} inline> <MessageTitle>Ooops!</MessageTitle>
<MarginalButton <MessageDescription>{error}</MessageDescription>
id={id ? 'kv-cancel-button-' + id : null} </Message>
type="button" </Margin>
onClick={onCancel} </Col>
disabled={disabled || submitting} </Row>
secondary ) : null}
fluid={mobile} {input === 'input' ? (
> <InputKeyValue
<span>Cancel</span> id={id}
</MarginalButton> onBlur={null}
</Margin> type={type}
<Button typeLabel={typeLabel}
id={id ? 'kv-submit-button-' + id : null} submitting={disabled || submitting}
type="submit" onlyName={onlyName}
disabled={pristine || invalid} onlyValue={onlyValue}
loading={submitting && !removing} fluid={mobile}
/>
) : null}
{input === 'textarea' ? (
<TextareaKeyValue
id={id}
type={type}
submitting={disabled || submitting}
onlyName={onlyName}
onlyValue={onlyValue}
editor={editor}
mobile={mobile}
/>
) : 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} fluid={mobile}
> >
<span>{method === 'add' ? 'Create' : 'Save'}</span> <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={onRemove}
disabled={disabled || submitting}
loading={removing}
secondary
right
icon
error
id={id ? 'kv-remove-button-' + id : null}
>
<Margin right="2">
<DeleteIcon
disabled={disabled || submitting}
fill={disabled || submitting ? undefined : theme.red}
/>
</Margin>
<span>Delete</span>
</Button> </Button>
</Col> </Col>
{!noRemove && ( )}
<Col xs={method === 'add' ? false : '5'}> </Row>
<Button </Margin>
type="button" </Padding>
onClick={onRemove} </CardOutlet>
disabled={disabled || submitting} ) : null}
loading={removing} </Card>
secondary );
right };
icon
error
id={id ? 'kv-remove-button-' + id : null}
>
<Margin right={2}>
<DeleteIcon
disabled={disabled || submitting}
fill={disabled || submitting ? undefined : 'red'}
/>
</Margin>
<span>Delete</span>
</Button>
</Col>
)}
</Row>
</Margin>
)}
</Padding>
</CardOutlet>
) : null}
</Card>
);
}
);
KeyValue.propTypes = { KeyValue.propTypes = {
input: PropTypes.oneOf(['input', 'textarea']).isRequired, input: PropTypes.oneOf(['input', 'textarea']).isRequired,
@ -397,8 +402,8 @@ KeyValue.propTypes = {
onRemove: PropTypes.func onRemove: PropTypes.func
}; };
export default ({ handleSubmit, ...rest }) => ( export default withTheme(({ handleSubmit, ...rest }) => (
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<KeyValue {...rest} /> <KeyValue {...rest} />
</form> </form>
); ));