2017-09-20 12:30:53 +03:00
|
|
|
import React from 'react';
|
|
|
|
import paramCase from 'param-case';
|
2017-12-21 21:20:22 +02:00
|
|
|
import { Margin } from 'styled-components-spacing';
|
|
|
|
import { set } from 'react-redux-values';
|
2017-09-20 12:30:53 +03:00
|
|
|
import { compose, graphql } from 'react-apollo';
|
2017-11-09 13:27:32 +02:00
|
|
|
import { connect } from 'react-redux';
|
|
|
|
import { SubmissionError, reset, startSubmit, stopSubmit } from 'redux-form';
|
|
|
|
import ReduxForm from 'declarative-redux-form';
|
2017-09-20 12:30:53 +03:00
|
|
|
import find from 'lodash.find';
|
|
|
|
import get from 'lodash.get';
|
2017-12-06 20:16:11 +02:00
|
|
|
import intercept from 'apr-intercept';
|
|
|
|
import remcalc from 'remcalc';
|
2017-09-20 12:30:53 +03:00
|
|
|
|
2017-10-09 16:43:51 +03:00
|
|
|
import {
|
|
|
|
ViewContainer,
|
|
|
|
StatusLoader,
|
|
|
|
Message,
|
|
|
|
MessageDescription,
|
2017-11-09 13:27:32 +02:00
|
|
|
MessageTitle,
|
2017-12-06 20:16:11 +02:00
|
|
|
Divider,
|
|
|
|
H3
|
2017-10-09 16:43:51 +03:00
|
|
|
} from 'joyent-ui-toolkit';
|
2017-09-20 12:30:53 +03:00
|
|
|
|
|
|
|
import GetMetadata from '@graphql/list-metadata.gql';
|
2017-11-09 13:27:32 +02:00
|
|
|
import UpdateMetadata from '@graphql/update-metadata.gql';
|
|
|
|
import DeleteMetadata from '@graphql/delete-metadata.gql';
|
2017-12-06 20:16:11 +02:00
|
|
|
import parseError from '@state/parse-error';
|
2017-09-20 12:30:53 +03:00
|
|
|
|
2017-12-06 20:16:11 +02:00
|
|
|
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)}`;
|
2017-09-27 17:24:40 +03:00
|
|
|
|
2017-11-09 13:27:32 +02:00
|
|
|
const Metadata = ({
|
|
|
|
instance,
|
2017-12-06 20:16:11 +02:00
|
|
|
metadata = [],
|
|
|
|
addOpen,
|
2017-11-09 13:27:32 +02:00
|
|
|
loading,
|
|
|
|
error,
|
2017-12-06 20:16:11 +02:00
|
|
|
handleToggleAddOpen,
|
|
|
|
handleUpdateExpanded,
|
|
|
|
handleCancel,
|
|
|
|
handleCreate,
|
2017-11-09 13:27:32 +02:00
|
|
|
handleUpdate,
|
2017-12-06 20:16:11 +02:00
|
|
|
handleRemove
|
2017-11-09 13:27:32 +02:00
|
|
|
}) => {
|
2017-12-06 20:16:11 +02:00
|
|
|
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 ? (
|
2017-12-21 21:20:22 +02:00
|
|
|
<Margin bottom={4} top={addOpen && 4}>
|
|
|
|
<H3>{metadata.length} key:value pair</H3>
|
|
|
|
</Margin>
|
2017-12-06 20:16:11 +02:00
|
|
|
) : null;
|
2017-09-20 12:30:53 +03:00
|
|
|
|
2017-11-09 13:27:32 +02:00
|
|
|
const _metadata =
|
|
|
|
!_loading &&
|
2017-12-06 20:16:11 +02:00
|
|
|
metadata.map(({ form, initialValues, expanded, removing }) => (
|
|
|
|
<ReduxForm
|
|
|
|
form={form}
|
|
|
|
key={form}
|
|
|
|
initialValues={initialValues}
|
|
|
|
destroyOnUnmount={false}
|
|
|
|
onSubmit={handleUpdate}
|
|
|
|
onToggleExpanded={() => handleUpdateExpanded(form, !expanded)}
|
|
|
|
onCancel={() => handleCancel(form)}
|
|
|
|
onRemove={() => handleRemove(form)}
|
|
|
|
expanded={expanded}
|
|
|
|
removing={removing}
|
|
|
|
>
|
|
|
|
{MetadataEditForm}
|
|
|
|
</ReduxForm>
|
2017-11-09 13:27:32 +02:00
|
|
|
));
|
|
|
|
|
2017-10-04 20:27:55 +03:00
|
|
|
const _error =
|
2017-12-06 20:16:11 +02:00
|
|
|
error && !_metadata.length && !_loading ? (
|
2017-10-09 16:43:51 +03:00
|
|
|
<Message error>
|
|
|
|
<MessageTitle>Ooops!</MessageTitle>
|
|
|
|
<MessageDescription>
|
2017-12-06 20:16:11 +02:00
|
|
|
An error occurred while loading your metadata
|
2017-10-09 16:43:51 +03:00
|
|
|
</MessageDescription>
|
|
|
|
</Message>
|
2017-10-04 20:27:55 +03:00
|
|
|
) : null;
|
2017-09-20 12:30:53 +03:00
|
|
|
|
|
|
|
return (
|
2017-12-06 20:16:11 +02:00
|
|
|
<ViewContainer main>
|
|
|
|
<ReduxForm
|
|
|
|
form={MENU_FORM_NAME}
|
|
|
|
searchable={!_loading}
|
|
|
|
onAdd={() => handleToggleAddOpen(!addOpen)}
|
|
|
|
>
|
|
|
|
{MetadataMenuForm}
|
|
|
|
</ReduxForm>
|
|
|
|
<Divider height={remcalc(11)} transparent />
|
|
|
|
{_line}
|
2017-09-20 12:30:53 +03:00
|
|
|
{_error}
|
2017-12-06 20:16:11 +02:00
|
|
|
{_loading}
|
2017-11-09 13:27:32 +02:00
|
|
|
{_add}
|
2017-12-06 20:16:11 +02:00
|
|
|
{_count}
|
|
|
|
{_metadata}
|
2017-09-20 12:30:53 +03:00
|
|
|
</ViewContainer>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default compose(
|
2017-11-09 13:27:32 +02:00
|
|
|
graphql(UpdateMetadata, { name: 'updateMetadata' }),
|
|
|
|
graphql(DeleteMetadata, { name: 'deleteMetadata' }),
|
2017-09-20 12:30:53 +03:00
|
|
|
graphql(GetMetadata, {
|
|
|
|
options: ({ match }) => ({
|
2017-12-06 20:16:11 +02:00
|
|
|
// pollInterval: 1000,
|
2017-09-20 12:30:53 +03:00
|
|
|
variables: {
|
|
|
|
name: get(match, 'params.instance')
|
|
|
|
}
|
|
|
|
}),
|
2017-11-09 13:27:32 +02:00
|
|
|
props: ({ data: { loading, error, variables, refetch, ...rest } }) => {
|
|
|
|
const { name } = variables;
|
|
|
|
|
|
|
|
const instance = find(get(rest, 'machines', []), ['name', name]);
|
2017-12-06 20:16:11 +02:00
|
|
|
const values = get(instance, 'metadata', []);
|
2017-09-27 17:24:40 +03:00
|
|
|
|
2017-12-06 20:16:11 +02:00
|
|
|
const metadata = values.map(({ name, value }) => ({
|
|
|
|
form: METADATA_FORM_KEY(name),
|
|
|
|
initialValues: {
|
|
|
|
name,
|
|
|
|
value
|
|
|
|
}
|
|
|
|
}));
|
2017-09-27 17:24:40 +03:00
|
|
|
|
2017-11-09 13:27:32 +02:00
|
|
|
return {
|
2017-12-06 20:16:11 +02:00
|
|
|
metadata,
|
2017-11-09 13:27:32 +02:00
|
|
|
instance,
|
|
|
|
loading,
|
|
|
|
error,
|
|
|
|
refetch
|
|
|
|
};
|
2017-09-27 17:24:40 +03:00
|
|
|
}
|
2017-11-09 13:27:32 +02:00
|
|
|
}),
|
2017-12-06 20:16:11 +02:00
|
|
|
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,
|
|
|
|
metadata,
|
|
|
|
updateMetadata,
|
|
|
|
deleteMetadata,
|
|
|
|
refetch
|
|
|
|
} = ownProps;
|
|
|
|
|
|
|
|
return {
|
|
|
|
handleCancel: form =>
|
2017-11-09 13:27:32 +02:00
|
|
|
dispatch([
|
2017-12-06 20:16:11 +02:00
|
|
|
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({
|
2017-11-09 13:27:32 +02:00
|
|
|
variables: {
|
|
|
|
id: instance.id,
|
2017-12-06 20:16:11 +02:00
|
|
|
metadata: [{ name, value }]
|
2017-11-09 13:27:32 +02:00
|
|
|
}
|
|
|
|
})
|
2017-12-06 20:16:11 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
// show mutation error
|
|
|
|
throw new SubmissionError({
|
|
|
|
_error: parseError(err)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
dispatch([
|
|
|
|
// 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(metadata, ['form', form]),
|
|
|
|
'initialValues.name'
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
updateMetadata({
|
|
|
|
variables: {
|
|
|
|
id: instance.id,
|
|
|
|
metadata: [{ name, value }]
|
|
|
|
}
|
2017-11-09 13:27:32 +02:00
|
|
|
})
|
|
|
|
])
|
2017-12-06 20:16:11 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
// show mutation error
|
2017-11-09 13:27:32 +02:00
|
|
|
throw new SubmissionError({
|
2017-12-06 20:16:11 +02:00
|
|
|
_error: parseError(err)
|
2017-11-09 13:27:32 +02:00
|
|
|
});
|
|
|
|
}
|
2017-12-06 20:16:11 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
const [err] = await intercept(
|
|
|
|
deleteMetadata({
|
|
|
|
variables: {
|
|
|
|
id: instance.id,
|
|
|
|
name: get(find(metadata, ['form', form]), 'initialValues.name')
|
|
|
|
}
|
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
// show mutation error
|
2017-11-09 13:27:32 +02:00
|
|
|
throw new SubmissionError({
|
2017-12-06 20:16:11 +02:00
|
|
|
_error: parseError(err)
|
2017-11-09 13:27:32 +02:00
|
|
|
});
|
2017-12-06 20:16:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
dispatch([
|
|
|
|
stopSubmit(form),
|
|
|
|
set({ name: `${form}-removing`, value: false })
|
|
|
|
]);
|
|
|
|
|
|
|
|
// fetch metadata again (even though we are polling)
|
|
|
|
return refetch();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
)
|
2017-09-20 12:30:53 +03:00
|
|
|
)(Metadata);
|