feat(my-joy-beta): revise Metadata and KeyValue implementations
fixes #908
This commit is contained in:
parent
c184066f26
commit
2538453d98
@ -1,4 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withTheme } from 'styled-components';
|
||||
import { Row, Col } from 'react-styled-flexboxgrid';
|
||||
import Value from 'react-redux-values';
|
||||
import { Field } from 'redux-form';
|
||||
@ -6,6 +8,7 @@ import styled from 'styled-components';
|
||||
import remcalc from 'remcalc';
|
||||
import titleCase from 'title-case';
|
||||
import { Margin, Padding } from 'styled-components-spacing';
|
||||
import Flex, { FlexItem } from 'styled-flex-component';
|
||||
import Editor from 'joyent-ui-toolkit/dist/es/editor';
|
||||
|
||||
import {
|
||||
@ -25,7 +28,9 @@ import {
|
||||
FormMeta,
|
||||
Button,
|
||||
Textarea,
|
||||
Divider
|
||||
Editor,
|
||||
Divider,
|
||||
DeleteIcon
|
||||
} from 'joyent-ui-toolkit';
|
||||
|
||||
const CollapsedKeyValue = styled.span`
|
||||
@ -49,155 +54,180 @@ class ValueTextareaField extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
const KeyValue = ({
|
||||
id,
|
||||
label = '',
|
||||
textarea,
|
||||
create,
|
||||
last,
|
||||
first,
|
||||
expanded,
|
||||
removing,
|
||||
pristine,
|
||||
error,
|
||||
submitting,
|
||||
onRemove,
|
||||
onToggleExpanded,
|
||||
handleSubmit,
|
||||
onClear
|
||||
}) => {
|
||||
const _error = error &&
|
||||
!submitting && (
|
||||
<Message error>
|
||||
<MessageTitle>Ooops!</MessageTitle>
|
||||
<MessageDescription>{error}</MessageDescription>
|
||||
</Message>
|
||||
);
|
||||
|
||||
const _meta = expanded ? (
|
||||
<H4>{create ? `Create ${label}` : `Edit ${label}`}</H4>
|
||||
) : (
|
||||
<CollapsedKeyValue>
|
||||
<Field
|
||||
name="name"
|
||||
type="text"
|
||||
component={({ input }) => <b>{`${input.value}: `}</b>}
|
||||
/>
|
||||
<Field name="value" type="text" component={({ input }) => input.value} />
|
||||
</CollapsedKeyValue>
|
||||
);
|
||||
|
||||
const chevronToggle = create ? null : (
|
||||
<CardHeaderBox onClick={onToggleExpanded} actionable={expanded}>
|
||||
<ChevronIcon />
|
||||
</CardHeaderBox>
|
||||
);
|
||||
|
||||
const _valueField = textarea ? (
|
||||
const TextareaKeyValue = ({ type, submitting }) => [
|
||||
<Row key="key">
|
||||
<Col xs={12}>
|
||||
<FormGroup name="name" reduxForm fluid>
|
||||
<FormLabel>{titleCase(type)} key</FormLabel>
|
||||
<Input type="text" disabled={submitting} />
|
||||
<FormMeta />
|
||||
</FormGroup>
|
||||
<Divider height={remcalc(12)} transparent />
|
||||
</Col>
|
||||
</Row>,
|
||||
<Row key="value">
|
||||
<Col xs={12}>
|
||||
<FormGroup name="value" reduxForm fluid>
|
||||
<FormLabel>{titleCase(type)} value</FormLabel>
|
||||
<Field
|
||||
name="name"
|
||||
fluid
|
||||
component={ValueTextareaField}
|
||||
props={{ submitting }}
|
||||
/>
|
||||
) : (
|
||||
<Input disabled={submitting} />
|
||||
);
|
||||
|
||||
const _cancel = (
|
||||
<Button
|
||||
type="button"
|
||||
key="cancel"
|
||||
bold
|
||||
onClick={
|
||||
create
|
||||
? pristine ? onToggleExpanded : onClear
|
||||
: pristine ? onRemove : onClear
|
||||
}
|
||||
disabled={submitting}
|
||||
loading={submitting && removing}
|
||||
secondary
|
||||
marginless
|
||||
>
|
||||
{create ? (pristine ? 'Cancel' : 'Clear') : pristine ? 'Remove' : 'Clear'}
|
||||
</Button>
|
||||
);
|
||||
|
||||
const _submit = (
|
||||
<Button
|
||||
type="submit"
|
||||
key="submit"
|
||||
bold
|
||||
disabled={pristine || submitting}
|
||||
loading={submitting && !removing}
|
||||
marginless
|
||||
>
|
||||
{create ? 'Create' : 'Update'}
|
||||
</Button>
|
||||
);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Divider
|
||||
transparent
|
||||
marginBottom={!first && expanded ? remcalc(13) : 0}
|
||||
/>
|
||||
<Card
|
||||
collapsed={!expanded}
|
||||
actionable={!expanded}
|
||||
bottomless={!last && !expanded}
|
||||
>
|
||||
<CardHeader
|
||||
secondary={false}
|
||||
transparent={false}
|
||||
onClick={onToggleExpanded}
|
||||
actionable
|
||||
>
|
||||
<CardHeaderMeta>
|
||||
<Padding left={1}>{_meta}</Padding>
|
||||
</CardHeaderMeta>
|
||||
{chevronToggle}
|
||||
</CardHeader>
|
||||
<CardOutlet>
|
||||
<Padding all={1}>
|
||||
<Row>
|
||||
<Col xs={12}>{_error}</Col>
|
||||
<FormMeta />
|
||||
</FormGroup>
|
||||
<Divider height={remcalc(12)} transparent />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col xs={6}>
|
||||
<FormGroup name="name" field={Field} fluid>
|
||||
<FormLabel>Enter {titleCase(label)} key</FormLabel>
|
||||
];
|
||||
|
||||
const InputKeyValue = ({ type, submitting }) => (
|
||||
<Flex full justifyStart contentStretch>
|
||||
<FlexItem basis="auto">
|
||||
<FormGroup name="name" reduxForm fluid>
|
||||
<FormLabel>{titleCase(type)} key</FormLabel>
|
||||
<Input type="text" disabled={submitting} />
|
||||
<FormMeta />
|
||||
</FormGroup>
|
||||
</Col>
|
||||
<Col xs={6}>
|
||||
<FormGroup name="value" field={Field} fluid>
|
||||
<FormLabel>Enter {titleCase(label)} value</FormLabel>
|
||||
{_valueField}
|
||||
</FlexItem>
|
||||
<FlexItem basis="auto">
|
||||
<FormGroup name="value" reduxForm fluid>
|
||||
<FormLabel>{titleCase(type)} value</FormLabel>
|
||||
<Input disabled={submitting} />
|
||||
<FormMeta />
|
||||
</FormGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
const KeyValue = withTheme(
|
||||
({
|
||||
input = 'input',
|
||||
type = 'metadata',
|
||||
method = 'add',
|
||||
error = null,
|
||||
expanded = true,
|
||||
submitting = false,
|
||||
pristine = true,
|
||||
removing = false,
|
||||
handleSubmit,
|
||||
onToggleExpanded = () => null,
|
||||
onCancel = () => null,
|
||||
onRemove = () => null,
|
||||
theme
|
||||
}) => {
|
||||
const handleHeaderClick = method === 'edit' && onToggleExpanded;
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Card collapsed={!expanded} actionable={!expanded} shadow>
|
||||
<CardHeader
|
||||
secondary={false}
|
||||
transparent={false}
|
||||
actionable={Boolean(handleHeaderClick)}
|
||||
onClick={handleHeaderClick}
|
||||
>
|
||||
<CardHeaderMeta>
|
||||
{method === 'add' ? (
|
||||
<H4>{`${titleCase(method)} ${type}`}</H4>
|
||||
) : (
|
||||
<CollapsedKeyValue>
|
||||
<Field
|
||||
name="name"
|
||||
type="text"
|
||||
component={({ input }) =>
|
||||
expanded ? (
|
||||
`${input.value}: `
|
||||
) : (
|
||||
<b>{`${input.value}: `}</b>
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Field
|
||||
name="value"
|
||||
type="text"
|
||||
component={({ input }) => input.value}
|
||||
/>
|
||||
</CollapsedKeyValue>
|
||||
)}
|
||||
</CardHeaderMeta>
|
||||
</CardHeader>
|
||||
<CardOutlet>
|
||||
<Padding all={1}>
|
||||
{error && !submitting ? (
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
<Margin top={2}>
|
||||
{_cancel}
|
||||
{_submit}
|
||||
</Margin>
|
||||
<Message error>
|
||||
<MessageTitle>Ooops!</MessageTitle>
|
||||
<MessageDescription>{error}</MessageDescription>
|
||||
</Message>
|
||||
</Col>
|
||||
</Row>
|
||||
) : null}
|
||||
{input === 'input' ? (
|
||||
<InputKeyValue type={type} submitting={submitting} />
|
||||
) : (
|
||||
<TextareaKeyValue type={type} submitting={submitting} />
|
||||
)}
|
||||
<Row between="xs" middle="xs">
|
||||
<Col xs={method === 'add' ? 12 : 7}>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={onCancel}
|
||||
disabled={submitting}
|
||||
secondary
|
||||
marginless
|
||||
>
|
||||
<span>Cancel</span>
|
||||
</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={pristine}
|
||||
loading={submitting && !removing}
|
||||
marginless
|
||||
>
|
||||
<span>{method === 'add' ? 'Create' : 'Save'}</span>
|
||||
</Button>
|
||||
</Col>
|
||||
<Col xs={method === 'add' ? false : 5}>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={onRemove}
|
||||
disabled={submitting}
|
||||
loading={removing}
|
||||
secondary
|
||||
right
|
||||
icon
|
||||
error
|
||||
marginless
|
||||
>
|
||||
<DeleteIcon
|
||||
disabled={submitting}
|
||||
fill={submitting ? undefined : theme.red}
|
||||
/>
|
||||
<span>Delete</span>
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</Padding>
|
||||
</CardOutlet>
|
||||
</Card>
|
||||
<Divider transparent marginBottom={last || expanded ? remcalc(13) : 0} />
|
||||
<Divider height={remcalc(13)} transparent />
|
||||
</form>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
KeyValue.propTypes = {
|
||||
input: PropTypes.oneOf(['input', 'textarea']).isRequired,
|
||||
type: PropTypes.string.isRequired,
|
||||
method: PropTypes.oneOf(['add', 'edit']).isRequired,
|
||||
removing: PropTypes.bool.isRequired,
|
||||
expanded: PropTypes.bool.isRequired,
|
||||
onToggleExpanded: PropTypes.func,
|
||||
onCancel: PropTypes.func,
|
||||
onRemove: PropTypes.func
|
||||
};
|
||||
|
||||
export default ({ id, ...rest }) => (
|
||||
<Value name={`${id}-removing`}>
|
||||
{({ value: removing }) => (
|
||||
<KeyValue {...rest} removing={removing} id={id} />
|
||||
)}
|
||||
</Value>
|
||||
);
|
||||
export default props => <KeyValue {...props} />;
|
||||
|
47
packages/my-joy-beta/src/components/instances/metadata.js
Normal file
47
packages/my-joy-beta/src/components/instances/metadata.js
Normal file
@ -0,0 +1,47 @@
|
||||
import React from 'react';
|
||||
import KeyValue from './key-value';
|
||||
|
||||
import {
|
||||
Row,
|
||||
Col,
|
||||
FormGroup,
|
||||
Input,
|
||||
FormLabel,
|
||||
Button
|
||||
} from 'joyent-ui-toolkit';
|
||||
|
||||
export const MenuForm = ({ searchable, onAdd }) => (
|
||||
<form>
|
||||
<Row>
|
||||
<Col xs={7} sm={5}>
|
||||
<FormGroup name="filter" fluid reduxForm>
|
||||
<FormLabel>Filter</FormLabel>
|
||||
<Input disabled={!searchable} fluid />
|
||||
</FormGroup>
|
||||
</Col>
|
||||
<Col xs={5} sm={7}>
|
||||
<FormGroup right>
|
||||
<FormLabel>⁣</FormLabel>
|
||||
<Button
|
||||
type="button"
|
||||
disabled={!searchable}
|
||||
onClick={onAdd}
|
||||
small
|
||||
icon
|
||||
fluid
|
||||
>
|
||||
Add metadata
|
||||
</Button>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
</form>
|
||||
);
|
||||
|
||||
export const AddForm = props => (
|
||||
<KeyValue {...props} method="add" input="textarea" type="metadata" expanded />
|
||||
);
|
||||
|
||||
export const EditForm = props => (
|
||||
<KeyValue {...props} method="edit" input="textarea" type="metadata" />
|
||||
);
|
@ -30,6 +30,7 @@ import DisableInstanceFw from '@graphql/disable-instance-fw.gql';
|
||||
import CreateSnapshot from '@graphql/create-snapshot.gql';
|
||||
import StartSnapshot from '@graphql/start-from-snapshot.gql';
|
||||
import Index from '@state/gen-index';
|
||||
import parseError from '@state/parse-error';
|
||||
|
||||
import {
|
||||
default as InstanceList,
|
||||
@ -264,12 +265,6 @@ export default compose(
|
||||
})
|
||||
);
|
||||
|
||||
// parses the error to handle existance or not of graphQLErrors
|
||||
const parseError = ({ graphQLErrors = [], message = '' }) =>
|
||||
graphQLErrors.length
|
||||
? graphQLErrors.map(({ message }) => message).join('\n')
|
||||
: message;
|
||||
|
||||
// reverts submitting flag to false and propagates the error if it exists
|
||||
const flipSubmitFalse = stopSubmit(TABLE_FORM_NAME, {
|
||||
_error: err && parseError(err)
|
||||
|
@ -6,115 +6,121 @@ import { connect } from 'react-redux';
|
||||
import { SubmissionError, reset, startSubmit, stopSubmit } from 'redux-form';
|
||||
import ReduxForm from 'declarative-redux-form';
|
||||
import find from 'lodash.find';
|
||||
import sortBy from 'lodash.sortby';
|
||||
import get from 'lodash.get';
|
||||
import intercept from 'apr-intercept';
|
||||
import remcalc from 'remcalc';
|
||||
|
||||
import {
|
||||
ViewContainer,
|
||||
Title,
|
||||
StatusLoader,
|
||||
Message,
|
||||
MessageDescription,
|
||||
MessageTitle,
|
||||
Button
|
||||
Button,
|
||||
Divider,
|
||||
H3
|
||||
} from 'joyent-ui-toolkit';
|
||||
|
||||
import GetMetadata from '@graphql/list-metadata.gql';
|
||||
import UpdateMetadata from '@graphql/update-metadata.gql';
|
||||
import DeleteMetadata from '@graphql/delete-metadata.gql';
|
||||
import { KeyValue } from '@components/instances';
|
||||
import parseError from '@state/parse-error';
|
||||
|
||||
const METADATA_FORM_KEY = (name, field) => `instance-metadata-${name}-${field}`;
|
||||
const CREATE_METADATA_FORM_KEY = name => `instance-create-metadata-${name}`;
|
||||
import {
|
||||
MenuForm as MetadataMenuForm,
|
||||
AddForm as MetadataAddForm,
|
||||
EditForm as MetadataEditForm
|
||||
} from '@components/instances/metadata';
|
||||
|
||||
const MENU_FORM_NAME = 'instance-metadata-list-menu';
|
||||
const ADD_FORM_NAME = 'instance-metadata-add-new';
|
||||
const METADATA_FORM_KEY = field => `instance-metadata-${paramCase(field)}`;
|
||||
|
||||
const Metadata = ({
|
||||
instance,
|
||||
values = [],
|
||||
metadata = [],
|
||||
addOpen,
|
||||
loading,
|
||||
error,
|
||||
handleRemove,
|
||||
handleClear,
|
||||
handleToggleAddOpen,
|
||||
handleUpdateExpanded,
|
||||
handleCancel,
|
||||
handleCreate,
|
||||
handleUpdate,
|
||||
handleCreate
|
||||
handleRemove
|
||||
}) => {
|
||||
const _loading = !(loading && !values.length) ? null : <StatusLoader />;
|
||||
const _loading = !(loading && !metadata.length) ? null : <StatusLoader />;
|
||||
|
||||
const _add = addOpen ? (
|
||||
<ReduxForm
|
||||
form={ADD_FORM_NAME}
|
||||
onSubmit={handleCreate}
|
||||
onCancel={() => handleToggleAddOpen(false)}
|
||||
>
|
||||
{MetadataAddForm}
|
||||
</ReduxForm>
|
||||
) : null;
|
||||
|
||||
const _line = !_loading
|
||||
? [
|
||||
<Divider key="line" height={remcalc(1)} />,
|
||||
<Divider key="after-line-space" height={remcalc(24)} transparent />
|
||||
]
|
||||
: null;
|
||||
|
||||
const _count = !_loading ? (
|
||||
<H3 marginBottom={remcalc(24)} marginTop={addOpen && remcalc(24)}>
|
||||
{metadata.length} key:value pair
|
||||
</H3>
|
||||
) : null;
|
||||
|
||||
// metadata items forms
|
||||
const _metadata =
|
||||
!_loading &&
|
||||
values.map(({ form, initialValues }, i) => (
|
||||
<Value name={`${form}-expanded`} key={form}>
|
||||
{({ value: expanded, onValueChange }) => (
|
||||
metadata.map(({ form, initialValues, expanded, removing }) => (
|
||||
<ReduxForm
|
||||
form={form}
|
||||
key={form}
|
||||
initialValues={initialValues}
|
||||
onSubmit={newValues => handleUpdate(newValues, form)}
|
||||
destroyOnUnmount
|
||||
id={form}
|
||||
onClear={() => handleClear(form)}
|
||||
onToggleExpanded={() => onValueChange(!expanded)}
|
||||
destroyOnUnmount={false}
|
||||
onSubmit={handleUpdate}
|
||||
onToggleExpanded={() => handleUpdateExpanded(form, !expanded)}
|
||||
onCancel={() => handleCancel(form)}
|
||||
onRemove={() => handleRemove(form)}
|
||||
label="metadata"
|
||||
last={values.length - 1 === i}
|
||||
first={i === 0}
|
||||
expanded={expanded}
|
||||
textarea
|
||||
removing={removing}
|
||||
>
|
||||
{KeyValue}
|
||||
{MetadataEditForm}
|
||||
</ReduxForm>
|
||||
)}
|
||||
</Value>
|
||||
));
|
||||
|
||||
// create metadata form
|
||||
const _addKey = instance && CREATE_METADATA_FORM_KEY(instance.name);
|
||||
const _add = _metadata &&
|
||||
_addKey && (
|
||||
<Value name={`${_addKey}-expanded`}>
|
||||
{({ value: expanded, onValueChange }) =>
|
||||
!expanded ? (
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => onValueChange(!expanded)}
|
||||
secondary
|
||||
>
|
||||
Add metadata
|
||||
</Button>
|
||||
) : (
|
||||
<ReduxForm
|
||||
form={_addKey}
|
||||
onSubmit={handleCreate}
|
||||
id={_addKey}
|
||||
onClear={() => handleClear(_addKey)}
|
||||
onToggleExpanded={() => onValueChange(!expanded)}
|
||||
onRemove={() => handleRemove(_addKey)}
|
||||
expanded={expanded}
|
||||
label="metadata"
|
||||
create
|
||||
textarea
|
||||
>
|
||||
{KeyValue}
|
||||
</ReduxForm>
|
||||
)}
|
||||
</Value>
|
||||
);
|
||||
|
||||
// fetching error
|
||||
const _error =
|
||||
error && !values.length && !_loading ? (
|
||||
error && !_metadata.length && !_loading ? (
|
||||
<Message error>
|
||||
<MessageTitle>Ooops!</MessageTitle>
|
||||
<MessageDescription>
|
||||
An error occurred while loading your instance metadata
|
||||
An error occurred while loading your metadata
|
||||
</MessageDescription>
|
||||
</Message>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<ViewContainer center={Boolean(_loading)} main>
|
||||
{_loading}
|
||||
<ViewContainer main>
|
||||
<ReduxForm
|
||||
form={MENU_FORM_NAME}
|
||||
searchable={!_loading}
|
||||
onAdd={() => handleToggleAddOpen(!addOpen)}
|
||||
>
|
||||
{MetadataMenuForm}
|
||||
</ReduxForm>
|
||||
<Divider height={remcalc(11)} transparent />
|
||||
{_line}
|
||||
{_error}
|
||||
{_metadata}
|
||||
{_loading}
|
||||
{_add}
|
||||
{_count}
|
||||
{_metadata}
|
||||
</ViewContainer>
|
||||
);
|
||||
};
|
||||
@ -124,7 +130,7 @@ export default compose(
|
||||
graphql(DeleteMetadata, { name: 'deleteMetadata' }),
|
||||
graphql(GetMetadata, {
|
||||
options: ({ match }) => ({
|
||||
pollInterval: 1000,
|
||||
// pollInterval: 1000,
|
||||
variables: {
|
||||
name: get(match, 'params.instance')
|
||||
}
|
||||
@ -133,23 +139,18 @@ export default compose(
|
||||
const { name } = variables;
|
||||
|
||||
const instance = find(get(rest, 'machines', []), ['name', name]);
|
||||
const metadata = get(instance, 'metadata', []);
|
||||
const values = get(instance, 'metadata', []);
|
||||
|
||||
const values = sortBy(metadata, 'name').map(({ name, value }) => {
|
||||
const field = paramCase(name);
|
||||
const form = METADATA_FORM_KEY(name, field);
|
||||
|
||||
return {
|
||||
form,
|
||||
const metadata = values.map(({ name, value }) => ({
|
||||
form: METADATA_FORM_KEY(name),
|
||||
initialValues: {
|
||||
name,
|
||||
value
|
||||
}
|
||||
};
|
||||
});
|
||||
}));
|
||||
|
||||
return {
|
||||
values,
|
||||
metadata,
|
||||
instance,
|
||||
loading,
|
||||
error,
|
||||
@ -157,58 +158,76 @@ export default compose(
|
||||
};
|
||||
}
|
||||
}),
|
||||
connect(null, (dispatch, ownProps) => {
|
||||
connect(
|
||||
({ values }, { metadata, ownProps }) => ({
|
||||
...ownProps,
|
||||
addOpen: get(values, 'add-metadata-open', false),
|
||||
metadata: metadata.map(({ form, ...metadata }) => ({
|
||||
...metadata,
|
||||
form,
|
||||
expanded: get(values, `${form}-expanded`, false),
|
||||
removing: get(values, `${form}-removing`, false)
|
||||
}))
|
||||
}),
|
||||
(dispatch, ownProps) => {
|
||||
const {
|
||||
instance,
|
||||
values,
|
||||
refetch,
|
||||
metadata,
|
||||
updateMetadata,
|
||||
deleteMetadata
|
||||
deleteMetadata,
|
||||
refetch
|
||||
} = ownProps;
|
||||
|
||||
return {
|
||||
// reset sets values to initialValues
|
||||
handleClear: form => dispatch(reset(form)),
|
||||
handleRemove: form =>
|
||||
Promise.resolve(
|
||||
// set removing=true (so that we can have a specific removing spinner)
|
||||
// because remove button is not a submit button, we have to manually flip that flag
|
||||
handleCancel: form =>
|
||||
dispatch([
|
||||
set({ name: `${form}-removing`, value: true }),
|
||||
startSubmit(form)
|
||||
])
|
||||
)
|
||||
.then(() =>
|
||||
// call mutation. get key from values' initialValues
|
||||
deleteMetadata({
|
||||
set({ name: `${form}-expanded`, value: false }),
|
||||
dispatch(reset(form))
|
||||
]),
|
||||
handleToggleAddOpen: value =>
|
||||
dispatch(set({ name: `add-metadata-open`, value })),
|
||||
handleUpdateExpanded: (form, expanded) =>
|
||||
dispatch(set({ name: `${form}-expanded`, value: expanded })),
|
||||
handleCreate: async ({ name, value }) => {
|
||||
// call mutation
|
||||
const [err] = await intercept(
|
||||
updateMetadata({
|
||||
variables: {
|
||||
id: instance.id,
|
||||
name: get(find(values, ['form', form]), 'initialValues.name')
|
||||
metadata: [{ name, value }]
|
||||
}
|
||||
})
|
||||
)
|
||||
// fetch metadata again
|
||||
.then(() => refetch())
|
||||
// we only flip removing and submitting when there is an error.
|
||||
// the reason for that is that metadata is updated asyncronously and
|
||||
// it takes longer to have an efect than the mutation
|
||||
.catch(error =>
|
||||
);
|
||||
|
||||
if (err) {
|
||||
// show mutation error
|
||||
throw new SubmissionError({
|
||||
_error: parseError(err)
|
||||
});
|
||||
}
|
||||
|
||||
dispatch([
|
||||
set({ name: `${form}-removing`, value: false }),
|
||||
stopSubmit(form, {
|
||||
_error: error.graphQLErrors
|
||||
.map(({ message }) => message)
|
||||
.join('\n')
|
||||
})
|
||||
])
|
||||
),
|
||||
handleUpdate: ({ name, value }, form) =>
|
||||
// call mutation. delete existing metadata, add new
|
||||
// reset create new metadata form
|
||||
reset(ADD_FORM_NAME),
|
||||
stopSubmit(ADD_FORM_NAME),
|
||||
// close add form
|
||||
set({ name: `add-metadata-open`, value: false })
|
||||
]);
|
||||
|
||||
// fetch metadata again (even though we are polling)
|
||||
return refetch();
|
||||
},
|
||||
handleUpdate: async ({ name, value }, _, { form }) => {
|
||||
// call mutations
|
||||
const [err] = await intercept(
|
||||
Promise.all([
|
||||
deleteMetadata({
|
||||
variables: {
|
||||
id: instance.id,
|
||||
name: get(find(values, ['form', form]), 'initialValues.name')
|
||||
name: get(
|
||||
find(metadata, ['form', form]),
|
||||
'initialValues.name'
|
||||
)
|
||||
}
|
||||
}),
|
||||
updateMetadata({
|
||||
@ -218,36 +237,57 @@ export default compose(
|
||||
}
|
||||
})
|
||||
])
|
||||
// fetch metadata again
|
||||
.then(() => refetch())
|
||||
// submit is flipped once the promise is resolved
|
||||
.catch(error => {
|
||||
);
|
||||
|
||||
if (err) {
|
||||
// show mutation error
|
||||
throw new SubmissionError({
|
||||
_error: error.graphQLErrors
|
||||
.map(({ message }) => message)
|
||||
.join('\n')
|
||||
_error: parseError(err)
|
||||
});
|
||||
}),
|
||||
handleCreate: ({ name, value }) =>
|
||||
}
|
||||
|
||||
dispatch([
|
||||
// reset form
|
||||
stopSubmit(form),
|
||||
// close card
|
||||
set({ name: `${form}-expanded`, value: false })
|
||||
]);
|
||||
|
||||
// fetch metadata again (even though we are polling)
|
||||
return refetch();
|
||||
},
|
||||
handleRemove: async form => {
|
||||
dispatch([
|
||||
set({ name: `${form}-removing`, value: true }),
|
||||
startSubmit(form)
|
||||
]);
|
||||
|
||||
// call mutation
|
||||
updateMetadata({
|
||||
const [err] = await intercept(
|
||||
deleteMetadata({
|
||||
variables: {
|
||||
id: instance.id,
|
||||
metadata: [{ name, value }]
|
||||
name: get(find(metadata, ['form', form]), 'initialValues.name')
|
||||
}
|
||||
})
|
||||
// fetch metadata again
|
||||
.then(() => refetch())
|
||||
// reset create new metadata form
|
||||
.then(() => dispatch(reset(CREATE_METADATA_FORM_KEY(instance.name))))
|
||||
// submit is flipped once the promise is resolved
|
||||
.catch(error => {
|
||||
);
|
||||
|
||||
if (err) {
|
||||
// show mutation error
|
||||
throw new SubmissionError({
|
||||
_error: error.graphQLErrors
|
||||
.map(({ message }) => message)
|
||||
.join('\n')
|
||||
_error: parseError(err)
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
dispatch([
|
||||
stopSubmit(form),
|
||||
set({ name: `${form}-removing`, value: false })
|
||||
]);
|
||||
|
||||
// fetch metadata again (even though we are polling)
|
||||
return refetch();
|
||||
}
|
||||
};
|
||||
})
|
||||
}
|
||||
)
|
||||
)(Metadata);
|
||||
|
@ -28,7 +28,7 @@ class FormGroup extends Component {
|
||||
}
|
||||
|
||||
renderGroup(inputProps) {
|
||||
const { className, style, children, ...rest } = this.props;
|
||||
const { className, style, children, fluid = false, ...rest } = this.props;
|
||||
|
||||
const value = {
|
||||
id: rndId(),
|
||||
@ -37,7 +37,7 @@ class FormGroup extends Component {
|
||||
};
|
||||
|
||||
return (
|
||||
<Wrapper className={className} style={style} {...rest}>
|
||||
<Wrapper className={className} style={style} fluid={fluid} {...rest}>
|
||||
<Broadcast channel="input-group" value={value}>
|
||||
<Noop>{children}</Noop>
|
||||
</Broadcast>
|
||||
|
Loading…
Reference in New Issue
Block a user